sync to Atlas repo

This commit is contained in:
Luciano Ramalho
2014-12-06 15:38:22 -02:00
parent 2f495627fb
commit b38e6fc5f2
7 changed files with 72 additions and 43 deletions

View File

@@ -1,8 +1,13 @@
"""StrKeyDict always converts non-string keys to `str` """StrKeyDict always converts non-string keys to `str`
Test for initializer: keys are converted to `str`.
>>> d = StrKeyDict([(2, 'two'), ('4', 'four')])
>>> sorted(d.keys())
['2', '4']
Tests for item retrieval using `d[key]` notation:: Tests for item retrieval using `d[key]` notation::
>>> d = StrKeyDict([('2', 'two'), ('4', 'four')])
>>> d['2'] >>> d['2']
'two' 'two'
>>> d[4] >>> d[4]
@@ -12,6 +17,15 @@ Tests for item retrieval using `d[key]` notation::
... ...
KeyError: '1' KeyError: '1'
Tests for item retrieval using `d.get(key)` notation::
>>> d.get('2')
'two'
>>> d.get(4)
'four'
>>> d.get(1, 'N/A')
'N/A'
Tests for the `in` operator:: Tests for the `in` operator::
>>> 2 in d >>> 2 in d

View File

@@ -14,6 +14,16 @@ Tests for item retrieval using `d[key]` notation::
... ...
KeyError: '1' KeyError: '1'
Tests for item retrieval using `d.get(key)` notation::
>>> d.get('2')
'two'
>>> d.get(4)
'four'
>>> d.get(1, 'N/A')
'N/A'
Tests for the `in` operator:: Tests for the `in` operator::
>>> 2 in d >>> 2 in d
@@ -24,8 +34,8 @@ Tests for the `in` operator::
# END STRKEYDICT0_TESTS # END STRKEYDICT0_TESTS
""" """
# BEGIN STRKEYDICT0
# BEGIN STRKEYDICT0
class StrKeyDict0(dict): # <1> class StrKeyDict0(dict): # <1>
def __missing__(self, key): def __missing__(self, key):
@@ -33,7 +43,13 @@ class StrKeyDict0(dict): # <1>
raise KeyError(key) raise KeyError(key)
return self[str(key)] # <3> return self[str(key)] # <3>
def __contains__(self, key): def get(self, key, default=None):
return key in self.keys() or str(key) in self.keys() # <4> try:
return self[key] # <4>
except KeyError:
return default # <5>
# END STRKEYDICT0 def __contains__(self, key):
return key in self.keys() or str(key) in self.keys() # <6>
# END STRKEYDICT0

View File

@@ -1,17 +1,12 @@
from abc import ABC, abstractmethod import abc
class Tombola(abc.ABC): # <1>
class Tombola(ABC): # <1> @abc.abstractmethod
def load(self, iterable): # <2>
@abstractmethod
def __init__(self, iterable): # <2>
"""New instance is loaded from an iterable."""
@abstractmethod
def load(self, iterable):
"""Add items from an iterable.""" """Add items from an iterable."""
@abstractmethod @abc.abstractmethod
def pick(self): # <3> def pick(self): # <3>
"""Remove item at random, returning it. """Remove item at random, returning it.

View File

@@ -1,33 +1,36 @@
import sys # BEGIN TOMBOLA_RUNNER
import importlib
import doctest import doctest
from tombola import Tombola from tombola import Tombola
# modules to test
import bingo, lotto, tombolist, drum # <1>
TEST_FILE = 'tombola_tests.rst' TEST_FILE = 'tombola_tests.rst'
MODULE_NAMES = 'bingo lotto tombolist drum'.split()
TEST_MSG = '{0:16} {1.attempted:2} tests, {1.failed:2} failed - {2}' TEST_MSG = '{0:16} {1.attempted:2} tests, {1.failed:2} failed - {2}'
def main(argv):
verbose = '-v' in argv
real_subclasses = Tombola.__subclasses__() # <2>
virtual_subclasses = list(Tombola._abc_registry) # <3>
for cls in real_subclasses + virtual_subclasses: # <4>
test(cls, verbose)
def test(cls, verbose=False): def test(cls, verbose=False):
res = doctest.testfile(TEST_FILE, res = doctest.testfile(
globs={'TombolaUnderTest': cls}, TEST_FILE,
verbose=verbose, globs={'ConcreteTombola': cls}, # <5>
optionflags=doctest.REPORT_ONLY_FIRST_FAILURE) verbose=verbose,
optionflags=doctest.REPORT_ONLY_FIRST_FAILURE)
tag = 'FAIL' if res.failed else 'OK' tag = 'FAIL' if res.failed else 'OK'
print(TEST_MSG.format(cls.__name__, res, tag)) print(TEST_MSG.format(cls.__name__, res, tag)) # <6>
if __name__ == '__main__': if __name__ == '__main__':
import sys
for name in MODULE_NAMES: # import modules to test, by name main(sys.argv)
importlib.import_module(name) # END TOMBOLA_RUNNER
verbose = '-v' in sys.argv
real_subclasses = Tombola.__subclasses__()
virtual_subclasses = list(Tombola._abc_registry)
for cls in real_subclasses + virtual_subclasses:
test(cls, verbose)

View File

@@ -8,7 +8,7 @@ Every concrete subclass of Tombola should pass these tests.
Create and load instance from iterable:: Create and load instance from iterable::
>>> balls = list(range(3)) >>> balls = list(range(3))
>>> globe = TombolaUnderTest(balls) >>> globe = ConcreteTombola(balls)
>>> globe.loaded() >>> globe.loaded()
True True
@@ -42,7 +42,7 @@ Reload::
Check that `LookupError` (or a subclass) is the exception Check that `LookupError` (or a subclass) is the exception
thrown when the device is empty:: thrown when the device is empty::
>>> globe = TombolaUnderTest([]) >>> globe = ConcreteTombola([])
>>> try: >>> try:
... globe.pick() ... globe.pick()
... except LookupError as exc: ... except LookupError as exc:
@@ -53,7 +53,7 @@ thrown when the device is empty::
Load and pick 100 balls to verify that they are all come out:: Load and pick 100 balls to verify that they are all come out::
>>> balls = list(range(100)) >>> balls = list(range(100))
>>> globe = TombolaUnderTest(balls) >>> globe = ConcreteTombola(balls)
>>> picks = [] >>> picks = []
>>> while globe.loaded(): >>> while globe.loaded():
... picks.append(globe.pick()) ... picks.append(globe.pick())
@@ -75,3 +75,6 @@ even if the implementation is OK. The probability of the 100
balls coming out, by chance, in the order they were loaded is balls coming out, by chance, in the order they were loaded is
1/100!, or approximately 1.07e-158. It's much easier to win the 1/100!, or approximately 1.07e-158. It's much easier to win the
Lotto or to become a billionaire working as a programmer. Lotto or to become a billionaire working as a programmer.
THE END

View File

@@ -16,6 +16,4 @@ class TomboList(list): # <2>
def loaded(self): return bool(self) # <6> def loaded(self): return bool(self) # <6>
""" # Tombola.register(TomboList) # <- Python 3.2 or earlier
Tombola.register(TomboList) # <- Python 3.2 or earlier
"""

View File

@@ -12,10 +12,10 @@ class Sentence:
def __init__(self, text): def __init__(self, text):
self.text = text self.text = text
self.words = RE_WORD.findall(text) #<1> self.words = RE_WORD.findall(text) # <1>
def __getitem__(self, index): def __getitem__(self, index):
return self.words[index] #<2> return self.words[index] # <2>
def __repr__(self): def __repr__(self):
return 'Sentence(%s)' % reprlib.repr(self.text) #<3> return 'Sentence(%s)' % reprlib.repr(self.text) # <3>