| import copy |
| import pickle |
| from random import shuffle |
| import unittest |
| from collections import OrderedDict |
| from collections import MutableMapping |
| from test import mapping_tests, test_support |
| |
| |
| class TestOrderedDict(unittest.TestCase): |
| |
| def test_init(self): |
| with self.assertRaises(TypeError): |
| OrderedDict([('a', 1), ('b', 2)], None) # too many args |
| pairs = [('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', 5)] |
| self.assertEqual(sorted(OrderedDict(dict(pairs)).items()), pairs) # dict input |
| self.assertEqual(sorted(OrderedDict(**dict(pairs)).items()), pairs) # kwds input |
| self.assertEqual(list(OrderedDict(pairs).items()), pairs) # pairs input |
| self.assertEqual(list(OrderedDict([('a', 1), ('b', 2), ('c', 9), ('d', 4)], |
| c=3, e=5).items()), pairs) # mixed input |
| |
| # make sure no positional args conflict with possible kwdargs |
| self.assertEqual(list(OrderedDict(self=42).items()), [('self', 42)]) |
| self.assertEqual(list(OrderedDict(other=42).items()), [('other', 42)]) |
| self.assertRaises(TypeError, OrderedDict, 42) |
| self.assertRaises(TypeError, OrderedDict, (), ()) |
| self.assertRaises(TypeError, OrderedDict.__init__) |
| |
| # Make sure that direct calls to __init__ do not clear previous contents |
| d = OrderedDict([('a', 1), ('b', 2), ('c', 3), ('d', 44), ('e', 55)]) |
| d.__init__([('e', 5), ('f', 6)], g=7, d=4) |
| self.assertEqual(list(d.items()), |
| [('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', 5), ('f', 6), ('g', 7)]) |
| |
| def test_update(self): |
| with self.assertRaises(TypeError): |
| OrderedDict().update([('a', 1), ('b', 2)], None) # too many args |
| pairs = [('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', 5)] |
| od = OrderedDict() |
| od.update(dict(pairs)) |
| self.assertEqual(sorted(od.items()), pairs) # dict input |
| od = OrderedDict() |
| od.update(**dict(pairs)) |
| self.assertEqual(sorted(od.items()), pairs) # kwds input |
| od = OrderedDict() |
| od.update(pairs) |
| self.assertEqual(list(od.items()), pairs) # pairs input |
| od = OrderedDict() |
| od.update([('a', 1), ('b', 2), ('c', 9), ('d', 4)], c=3, e=5) |
| self.assertEqual(list(od.items()), pairs) # mixed input |
| |
| # Issue 9137: Named argument called 'other' or 'self' |
| # shouldn't be treated specially. |
| od = OrderedDict() |
| od.update(self=23) |
| self.assertEqual(list(od.items()), [('self', 23)]) |
| od = OrderedDict() |
| od.update(other={}) |
| self.assertEqual(list(od.items()), [('other', {})]) |
| od = OrderedDict() |
| od.update(red=5, blue=6, other=7, self=8) |
| self.assertEqual(sorted(list(od.items())), |
| [('blue', 6), ('other', 7), ('red', 5), ('self', 8)]) |
| |
| # Make sure that direct calls to update do not clear previous contents |
| # add that updates items are not moved to the end |
| d = OrderedDict([('a', 1), ('b', 2), ('c', 3), ('d', 44), ('e', 55)]) |
| d.update([('e', 5), ('f', 6)], g=7, d=4) |
| self.assertEqual(list(d.items()), |
| [('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', 5), ('f', 6), ('g', 7)]) |
| |
| self.assertRaises(TypeError, OrderedDict().update, 42) |
| self.assertRaises(TypeError, OrderedDict().update, (), ()) |
| self.assertRaises(TypeError, OrderedDict.update) |
| |
| def test_abc(self): |
| self.assertIsInstance(OrderedDict(), MutableMapping) |
| self.assertTrue(issubclass(OrderedDict, MutableMapping)) |
| |
| def test_clear(self): |
| pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)] |
| shuffle(pairs) |
| od = OrderedDict(pairs) |
| self.assertEqual(len(od), len(pairs)) |
| od.clear() |
| self.assertEqual(len(od), 0) |
| |
| def test_delitem(self): |
| pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)] |
| od = OrderedDict(pairs) |
| del od['a'] |
| self.assertNotIn('a', od) |
| with self.assertRaises(KeyError): |
| del od['a'] |
| self.assertEqual(list(od.items()), pairs[:2] + pairs[3:]) |
| |
| def test_setitem(self): |
| od = OrderedDict([('d', 1), ('b', 2), ('c', 3), ('a', 4), ('e', 5)]) |
| od['c'] = 10 # existing element |
| od['f'] = 20 # new element |
| self.assertEqual(list(od.items()), |
| [('d', 1), ('b', 2), ('c', 10), ('a', 4), ('e', 5), ('f', 20)]) |
| |
| def test_iterators(self): |
| pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)] |
| shuffle(pairs) |
| od = OrderedDict(pairs) |
| self.assertEqual(list(od), [t[0] for t in pairs]) |
| self.assertEqual(od.keys()[:], [t[0] for t in pairs]) |
| self.assertEqual(od.values()[:], [t[1] for t in pairs]) |
| self.assertEqual(od.items()[:], pairs) |
| self.assertEqual(list(od.iterkeys()), [t[0] for t in pairs]) |
| self.assertEqual(list(od.itervalues()), [t[1] for t in pairs]) |
| self.assertEqual(list(od.iteritems()), pairs) |
| self.assertEqual(list(reversed(od)), |
| [t[0] for t in reversed(pairs)]) |
| |
| def test_popitem(self): |
| pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)] |
| shuffle(pairs) |
| od = OrderedDict(pairs) |
| while pairs: |
| self.assertEqual(od.popitem(), pairs.pop()) |
| with self.assertRaises(KeyError): |
| od.popitem() |
| self.assertEqual(len(od), 0) |
| |
| def test_pop(self): |
| pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)] |
| shuffle(pairs) |
| od = OrderedDict(pairs) |
| shuffle(pairs) |
| while pairs: |
| k, v = pairs.pop() |
| self.assertEqual(od.pop(k), v) |
| with self.assertRaises(KeyError): |
| od.pop('xyz') |
| self.assertEqual(len(od), 0) |
| self.assertEqual(od.pop(k, 12345), 12345) |
| |
| # make sure pop still works when __missing__ is defined |
| class Missing(OrderedDict): |
| def __missing__(self, key): |
| return 0 |
| m = Missing(a=1) |
| self.assertEqual(m.pop('b', 5), 5) |
| self.assertEqual(m.pop('a', 6), 1) |
| self.assertEqual(m.pop('a', 6), 6) |
| with self.assertRaises(KeyError): |
| m.pop('a') |
| |
| def test_equality(self): |
| pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)] |
| shuffle(pairs) |
| od1 = OrderedDict(pairs) |
| od2 = OrderedDict(pairs) |
| self.assertEqual(od1, od2) # same order implies equality |
| pairs = pairs[2:] + pairs[:2] |
| od2 = OrderedDict(pairs) |
| self.assertNotEqual(od1, od2) # different order implies inequality |
| # comparison to regular dict is not order sensitive |
| self.assertEqual(od1, dict(od2)) |
| self.assertEqual(dict(od2), od1) |
| # different length implied inequality |
| self.assertNotEqual(od1, OrderedDict(pairs[:-1])) |
| |
| def test_copying(self): |
| # Check that ordered dicts are copyable, deepcopyable, picklable, |
| # and have a repr/eval round-trip |
| pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)] |
| od = OrderedDict(pairs) |
| update_test = OrderedDict() |
| update_test.update(od) |
| for i, dup in enumerate([ |
| od.copy(), |
| copy.copy(od), |
| copy.deepcopy(od), |
| pickle.loads(pickle.dumps(od, 0)), |
| pickle.loads(pickle.dumps(od, 1)), |
| pickle.loads(pickle.dumps(od, 2)), |
| pickle.loads(pickle.dumps(od, -1)), |
| eval(repr(od)), |
| update_test, |
| OrderedDict(od), |
| ]): |
| self.assertTrue(dup is not od) |
| self.assertEqual(dup, od) |
| self.assertEqual(list(dup.items()), list(od.items())) |
| self.assertEqual(len(dup), len(od)) |
| self.assertEqual(type(dup), type(od)) |
| |
| def test_yaml_linkage(self): |
| # Verify that __reduce__ is setup in a way that supports PyYAML's dump() feature. |
| # In yaml, lists are native but tuples are not. |
| pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)] |
| od = OrderedDict(pairs) |
| # yaml.dump(od) --> |
| # '!!python/object/apply:__main__.OrderedDict\n- - [a, 1]\n - [b, 2]\n' |
| self.assertTrue(all(type(pair)==list for pair in od.__reduce__()[1])) |
| |
| def test_reduce_not_too_fat(self): |
| # do not save instance dictionary if not needed |
| pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)] |
| od = OrderedDict(pairs) |
| self.assertEqual(len(od.__reduce__()), 2) |
| od.x = 10 |
| self.assertEqual(len(od.__reduce__()), 3) |
| |
| def test_repr(self): |
| od = OrderedDict([('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)]) |
| self.assertEqual(repr(od), |
| "OrderedDict([('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)])") |
| self.assertEqual(eval(repr(od)), od) |
| self.assertEqual(repr(OrderedDict()), "OrderedDict()") |
| |
| def test_repr_recursive(self): |
| # See issue #9826 |
| od = OrderedDict.fromkeys('abc') |
| od['x'] = od |
| self.assertEqual(repr(od), |
| "OrderedDict([('a', None), ('b', None), ('c', None), ('x', ...)])") |
| |
| def test_repr_recursive_values(self): |
| od = OrderedDict() |
| od[42] = od.viewvalues() |
| r = repr(od) |
| # Cannot perform a stronger test, as the contents of the repr |
| # are implementation-dependent. All we can say is that we |
| # want a str result, not an exception of any sort. |
| self.assertIsInstance(r, str) |
| od[42] = od.viewitems() |
| r = repr(od) |
| # Again. |
| self.assertIsInstance(r, str) |
| |
| def test_setdefault(self): |
| pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)] |
| shuffle(pairs) |
| od = OrderedDict(pairs) |
| pair_order = list(od.items()) |
| self.assertEqual(od.setdefault('a', 10), 3) |
| # make sure order didn't change |
| self.assertEqual(list(od.items()), pair_order) |
| self.assertEqual(od.setdefault('x', 10), 10) |
| # make sure 'x' is added to the end |
| self.assertEqual(list(od.items())[-1], ('x', 10)) |
| |
| # make sure setdefault still works when __missing__ is defined |
| class Missing(OrderedDict): |
| def __missing__(self, key): |
| return 0 |
| self.assertEqual(Missing().setdefault(5, 9), 9) |
| |
| def test_reinsert(self): |
| # Given insert a, insert b, delete a, re-insert a, |
| # verify that a is now later than b. |
| od = OrderedDict() |
| od['a'] = 1 |
| od['b'] = 2 |
| del od['a'] |
| od['a'] = 1 |
| self.assertEqual(list(od.items()), [('b', 2), ('a', 1)]) |
| |
| def test_views(self): |
| s = 'the quick brown fox jumped over a lazy dog yesterday before dawn'.split() |
| od = OrderedDict.fromkeys(s) |
| self.assertEqual(list(od.viewkeys()), s) |
| self.assertEqual(list(od.viewvalues()), [None for k in s]) |
| self.assertEqual(list(od.viewitems()), [(k, None) for k in s]) |
| |
| # See http://bugs.python.org/issue24286 |
| self.assertEqual(od.viewkeys(), dict(od).viewkeys()) |
| self.assertEqual(od.viewitems(), dict(od).viewitems()) |
| |
| def test_override_update(self): |
| # Verify that subclasses can override update() without breaking __init__() |
| class MyOD(OrderedDict): |
| def update(self, *args, **kwds): |
| raise Exception() |
| items = [('a', 1), ('c', 3), ('b', 2)] |
| self.assertEqual(list(MyOD(items).items()), items) |
| |
| def test_free_after_iterating(self): |
| test_support.check_free_after_iterating(self, iter, OrderedDict) |
| test_support.check_free_after_iterating(self, lambda d: d.iterkeys(), OrderedDict) |
| test_support.check_free_after_iterating(self, lambda d: d.itervalues(), OrderedDict) |
| test_support.check_free_after_iterating(self, lambda d: d.iteritems(), OrderedDict) |
| test_support.check_free_after_iterating(self, lambda d: iter(d.viewkeys()), OrderedDict) |
| test_support.check_free_after_iterating(self, lambda d: iter(d.viewvalues()), OrderedDict) |
| test_support.check_free_after_iterating(self, lambda d: iter(d.viewitems()), OrderedDict) |
| |
| class GeneralMappingTests(mapping_tests.BasicTestMappingProtocol): |
| type2test = OrderedDict |
| |
| def test_popitem(self): |
| d = self._empty_mapping() |
| self.assertRaises(KeyError, d.popitem) |
| |
| class MyOrderedDict(OrderedDict): |
| pass |
| |
| class SubclassMappingTests(mapping_tests.BasicTestMappingProtocol): |
| type2test = MyOrderedDict |
| |
| def test_popitem(self): |
| d = self._empty_mapping() |
| self.assertRaises(KeyError, d.popitem) |
| |
| |
| def test_main(verbose=None): |
| test_classes = [TestOrderedDict, GeneralMappingTests, SubclassMappingTests] |
| test_support.run_unittest(*test_classes) |
| |
| if __name__ == "__main__": |
| test_main(verbose=True) |