Add tests for the _ChainMap helper class.
This commit is contained in:
parent
08f5cf51dc
commit
499e19340e
|
@ -695,6 +695,15 @@ class _ChainMap(MutableMapping):
|
||||||
|
|
||||||
__copy__ = copy
|
__copy__ = copy
|
||||||
|
|
||||||
|
def new_child(self): # like Django's Context.push()
|
||||||
|
'New ChainMap with a new dict followed by all previous maps.'
|
||||||
|
return self.__class__({}, *self.maps)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def parents(self): # like Django's Context.pop()
|
||||||
|
'New ChainMap from maps[1:].'
|
||||||
|
return self.__class__(*self.maps[1:])
|
||||||
|
|
||||||
def __setitem__(self, key, value):
|
def __setitem__(self, key, value):
|
||||||
self.maps[0][key] = value
|
self.maps[0][key] = value
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ import keyword
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
from collections import UserDict
|
from collections import UserDict
|
||||||
|
from collections import _ChainMap as ChainMap
|
||||||
from collections.abc import Hashable, Iterable, Iterator
|
from collections.abc import Hashable, Iterable, Iterator
|
||||||
from collections.abc import Sized, Container, Callable
|
from collections.abc import Sized, Container, Callable
|
||||||
from collections.abc import Set, MutableSet
|
from collections.abc import Set, MutableSet
|
||||||
|
@ -18,6 +19,97 @@ from collections.abc import Mapping, MutableMapping, KeysView, ItemsView
|
||||||
from collections.abc import Sequence, MutableSequence
|
from collections.abc import Sequence, MutableSequence
|
||||||
from collections.abc import ByteString
|
from collections.abc import ByteString
|
||||||
|
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
### _ChainMap (helper class for configparser and the string module)
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
class TestChainMap(unittest.TestCase):
|
||||||
|
|
||||||
|
def test_basics(self):
|
||||||
|
c = ChainMap()
|
||||||
|
c['a'] = 1
|
||||||
|
c['b'] = 2
|
||||||
|
d = c.new_child()
|
||||||
|
d['b'] = 20
|
||||||
|
d['c'] = 30
|
||||||
|
self.assertEqual(d.maps, [{'b':20, 'c':30}, {'a':1, 'b':2}]) # check internal state
|
||||||
|
self.assertEqual(d.items(), dict(a=1, b=20, c=30).items()) # check items/iter/getitem
|
||||||
|
self.assertEqual(len(d), 3) # check len
|
||||||
|
for key in 'abc': # check contains
|
||||||
|
self.assertIn(key, d)
|
||||||
|
for k, v in dict(a=1, b=20, c=30, z=100).items(): # check get
|
||||||
|
self.assertEqual(d.get(k, 100), v)
|
||||||
|
|
||||||
|
del d['b'] # unmask a value
|
||||||
|
self.assertEqual(d.maps, [{'c':30}, {'a':1, 'b':2}]) # check internal state
|
||||||
|
self.assertEqual(d.items(), dict(a=1, b=2, c=30).items()) # check items/iter/getitem
|
||||||
|
self.assertEqual(len(d), 3) # check len
|
||||||
|
for key in 'abc': # check contains
|
||||||
|
self.assertIn(key, d)
|
||||||
|
for k, v in dict(a=1, b=2, c=30, z=100).items(): # check get
|
||||||
|
self.assertEqual(d.get(k, 100), v)
|
||||||
|
self.assertIn(repr(d), [ # check repr
|
||||||
|
type(d).__name__ + "({'c': 30}, {'a': 1, 'b': 2})",
|
||||||
|
type(d).__name__ + "({'c': 30}, {'b': 2, 'a': 1})"
|
||||||
|
])
|
||||||
|
|
||||||
|
for e in d.copy(), copy.copy(d): # check shallow copies
|
||||||
|
self.assertEqual(d, e)
|
||||||
|
self.assertEqual(d.maps, e.maps)
|
||||||
|
self.assertIsNot(d, e)
|
||||||
|
self.assertIsNot(d.maps[0], e.maps[0])
|
||||||
|
for m1, m2 in zip(d.maps[1:], e.maps[1:]):
|
||||||
|
self.assertIs(m1, m2)
|
||||||
|
|
||||||
|
for e in [pickle.loads(pickle.dumps(d)),
|
||||||
|
copy.deepcopy(d),
|
||||||
|
eval(repr(d))
|
||||||
|
]: # check deep copies
|
||||||
|
self.assertEqual(d, e)
|
||||||
|
self.assertEqual(d.maps, e.maps)
|
||||||
|
self.assertIsNot(d, e)
|
||||||
|
for m1, m2 in zip(d.maps, e.maps):
|
||||||
|
self.assertIsNot(m1, m2, e)
|
||||||
|
|
||||||
|
d.new_child()
|
||||||
|
d['b'] = 5
|
||||||
|
self.assertEqual(d.maps, [{'b': 5}, {'c':30}, {'a':1, 'b':2}])
|
||||||
|
self.assertEqual(d.parents.maps, [{'c':30}, {'a':1, 'b':2}]) # check parents
|
||||||
|
self.assertEqual(d['b'], 5) # find first in chain
|
||||||
|
self.assertEqual(d.parents['b'], 2) # look beyond maps[0]
|
||||||
|
|
||||||
|
def test_contructor(self):
|
||||||
|
self.assertEqual(ChainedContext().maps, [{}]) # no-args --> one new dict
|
||||||
|
self.assertEqual(ChainMap({1:2}).maps, [{1:2}]) # 1 arg --> list
|
||||||
|
|
||||||
|
def test_missing(self):
|
||||||
|
class DefaultChainMap(ChainMap):
|
||||||
|
def __missing__(self, key):
|
||||||
|
return 999
|
||||||
|
d = DefaultChainMap(dict(a=1, b=2), dict(b=20, c=30))
|
||||||
|
for k, v in dict(a=1, b=2, c=30, d=999).items():
|
||||||
|
self.assertEqual(d[k], v) # check __getitem__ w/missing
|
||||||
|
for k, v in dict(a=1, b=2, c=30, d=77).items():
|
||||||
|
self.assertEqual(d.get(k, 77), v) # check get() w/ missing
|
||||||
|
for k, v in dict(a=True, b=True, c=True, d=False).items():
|
||||||
|
self.assertEqual(k in d, v) # check __contains__ w/missing
|
||||||
|
self.assertEqual(d.pop('a', 1001), 1, d)
|
||||||
|
self.assertEqual(d.pop('a', 1002), 1002) # check pop() w/missing
|
||||||
|
self.assertEqual(d.popitem(), ('b', 2)) # check popitem() w/missing
|
||||||
|
with self.assertRaises(KeyError):
|
||||||
|
d.popitem()
|
||||||
|
|
||||||
|
def test_dict_coercion(self):
|
||||||
|
d = ChainMap(dict(a=1, b=2), dict(b=20, c=30))
|
||||||
|
self.assertEqual(dict(d), dict(a=1, b=2, c=30))
|
||||||
|
self.assertEqual(dict(d.items()), dict(a=1, b=2, c=30))
|
||||||
|
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
### Named Tuples
|
||||||
|
################################################################################
|
||||||
|
|
||||||
TestNT = namedtuple('TestNT', 'x y z') # type used for pickle tests
|
TestNT = namedtuple('TestNT', 'x y z') # type used for pickle tests
|
||||||
|
|
||||||
class TestNamedTuple(unittest.TestCase):
|
class TestNamedTuple(unittest.TestCase):
|
||||||
|
@ -229,6 +321,10 @@ class TestNamedTuple(unittest.TestCase):
|
||||||
self.assertEqual(repr(B(1)), 'B(x=1)')
|
self.assertEqual(repr(B(1)), 'B(x=1)')
|
||||||
|
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
### Abstract Base Classes
|
||||||
|
################################################################################
|
||||||
|
|
||||||
class ABCTestCase(unittest.TestCase):
|
class ABCTestCase(unittest.TestCase):
|
||||||
|
|
||||||
def validate_abstract_methods(self, abc, *names):
|
def validate_abstract_methods(self, abc, *names):
|
||||||
|
@ -626,6 +722,11 @@ class TestCollectionABCs(ABCTestCase):
|
||||||
self.validate_abstract_methods(MutableSequence, '__contains__', '__iter__',
|
self.validate_abstract_methods(MutableSequence, '__contains__', '__iter__',
|
||||||
'__len__', '__getitem__', '__setitem__', '__delitem__', 'insert')
|
'__len__', '__getitem__', '__setitem__', '__delitem__', 'insert')
|
||||||
|
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
### Counter
|
||||||
|
################################################################################
|
||||||
|
|
||||||
class TestCounter(unittest.TestCase):
|
class TestCounter(unittest.TestCase):
|
||||||
|
|
||||||
def test_basics(self):
|
def test_basics(self):
|
||||||
|
@ -789,6 +890,11 @@ class TestCounter(unittest.TestCase):
|
||||||
self.assertEqual(m,
|
self.assertEqual(m,
|
||||||
OrderedDict([('a', 5), ('b', 2), ('r', 2), ('c', 1), ('d', 1)]))
|
OrderedDict([('a', 5), ('b', 2), ('r', 2), ('c', 1), ('d', 1)]))
|
||||||
|
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
### OrderedDict
|
||||||
|
################################################################################
|
||||||
|
|
||||||
class TestOrderedDict(unittest.TestCase):
|
class TestOrderedDict(unittest.TestCase):
|
||||||
|
|
||||||
def test_init(self):
|
def test_init(self):
|
||||||
|
@ -1067,6 +1173,10 @@ class SubclassMappingTests(mapping_tests.BasicTestMappingProtocol):
|
||||||
self.assertRaises(KeyError, d.popitem)
|
self.assertRaises(KeyError, d.popitem)
|
||||||
|
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
### Run tests
|
||||||
|
################################################################################
|
||||||
|
|
||||||
import doctest, collections
|
import doctest, collections
|
||||||
|
|
||||||
def test_main(verbose=None):
|
def test_main(verbose=None):
|
||||||
|
|
Loading…
Reference in New Issue