sync to Atlas repo
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
|
||||||
"""
|
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user