updated contents from Atlas repo

This commit is contained in:
Luciano Ramalho
2014-10-14 14:26:55 -03:00
parent 40688c038d
commit 981d5bc473
157 changed files with 71134 additions and 1 deletions

19
interfaces/bingo.py Normal file
View File

@@ -0,0 +1,19 @@
import random
from tombola import Tombola
class BingoCage(Tombola): # <1>
def __init__(self, items):
self._balls = list(items) # <2>
def load(self, items):
self._balls.extend(items)
def pop(self):
try:
position = random.randrange(len(self._balls)) # <4>
except ValueError:
raise LookupError('pop from empty BingoCage')
return self._balls.pop(position)

17
interfaces/drum.py Normal file
View File

@@ -0,0 +1,17 @@
from random import shuffle
from tombola import Tombola
class TumblingDrum(Tombola):
def __init__(self, iterable):
self._balls = []
self.load(iterable)
def load(self, iterable):
self._balls.extend(iterable)
shuffle(self._balls)
def pop(self):
return self._balls.pop()

View File

@@ -0,0 +1,61 @@
BaseException
├── SystemExit
├── KeyboardInterrupt
├── GeneratorExit
└── Exception
├── StopIteration
├── ArithmeticError
│ ├── FloatingPointError
│ ├── OverflowError
│ └── ZeroDivisionError
├── AssertionError
├── AttributeError
├── BufferError
├── EOFError
├── ImportError
├── LookupError
│ ├── IndexError
│ └── KeyError
├── MemoryError
├── NameError
│ └── UnboundLocalError
├── OSError
│ ├── BlockingIOError
│ ├── ChildProcessError
│ ├── ConnectionError
│ │ ├── BrokenPipeError
│ │ ├── ConnectionAbortedError
│ │ ├── ConnectionRefusedError
│ │ └── ConnectionResetError
│ ├── FileExistsError
│ ├── FileNotFoundError
│ ├── InterruptedError
│ ├── IsADirectoryError
│ ├── NotADirectoryError
│ ├── PermissionError
│ ├── ProcessLookupError
│ └── TimeoutError
├── ReferenceError
├── RuntimeError
│ └── NotImplementedError
├── SyntaxError
│ └── IndentationError
│ └── TabError
├── SystemError
├── TypeError
├── ValueError
│ └── UnicodeError
│ ├── UnicodeDecodeError
│ ├── UnicodeEncodeError
│ └── UnicodeTranslateError
└── Warning
├── DeprecationWarning
├── PendingDeprecationWarning
├── RuntimeWarning
├── SyntaxWarning
├── UserWarning
├── FutureWarning
├── ImportWarning
├── UnicodeWarning
├── BytesWarning
└── ResourceWarning

24
interfaces/lotto.py Normal file
View File

@@ -0,0 +1,24 @@
import random
from tombola import Tombola
class LotteryBlower(Tombola):
def __init__(self, iterable):
self.randomizer = random.SystemRandom() # <1>
self.clear()
self.load(iterable)
def clear(self):
self._balls = []
def load(self, iterable):
self._balls.extend(iterable)
self.randomizer.shuffle(self._balls) # <2>
def pop(self):
return self._balls.pop() # <3>
def loaded(self): # <4>
return len(self._balls) > 0

25
interfaces/tombola.py Normal file
View File

@@ -0,0 +1,25 @@
from abc import ABCMeta, abstractmethod
class Tombola(metaclass=ABCMeta): # <1>
@abstractmethod
def __init__(self, iterable): # <2>
raise NotImplementedError
@abstractmethod
def load(self):
raise NotImplementedError
@abstractmethod
def pop(self):
raise NotImplementedError
def loaded(self): # <3>
try:
item = self.pop()
except LookupError:
return False
else:
self.load([item]) # put it back
return True

View File

@@ -0,0 +1,52 @@
import sys
import importlib
import doctest
from tombola import Tombola
TESTS = 'tombola_tests.rst'
MODULES = 'bingo lotto tombolist drum'.split()
def test_module(module_name, verbose=False):
module = importlib.import_module(module_name)
tombola_class = None
for name in dir(module):
obj = getattr(module, name)
if (isinstance(obj, type) and
issubclass(obj, Tombola) and
obj.__module__ == module_name):
tombola_class = obj
break # stop at first matching class
if tombola_class is None:
print('ERROR: no Tombola subclass found in', module_name)
sys.exit(1)
res = doctest.testfile(TESTS,
globs={'TombolaUnderTest': tombola_class},
verbose=verbose,
optionflags=doctest.REPORT_ONLY_FIRST_FAILURE)
print('{:10} {}'.format(module_name, res))
if __name__ == '__main__':
args = sys.argv[:]
if '-v' in args:
args.remove('-v')
verbose = True
else:
verbose = False
if len(args) == 2:
module_names = [args[1]]
else:
module_names = MODULES
for name in module_names:
print('*' * 60, name)
test_module(name, verbose)

View File

@@ -0,0 +1,70 @@
==============
Tombola tests
==============
Every concrete subclass of Tombola should pass these tests.
Create and load instance from iterable::
>>> balls = list(range(3))
>>> globe = TombolaUnderTest(balls)
>>> globe.loaded()
True
Pop and collect balls::
>>> picks = []
>>> picks.append(globe.pop())
>>> picks.append(globe.pop())
>>> picks.append(globe.pop())
Check state and results::
>>> globe.loaded()
False
>>> sorted(picks) == balls
True
Reload::
>>> globe.load(balls)
>>> globe.loaded()
True
>>> picks = [globe.pop() for i in balls]
>>> globe.loaded()
False
Load and pop 20 balls to verify that the order has changed::
>>> balls = list(range(20))
>>> globe = TombolaUnderTest(balls)
>>> picks = []
>>> while globe.loaded():
... picks.append(globe.pop())
>>> len(picks) == len(balls)
True
>>> picks != balls
True
Also check that the order is not simply reversed either::
>>> picks[::-1] != balls
True
Note: last 2 tests each have 1 chance in 20! (factorial) of failing even if the implementation is OK. 1/20!, or approximately 4.11e-19, is the probability of the 20 balls coming out, by chance, in the exact order the were loaded.
Check that `LookupError` (or a subclass) is the exception thrown when the device is empty::
>>> globe = TombolaUnderTest([])
>>> try:
... globe.pop()
... except LookupError as exc:
... print('OK')
OK

19
interfaces/tombolist.py Normal file
View File

@@ -0,0 +1,19 @@
from random import randrange
from tombola import Tombola
class TomboList(list): # <1>
def pop(self):
if self: # <2>
return super().pop(randrange(len(self))) # <3>
else:
raise LookupError('pop from empty TomboList')
def load(self, iterable): self.extend(iterable) # <4>
def loaded(self): return bool(self) # <5>
Tombola.register(TomboList) # <6>