Skip to content

Commit a786180

Browse files
committed
update from Atlas with major reorg
1 parent 57902d3 commit a786180

File tree

134 files changed

+369
-520
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

134 files changed

+369
-520
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ concurrency/charfinder/charfinder_index.pickle
44
metaprog/oscon-schedule/data/schedule?_db
55
concurrency/wikipedia/fixture/docroot/
66
17-futures/countries/flags/
7+
attic/futures/countries/flags/
78

89
# Byte-compiled / optimized / DLL files
910
__pycache__/
File renamed without changes.

05-1class-func/bingo.py renamed to 05-1class-func/bingocall.py

+11-6
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@
22
# BEGIN BINGO_DEMO
33
44
>>> bingo = BingoCage(range(3))
5-
>>> bingo()
6-
2
5+
>>> bingo.pick()
6+
1
77
>>> bingo()
88
0
99
>>> callable(bingo)
1010
True
11+
1112
# END BINGO_DEMO
1213
1314
"""
@@ -22,9 +23,13 @@ def __init__(self, items):
2223
self._items = list(items) # <1>
2324
random.shuffle(self._items) # <2>
2425

25-
def __call__(self):
26-
if not self._items: # <3>
27-
raise IndexError('pop from empty BingoCage')
28-
return self._items.pop()
26+
def pick(self): # <3>
27+
try:
28+
return self._items.pop()
29+
except IndexError:
30+
raise LookupError('pick from empty BingoCage') # <4>
31+
32+
def __call__(self): # <5>
33+
return self.pick()
2934

3035
# END BINGO
File renamed without changes.

07-closure-deco/clockdeco_cls.py

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# clockdeco_param.py
2+
3+
"""
4+
>>> snooze(.1) # doctest: +ELLIPSIS
5+
[0.101...s] snooze(0.1) -> None
6+
>>> clock('{name}: {elapsed}')(time.sleep)(.2) # doctest: +ELLIPSIS
7+
sleep: 0.20...
8+
>>> clock('{name}({args}) dt={elapsed:0.3f}s')(time.sleep)(.2)
9+
sleep(0.2) dt=0.201s
10+
"""
11+
12+
# BEGIN CLOCKDECO_CLS
13+
import time
14+
15+
DEFAULT_FMT = '[{elapsed:0.8f}s] {name}({args}) -> {result}'
16+
17+
class clock:
18+
19+
def __init__(self, fmt=DEFAULT_FMT):
20+
self.fmt = fmt
21+
22+
def __call__(self, func):
23+
def clocked(*_args):
24+
t0 = time.time()
25+
_result = func(*_args)
26+
elapsed = time.time() - t0
27+
name = func.__name__
28+
args = ', '.join(repr(arg) for arg in _args)
29+
result = repr(_result)
30+
print(self.fmt.format(**locals()))
31+
return _result
32+
return clocked
33+
34+
if __name__ == '__main__':
35+
36+
@clock()
37+
def snooze(seconds):
38+
time.sleep(seconds)
39+
40+
for i in range(3):
41+
snooze(.123)
42+
43+
# END CLOCKDECO_CLS

11-iface-abc/bingo.py

+16-7
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
# BEGIN TOMBOLA_BINGO
2+
13
import random
24

35
from tombola import Tombola
@@ -6,14 +8,21 @@
68
class BingoCage(Tombola): # <1>
79

810
def __init__(self, items):
9-
self._balls = list(items) # <2>
11+
self._randomizer = random.SystemRandom() # <2>
12+
self._items = []
13+
self.load(items) # <3>
1014

1115
def load(self, items):
12-
self._balls.extend(items)
16+
self._items.extend(items)
17+
self._randomizer.shuffle(self._items) # <4>
1318

14-
def pick(self):
19+
def pick(self): # <5>
1520
try:
16-
position = random.randrange(len(self._balls)) # <3>
17-
except ValueError:
18-
raise LookupError('pop from empty BingoCage')
19-
return self._balls.pop(position) # <4>
21+
return self._items.pop()
22+
except IndexError:
23+
raise LookupError('pick from empty BingoCage')
24+
25+
def __call__(self): # <7>
26+
self.pick()
27+
28+
# END TOMBOLA_BINGO
File renamed without changes.

11-iface-abc/lotto.py

+15-9
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
# BEGIN LOTTERY_BLOWER
2+
13
import random
24

35
from tombola import Tombola
@@ -6,19 +8,23 @@
68
class LotteryBlower(Tombola):
79

810
def __init__(self, iterable):
9-
self.randomizer = random.SystemRandom() # <1>
10-
self.clear()
11-
self.load(iterable)
12-
13-
def clear(self):
14-
self._balls = []
11+
self._balls = list(iterable) # <1>
1512

1613
def load(self, iterable):
1714
self._balls.extend(iterable)
18-
self.randomizer.shuffle(self._balls) # <2>
1915

2016
def pick(self):
21-
return self._balls.pop() # <3>
17+
try:
18+
position = random.randrange(len(self._balls)) # <2>
19+
except ValueError:
20+
raise LookupError('pick from empty BingoCage')
21+
return self._balls.pop(position) # <3>
2222

2323
def loaded(self): # <4>
24-
return len(self._balls) > 0
24+
return bool(self._balls)
25+
26+
def inspect(self): # <5>
27+
return tuple(sorted(self._balls))
28+
29+
30+
# END LOTTERY_BLOWER

11-iface-abc/tombola.py

+19-7
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
# BEGIN TOMBOLA_ABC
2+
13
import abc
24

35
class Tombola(abc.ABC): # <1>
@@ -14,10 +16,20 @@ def pick(self): # <3>
1416
"""
1517

1618
def loaded(self): # <4>
17-
try:
18-
item = self.pick()
19-
except LookupError:
20-
return False
21-
else:
22-
self.load([item]) # put it back
23-
return True
19+
"""Return `True` if there's at least 1 item, `False` otherwise."""
20+
return bool(self.inspect()) # <5>
21+
22+
23+
def inspect(self):
24+
"""Return a sorted tuple with the items currently inside."""
25+
items = []
26+
while True: # <6>
27+
try:
28+
items.append(self.pick())
29+
except LookupError:
30+
break
31+
self.load(items) # <7>
32+
return tuple(sorted(items))
33+
34+
35+
# END TOMBOLA_ABC

11-iface-abc/tombola_tests.rst

+4-2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ Create and load instance from iterable::
1111
>>> globe = ConcreteTombola(balls)
1212
>>> globe.loaded()
1313
True
14+
>>> globe.inspect()
15+
(0, 1, 2)
1416

1517

1618
Pick and collect balls::
@@ -55,7 +57,7 @@ Load and pick 100 balls to verify that they all come out::
5557
>>> balls = list(range(100))
5658
>>> globe = ConcreteTombola(balls)
5759
>>> picks = []
58-
>>> while globe.loaded():
60+
>>> while globe.inspect():
5961
... picks.append(globe.pick())
6062
>>> len(picks) == len(balls)
6163
True
@@ -72,7 +74,7 @@ Check that the order has changed and is not simply reversed::
7274

7375
Note: the previous 2 tests have a *very* small chance of failing
7476
even if the implementation is OK. The probability of the 100
75-
balls coming out, by chance, in the order they were loaded is
77+
balls coming out, by chance, in the order they were inspect is
7678
1/100!, or approximately 1.07e-158. It's much easier to win the
7779
Lotto or to become a billionaire working as a programmer.
7880

11-iface-abc/tombolist.py

+7-3
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,12 @@ def pick(self):
1212
else:
1313
raise LookupError('pop from empty TomboList')
1414

15-
def load(self, iterable): self.extend(iterable) # <5>
15+
load = list.extend # <5>
1616

17-
def loaded(self): return bool(self) # <6>
17+
def loaded(self):
18+
return bool(self) # <6>
1819

19-
# Tombola.register(TomboList) # <- Python 3.2 or earlier
20+
def inspect(self):
21+
return tuple(sorted(self))
22+
23+
# Tombola.register(TomboList) # <7>

13-op-overloading/bingo.py

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# BEGIN TOMBOLA_BINGO
2+
3+
import random
4+
5+
from tombola import Tombola
6+
7+
8+
class BingoCage(Tombola): # <1>
9+
10+
def __init__(self, items):
11+
self._randomizer = random.SystemRandom() # <2>
12+
self._items = []
13+
self.load(items) # <3>
14+
15+
def load(self, items):
16+
self._items.extend(items)
17+
self._randomizer.shuffle(self._items) # <4>
18+
19+
def pick(self): # <5>
20+
try:
21+
return self._items.pop()
22+
except IndexError:
23+
raise LookupError('pick from empty BingoCage')
24+
25+
def __call__(self): # <7>
26+
self.pick()
27+
28+
# END TOMBOLA_BINGO

13-op-overloading/bingoaddable.py

+49-22
Original file line numberDiff line numberDiff line change
@@ -4,56 +4,83 @@
44
======================
55
66
7-
Tests for __add__ and __iadd__:
7+
Tests for __add__:
8+
9+
# BEGIN ADDABLE_BINGO_ADD_DEMO
810
911
>>> vowels = 'AEIOU'
10-
>>> globe = AddableBingoCage(vowels)
11-
>>> len(globe)
12-
5
13-
>>> globe.pop() in vowels
12+
>>> globe = AddableBingoCage(vowels) # <1>
13+
>>> globe.inspect()
14+
('A', 'E', 'I', 'O', 'U')
15+
>>> globe.pick() in vowels # <2>
1416
True
15-
>>> len(globe)
17+
>>> len(globe.inspect()) # <3>
1618
4
17-
>>> globe2 = AddableBingoCage('XYZ')
19+
>>> globe2 = AddableBingoCage('XYZ') # <4>
1820
>>> globe3 = globe + globe2
19-
>>> len(globe3)
21+
>>> len(globe3.inspect()) # <5>
2022
7
21-
>>> void = globe + [10, 20]
23+
>>> void = globe + [10, 20] # <6>
2224
Traceback (most recent call last):
2325
...
2426
TypeError: unsupported operand type(s) for +: 'AddableBingoCage' and 'list'
2527
2628
27-
Tests for __add__ and __iadd__:
29+
# END ADDABLE_BINGO_ADD_DEMO
30+
31+
Tests for __iadd__:
32+
33+
# BEGIN ADDABLE_BINGO_IADD_DEMO
2834
29-
>>> globe_orig = globe
30-
>>> len(globe)
35+
>>> globe_orig = globe # <1>
36+
>>> len(globe.inspect()) # <2>
3137
4
32-
>>> globe += globe2
33-
>>> len(globe)
38+
>>> globe += globe2 # <3>
39+
>>> len(globe.inspect())
3440
7
35-
>>> globe += [10, 20]
36-
>>> len(globe)
41+
>>> globe += ['M', 'N'] # <4>
42+
>>> len(globe.inspect())
3743
9
38-
>>> globe is globe_orig
44+
>>> globe is globe_orig # <5>
3945
True
46+
>>> globe += 1 # <6>
47+
Traceback (most recent call last):
48+
...
49+
TypeError: right operand in += must be 'AddableBingoCage' or an iterable
50+
51+
# END ADDABLE_BINGO_IADD_DEMO
4052
4153
"""
4254

4355
# BEGIN ADDABLE_BINGO
4456
import itertools # <1>
45-
from bingobase import BingoCage
57+
58+
from tombola import Tombola
59+
from bingo import BingoCage
4660

4761

4862
class AddableBingoCage(BingoCage): # <2>
4963

5064
def __add__(self, other):
51-
if isinstance(other, AddableBingoCage): # <3>
52-
return AddableBingoCage(itertools.chain(self, other)) # <4>
65+
if isinstance(other, Tombola): # <3>
66+
return AddableBingoCage(self.inspect() + other.inspect()) # <6>
5367
else:
5468
return NotImplemented
5569

5670
def __iadd__(self, other):
57-
self.load(other) # <5>
58-
return self # <6>
71+
if isinstance(other, Tombola):
72+
other_iterable = other.inspect() # <4>
73+
else:
74+
try:
75+
other_iterable = iter(other) # <5>
76+
except TypeError: # <6>
77+
self_cls = type(self).__name__
78+
msg = "right operand in += must be {!r} or an iterable"
79+
raise TypeError(msg.format(self_cls))
80+
self.load(other_iterable) # <7>
81+
return self # <8>
82+
83+
84+
85+
5986
# END ADDABLE_BINGO

0 commit comments

Comments
 (0)