]> granicus.if.org Git - python/commitdiff
Issue #25616: Tests for OrderedDict are extracted from test_collections
authorSerhiy Storchaka <storchaka@gmail.com>
Wed, 25 Nov 2015 15:12:02 +0000 (17:12 +0200)
committerSerhiy Storchaka <storchaka@gmail.com>
Wed, 25 Nov 2015 15:12:02 +0000 (17:12 +0200)
into separate file test_ordered_dict.

1  2 
Lib/test/test_collections.py
Lib/test/test_ordered_dict.py
Misc/NEWS

index b9fdf79463905ef24731f36504ecafa73448989d,0882bac9fce4705bc2d202f62b942b12e7fe4001..4c32e094f9e318ce32935b005577aa47bd5e5fc7
@@@ -1,23 -1,22 +1,26 @@@
  """Unit tests for collections.py."""
  
- import unittest, doctest, operator
- from test.support import TESTFN, forget, unlink, import_fresh_module
- import contextlib
+ import collections
+ import copy
+ import doctest
 +import inspect
- from test import support
- from collections import namedtuple, Counter, OrderedDict, _count_elements
- from test import mapping_tests
- import pickle, copy
- from random import randrange, shuffle
  import keyword
+ import operator
+ import pickle
+ from random import choice, randrange
  import re
+ import string
  import sys
 -from collections import UserDict
+ from test import support
 +import types
+ import unittest
+ from collections import namedtuple, Counter, OrderedDict, _count_elements
 +from collections import UserDict, UserString, UserList
  from collections import ChainMap
 -from collections.abc import Hashable, Iterable, Iterator
 +from collections import deque
 +from collections.abc import Awaitable, Coroutine, AsyncIterator, AsyncIterable
 +from collections.abc import Hashable, Iterable, Iterator, Generator
  from collections.abc import Sized, Container, Callable
  from collections.abc import Set, MutableSet
  from collections.abc import Mapping, MutableMapping, KeysView, ItemsView
@@@ -2301,16 -1289,7 +1629,9 @@@ class TestCounter(unittest.TestCase)
  def test_main(verbose=None):
      NamedTupleDocs = doctest.DocTestSuite(module=collections)
      test_classes = [TestNamedTuple, NamedTupleDocs, TestOneTrickPonyABCs,
 -                    TestCollectionABCs, TestCounter, TestChainMap]
 +                    TestCollectionABCs, TestCounter, TestChainMap,
-                     PurePythonOrderedDictTests, CPythonOrderedDictTests,
-                     PurePythonOrderedDictSubclassTests,
-                     CPythonOrderedDictSubclassTests,
-                     PurePythonGeneralMappingTests, CPythonGeneralMappingTests,
-                     PurePythonSubclassMappingTests, CPythonSubclassMappingTests,
 +                    TestUserObjects,
 +                    ]
      support.run_unittest(*test_classes)
      support.run_doctest(collections, verbose)
  
index 0000000000000000000000000000000000000000,6d3e3092840183c41fdd8b86db88d8964ce88a93..4b092279692c212731a76bed89edc2086c97229f
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,302 +1,683 @@@
 -from random import shuffle
+ import contextlib
+ import copy
+ import pickle
 -from collections import OrderedDict
++from random import randrange, shuffle
+ import sys
+ import unittest
 -class TestOrderedDict(unittest.TestCase):
+ from collections.abc import MutableMapping
+ from test import mapping_tests, support
 -        for proto in range(pickle.HIGHEST_PROTOCOL + 1):
 -            with self.subTest(proto=proto):
 -                check(pickle.loads(pickle.dumps(od, proto)))
++py_coll = support.import_fresh_module('collections', blocked=['_collections'])
++c_coll = support.import_fresh_module('collections', fresh=['_collections'])
++
++
++@contextlib.contextmanager
++def replaced_module(name, replacement):
++    original_module = sys.modules[name]
++    sys.modules[name] = replacement
++    try:
++        yield
++    finally:
++        sys.modules[name] = original_module
++
++
++class OrderedDictTests:
+     def test_init(self):
++        OrderedDict = self.OrderedDict
+         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):
++        OrderedDict = self.OrderedDict
+         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)
++        self.assertRaises(TypeError, OrderedDict().update, 42)
++        self.assertRaises(TypeError, OrderedDict().update, (), ())
++        self.assertRaises(TypeError, OrderedDict.update)
++
++    def test_fromkeys(self):
++        OrderedDict = self.OrderedDict
++        od = OrderedDict.fromkeys('abc')
++        self.assertEqual(list(od.items()), [(c, None) for c in 'abc'])
++        od = OrderedDict.fromkeys('abc', value=None)
++        self.assertEqual(list(od.items()), [(c, None) for c in 'abc'])
++        od = OrderedDict.fromkeys('abc', value=0)
++        self.assertEqual(list(od.items()), [(c, 0) for c in 'abc'])
++
+     def test_abc(self):
++        OrderedDict = self.OrderedDict
+         self.assertIsInstance(OrderedDict(), MutableMapping)
+         self.assertTrue(issubclass(OrderedDict, MutableMapping))
+     def test_clear(self):
++        OrderedDict = self.OrderedDict
+         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):
++        OrderedDict = self.OrderedDict
+         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):
++        OrderedDict = self.OrderedDict
+         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):
++        OrderedDict = self.OrderedDict
+         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(list(od.keys()), [t[0] for t in pairs])
+         self.assertEqual(list(od.values()), [t[1] for t in pairs])
+         self.assertEqual(list(od.items()), pairs)
+         self.assertEqual(list(reversed(od)),
+                          [t[0] for t in reversed(pairs)])
++        self.assertEqual(list(reversed(od.keys())),
++                         [t[0] for t in reversed(pairs)])
++        self.assertEqual(list(reversed(od.values())),
++                         [t[1] for t in reversed(pairs)])
++        self.assertEqual(list(reversed(od.items())), list(reversed(pairs)))
++
++    def test_detect_deletion_during_iteration(self):
++        OrderedDict = self.OrderedDict
++        od = OrderedDict.fromkeys('abc')
++        it = iter(od)
++        key = next(it)
++        del od[key]
++        with self.assertRaises(Exception):
++            # Note, the exact exception raised is not guaranteed
++            # The only guarantee that the next() will not succeed
++            next(it)
++
++    def test_sorted_iterators(self):
++        OrderedDict = self.OrderedDict
++        with self.assertRaises(TypeError):
++            OrderedDict([('a', 1), ('b', 2)], None)
++        pairs = [('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', 5)]
++        od = OrderedDict(pairs)
++        self.assertEqual(sorted(od), [t[0] for t in pairs])
++        self.assertEqual(sorted(od.keys()), [t[0] for t in pairs])
++        self.assertEqual(sorted(od.values()), [t[1] for t in pairs])
++        self.assertEqual(sorted(od.items()), pairs)
++        self.assertEqual(sorted(reversed(od)),
++                         sorted([t[0] for t in reversed(pairs)]))
++
++    def test_iterators_empty(self):
++        OrderedDict = self.OrderedDict
++        od = OrderedDict()
++        empty = []
++        self.assertEqual(list(od), empty)
++        self.assertEqual(list(od.keys()), empty)
++        self.assertEqual(list(od.values()), empty)
++        self.assertEqual(list(od.items()), empty)
++        self.assertEqual(list(reversed(od)), empty)
++        self.assertEqual(list(reversed(od.keys())), empty)
++        self.assertEqual(list(reversed(od.values())), empty)
++        self.assertEqual(list(reversed(od.items())), empty)
+     def test_popitem(self):
++        OrderedDict = self.OrderedDict
+         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_popitem_last(self):
++        OrderedDict = self.OrderedDict
++        pairs = [(i, i) for i in range(30)]
++
++        obj = OrderedDict(pairs)
++        for i in range(8):
++            obj.popitem(True)
++        obj.popitem(True)
++        obj.popitem(last=True)
++        self.assertEqual(len(obj), 20)
++
+     def test_pop(self):
++        OrderedDict = self.OrderedDict
+         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)
++        self.assertEqual(m.pop('a', default=6), 6)
+         with self.assertRaises(KeyError):
+             m.pop('a')
+     def test_equality(self):
++        OrderedDict = self.OrderedDict
+         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):
++        OrderedDict = self.OrderedDict
+         # 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)
+         def check(dup):
+             msg = "\ncopy: %s\nod: %s" % (dup, od)
+             self.assertIsNot(dup, od, msg)
+             self.assertEqual(dup, od)
++            self.assertEqual(list(dup.items()), list(od.items()))
++            self.assertEqual(len(dup), len(od))
++            self.assertEqual(type(dup), type(od))
+         check(od.copy())
+         check(copy.copy(od))
+         check(copy.deepcopy(od))
 -        for proto in range(-1, pickle.HIGHEST_PROTOCOL + 1):
 -            dup = pickle.loads(pickle.dumps(od, proto))
 -            self.assertIsNot(dup, od)
 -            self.assertEqual(list(dup.keys()), [1])
 -            self.assertIs(dup[1], dup)
++        # pickle directly pulls the module, so we have to fake it
++        with replaced_module('collections', self.module):
++            for proto in range(pickle.HIGHEST_PROTOCOL + 1):
++                with self.subTest(proto=proto):
++                    check(pickle.loads(pickle.dumps(od, proto)))
+         check(eval(repr(od)))
+         update_test = OrderedDict()
+         update_test.update(od)
+         check(update_test)
+         check(OrderedDict(od))
+     def test_yaml_linkage(self):
++        OrderedDict = self.OrderedDict
+         # 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):
++        OrderedDict = self.OrderedDict
+         # 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.assertIsNone(od.__reduce__()[2])
+         od.x = 10
+         self.assertIsNotNone(od.__reduce__()[2])
+     def test_pickle_recursive(self):
++        OrderedDict = self.OrderedDict
+         od = OrderedDict()
+         od[1] = od
 -class GeneralMappingTests(mapping_tests.BasicTestMappingProtocol):
 -    type2test = OrderedDict
++
++        # pickle directly pulls the module, so we have to fake it
++        with replaced_module('collections', self.module):
++            for proto in range(-1, pickle.HIGHEST_PROTOCOL + 1):
++                dup = pickle.loads(pickle.dumps(od, proto))
++                self.assertIsNot(dup, od)
++                self.assertEqual(list(dup.keys()), [1])
++                self.assertIs(dup[1], dup)
+     def test_repr(self):
++        OrderedDict = self.OrderedDict
+         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):
++        OrderedDict = self.OrderedDict
+         # See issue #9826
+         od = OrderedDict.fromkeys('abc')
+         od['x'] = od
+         self.assertEqual(repr(od),
+             "OrderedDict([('a', None), ('b', None), ('c', None), ('x', ...)])")
+     def test_setdefault(self):
++        OrderedDict = self.OrderedDict
+         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))
++        self.assertEqual(od.setdefault('g', default=9), 9)
+         # 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):
++        OrderedDict = self.OrderedDict
+         # 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']
++        self.assertEqual(list(od.items()), [('b', 2)])
+         od['a'] = 1
+         self.assertEqual(list(od.items()), [('b', 2), ('a', 1)])
+     def test_move_to_end(self):
++        OrderedDict = self.OrderedDict
+         od = OrderedDict.fromkeys('abcde')
+         self.assertEqual(list(od), list('abcde'))
+         od.move_to_end('c')
+         self.assertEqual(list(od), list('abdec'))
+         od.move_to_end('c', 0)
+         self.assertEqual(list(od), list('cabde'))
+         od.move_to_end('c', 0)
+         self.assertEqual(list(od), list('cabde'))
+         od.move_to_end('e')
+         self.assertEqual(list(od), list('cabde'))
++        od.move_to_end('b', last=False)
++        self.assertEqual(list(od), list('bcade'))
+         with self.assertRaises(KeyError):
+             od.move_to_end('x')
++        with self.assertRaises(KeyError):
++            od.move_to_end('x', 0)
++
++    def test_move_to_end_issue25406(self):
++        OrderedDict = self.OrderedDict
++        od = OrderedDict.fromkeys('abc')
++        od.move_to_end('c', last=False)
++        self.assertEqual(list(od), list('cab'))
++        od.move_to_end('a', last=False)
++        self.assertEqual(list(od), list('acb'))
++
++        od = OrderedDict.fromkeys('abc')
++        od.move_to_end('a')
++        self.assertEqual(list(od), list('bca'))
++        od.move_to_end('c')
++        self.assertEqual(list(od), list('bac'))
+     def test_sizeof(self):
++        OrderedDict = self.OrderedDict
+         # Wimpy test: Just verify the reported size is larger than a regular dict
+         d = dict(a=1)
+         od = OrderedDict(**d)
+         self.assertGreater(sys.getsizeof(od), sys.getsizeof(d))
+     def test_override_update(self):
++        OrderedDict = self.OrderedDict
+         # 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)
 -class MyOrderedDict(OrderedDict):
 -    pass
++    def test_highly_nested(self):
++        # Issue 25395: crashes during garbage collection
++        OrderedDict = self.OrderedDict
++        obj = None
++        for _ in range(1000):
++            obj = OrderedDict([(None, obj)])
++        del obj
++        support.gc_collect()
++
++    def test_highly_nested_subclass(self):
++        # Issue 25395: crashes during garbage collection
++        OrderedDict = self.OrderedDict
++        deleted = []
++        class MyOD(OrderedDict):
++            def __del__(self):
++                deleted.append(self.i)
++        obj = None
++        for i in range(100):
++            obj = MyOD([(None, obj)])
++            obj.i = i
++        del obj
++        support.gc_collect()
++        self.assertEqual(deleted, list(reversed(range(100))))
++
++    def test_delitem_hash_collision(self):
++        OrderedDict = self.OrderedDict
++
++        class Key:
++            def __init__(self, hash):
++                self._hash = hash
++                self.value = str(id(self))
++            def __hash__(self):
++                return self._hash
++            def __eq__(self, other):
++                try:
++                    return self.value == other.value
++                except AttributeError:
++                    return False
++            def __repr__(self):
++                return self.value
++
++        def blocking_hash(hash):
++            # See the collision-handling in lookdict (in Objects/dictobject.c).
++            MINSIZE = 8
++            i = (hash & MINSIZE-1)
++            return (i << 2) + i + hash + 1
++
++        COLLIDING = 1
++
++        key = Key(COLLIDING)
++        colliding = Key(COLLIDING)
++        blocking = Key(blocking_hash(COLLIDING))
++
++        od = OrderedDict()
++        od[key] = ...
++        od[blocking] = ...
++        od[colliding] = ...
++        od['after'] = ...
++
++        del od[blocking]
++        del od[colliding]
++        self.assertEqual(list(od.items()), [(key, ...), ('after', ...)])
++
++    def test_issue24347(self):
++        OrderedDict = self.OrderedDict
++
++        class Key:
++            def __hash__(self):
++                return randrange(100000)
++
++        od = OrderedDict()
++        for i in range(100):
++            key = Key()
++            od[key] = i
++
++        # These should not crash.
++        with self.assertRaises(KeyError):
++            list(od.values())
++        with self.assertRaises(KeyError):
++            list(od.items())
++        with self.assertRaises(KeyError):
++            repr(od)
++        with self.assertRaises(KeyError):
++            od.copy()
++
++    def test_issue24348(self):
++        OrderedDict = self.OrderedDict
++
++        class Key:
++            def __hash__(self):
++                return 1
++
++        od = OrderedDict()
++        od[Key()] = 0
++        # This should not crash.
++        od.popitem()
++
++    def test_issue24667(self):
++        """
++        dict resizes after a certain number of insertion operations,
++        whether or not there were deletions that freed up slots in the
++        hash table.  During fast node lookup, OrderedDict must correctly
++        respond to all resizes, even if the current "size" is the same
++        as the old one.  We verify that here by forcing a dict resize
++        on a sparse odict and then perform an operation that should
++        trigger an odict resize (e.g. popitem).  One key aspect here is
++        that we will keep the size of the odict the same at each popitem
++        call.  This verifies that we handled the dict resize properly.
++        """
++        OrderedDict = self.OrderedDict
++
++        od = OrderedDict()
++        for c0 in '0123456789ABCDEF':
++            for c1 in '0123456789ABCDEF':
++                if len(od) == 4:
++                    # This should not raise a KeyError.
++                    od.popitem(last=False)
++                key = c0 + c1
++                od[key] = key
++
++    # Direct use of dict methods
++
++    def test_dict_setitem(self):
++        OrderedDict = self.OrderedDict
++        od = OrderedDict()
++        dict.__setitem__(od, 'spam', 1)
++        self.assertNotIn('NULL', repr(od))
++
++    def test_dict_delitem(self):
++        OrderedDict = self.OrderedDict
++        od = OrderedDict()
++        od['spam'] = 1
++        od['ham'] = 2
++        dict.__delitem__(od, 'spam')
++        with self.assertRaises(KeyError):
++            repr(od)
++
++    def test_dict_clear(self):
++        OrderedDict = self.OrderedDict
++        od = OrderedDict()
++        od['spam'] = 1
++        od['ham'] = 2
++        dict.clear(od)
++        self.assertNotIn('NULL', repr(od))
++
++    def test_dict_pop(self):
++        OrderedDict = self.OrderedDict
++        od = OrderedDict()
++        od['spam'] = 1
++        od['ham'] = 2
++        dict.pop(od, 'spam')
++        with self.assertRaises(KeyError):
++            repr(od)
++
++    def test_dict_popitem(self):
++        OrderedDict = self.OrderedDict
++        od = OrderedDict()
++        od['spam'] = 1
++        od['ham'] = 2
++        dict.popitem(od)
++        with self.assertRaises(KeyError):
++            repr(od)
++
++    def test_dict_setdefault(self):
++        OrderedDict = self.OrderedDict
++        od = OrderedDict()
++        dict.setdefault(od, 'spam', 1)
++        self.assertNotIn('NULL', repr(od))
++
++    def test_dict_update(self):
++        OrderedDict = self.OrderedDict
++        od = OrderedDict()
++        dict.update(od, [('spam', 1)])
++        self.assertNotIn('NULL', repr(od))
++
++
++class PurePythonOrderedDictTests(OrderedDictTests, unittest.TestCase):
++
++    module = py_coll
++    OrderedDict = py_coll.OrderedDict
++
++
++@unittest.skipUnless(c_coll, 'requires the C version of the collections module')
++class CPythonOrderedDictTests(OrderedDictTests, unittest.TestCase):
++
++    module = c_coll
++    OrderedDict = c_coll.OrderedDict
++
++    def test_key_change_during_iteration(self):
++        OrderedDict = self.OrderedDict
++
++        od = OrderedDict.fromkeys('abcde')
++        self.assertEqual(list(od), list('abcde'))
++        with self.assertRaises(RuntimeError):
++            for i, k in enumerate(od):
++                od.move_to_end(k)
++                self.assertLess(i, 5)
++        with self.assertRaises(RuntimeError):
++            for k in od:
++                od['f'] = None
++        with self.assertRaises(RuntimeError):
++            for k in od:
++                del od['c']
++        self.assertEqual(list(od), list('bdeaf'))
++
++
++class PurePythonOrderedDictSubclassTests(PurePythonOrderedDictTests):
++
++    module = py_coll
++    class OrderedDict(py_coll.OrderedDict):
++        pass
++
++
++class CPythonOrderedDictSubclassTests(CPythonOrderedDictTests):
++
++    module = c_coll
++    class OrderedDict(c_coll.OrderedDict):
++        pass
++
++
++class PurePythonGeneralMappingTests(mapping_tests.BasicTestMappingProtocol):
++
++    @classmethod
++    def setUpClass(cls):
++        cls.type2test = py_coll.OrderedDict
+     def test_popitem(self):
+         d = self._empty_mapping()
+         self.assertRaises(KeyError, d.popitem)
 -class SubclassMappingTests(mapping_tests.BasicTestMappingProtocol):
 -    type2test = MyOrderedDict
++@unittest.skipUnless(c_coll, 'requires the C version of the collections module')
++class CPythonGeneralMappingTests(mapping_tests.BasicTestMappingProtocol):
++
++    @classmethod
++    def setUpClass(cls):
++        cls.type2test = c_coll.OrderedDict
++
++    def test_popitem(self):
++        d = self._empty_mapping()
++        self.assertRaises(KeyError, d.popitem)
++
++
++class PurePythonSubclassMappingTests(mapping_tests.BasicTestMappingProtocol):
++
++    @classmethod
++    def setUpClass(cls):
++        class MyOrderedDict(py_coll.OrderedDict):
++            pass
++        cls.type2test = MyOrderedDict
++
++    def test_popitem(self):
++        d = self._empty_mapping()
++        self.assertRaises(KeyError, d.popitem)
++
++
++@unittest.skipUnless(c_coll, 'requires the C version of the collections module')
++class CPythonSubclassMappingTests(mapping_tests.BasicTestMappingProtocol):
++
++    @classmethod
++    def setUpClass(cls):
++        class MyOrderedDict(c_coll.OrderedDict):
++            pass
++        cls.type2test = MyOrderedDict
+     def test_popitem(self):
+         d = self._empty_mapping()
+         self.assertRaises(KeyError, d.popitem)
+ if __name__ == "__main__":
+     unittest.main()
diff --cc Misc/NEWS
index 99e962be28a88626c09741a6b3ead80031b34b0d,fa365cc0dd0aaf2c09e4316c238cea2f78df17cf..ba4b54ccd069adcb0f08bf31759a3d9e0e1bda14
+++ b/Misc/NEWS
@@@ -14,117 -14,116 +14,123 @@@ Core and Builtin
    __bytes__, __trunc__, and __float__ returning instances of subclasses of
    bytes, int, and float to subclasses of bytes, int, and float correspondingly.
  
 -- Issue #25388: Fixed tokenizer crash when processing undecodable source code
 -  with a null byte.
 +Library
 +-------
  
 -- Issue #22995: Default implementation of __reduce__ and __reduce_ex__ now
 -  rejects builtin types with not defined __new__.
 +- Issue #25725: Fixed a reference leak in pickle.loads() when unpickling
 +  invalid data including tuple instructions.
  
 -- Issue #24802: Avoid buffer overreads when int(), float(), compile(), exec()
 -  and eval() are passed bytes-like objects.  These objects are not
 -  necessarily terminated by a null byte, but the functions assumed they were.
 +- Issue #25663: In the Readline completer, avoid listing duplicate global
 +  names, and search the global namespace before searching builtins.
  
 -- Issue #24402: Fix input() to prompt to the redirected stdout when
 -  sys.stdout.fileno() fails.
 +- Issue #25688: Fixed file leak in ElementTree.iterparse() raising an error.
  
 -- Issue #24806: Prevent builtin types that are not allowed to be subclassed from
 -  being subclassed through multiple inheritance.
 +- Issue #23914: Fixed SystemError raised by unpickler on broken pickle data.
  
 -- Issue #24848: Fixed a number of bugs in UTF-7 decoding of misformed data.
 +- Issue #25691: Fixed crash on deleting ElementTree.Element attributes.
  
 -- Issue #25280: Import trace messages emitted in verbose (-v) mode are no
 -  longer formatted twice.
 +- Issue #25624: ZipFile now always writes a ZIP_STORED header for directory
 +  entries.  Patch by Dingyuan Wang.
  
 -- Issue #25003: os.urandom() doesn't use getentropy() on Solaris because
 -  getentropy() is blocking, whereas os.urandom() should not block. getentropy()
 -  is supported since Solaris 11.3.
++Tests
++-----
 -- Issue #25182: The stdprinter (used as sys.stderr before the io module is
 -  imported at startup) now uses the backslashreplace error handler.
++- Issue #25616: Tests for OrderedDict are extracted from test_collections
++  into separate file test_ordered_dict.
 -- Issue #24891: Fix a race condition at Python startup if the file descriptor
 -  of stdin (0), stdout (1) or stderr (2) is closed while Python is creating
 -  sys.stdin, sys.stdout and sys.stderr objects. These attributes are now set
 -  to None if the creation of the object failed, instead of raising an OSError
 -  exception. Initial patch written by Marco Paolini.
  
 -- Issue #21167: NAN operations are now handled correctly when python is
 -  compiled with ICC even if -fp-model strict is not specified.
 +What's New in Python 3.5.1 final?
 +=================================
  
 -- Issue #4395: Better testing and documentation of binary operators.
 -  Patch by Martin Panter.
 +Release date: 2015-12-06
  
 -- Issue #24467: Fixed possible buffer over-read in bytearray. The bytearray
 -  object now always allocates place for trailing null byte and it's buffer now
 -  is always null-terminated.
 +Core and Builtins
 +-----------------
  
 -- Issue #24115: Update uses of PyObject_IsTrue(), PyObject_Not(),
 -  PyObject_IsInstance(), PyObject_RichCompareBool() and _PyDict_Contains()
 -  to check for and handle errors correctly.
 +Library
 +-------
  
 -- Issue #24257: Fixed system error in the comparison of faked
 -  types.SimpleNamespace.
  
 -- Issue #22939: Fixed integer overflow in iterator object.  Patch by
 -  Clement Rouault.
 +What's New in Python 3.5.1 release candidate 1?
 +===============================================
  
 -- Issue #23985: Fix a possible buffer overrun when deleting a slice from
 -  the front of a bytearray and then appending some other bytes data.
 +Release date: 2015-11-22
  
 -- Issue #24102: Fixed exception type checking in standard error handlers.
 +Core and Builtins
 +-----------------
  
 -- Issue #23757: PySequence_Tuple() incorrectly called the concrete list API
 -  when the data was a list subclass.
 +- Issue #25630: Fix a possible segfault during argument parsing in functions
 +  that accept filesystem paths.
  
 -- Issue #24407: Fix crash when dict is mutated while being updated.
 +- Issue #23564: Fixed a partially broken sanity check in the _posixsubprocess
 +  internals regarding how fds_to_pass were passed to the child.  The bug had
 +  no actual impact as subprocess.py already avoided it.
  
 -- Issue #24096: Make warnings.warn_explicit more robust against mutation of the
 -  warnings.filters list.
 +- Issue #25388: Fixed tokenizer crash when processing undecodable source code
 +  with a null byte.
  
 -- Issue #23996: Avoid a crash when a delegated generator raises an
 -  unnormalized StopIteration exception.  Patch by Stefan Behnel.
 +- Issue #25462: The hash of the key now is calculated only once in most
 +  operations in C implementation of OrderedDict.
  
 -- Issue #24022: Fix tokenizer crash when processing undecodable source code.
 +- Issue #22995: Default implementation of __reduce__ and __reduce_ex__ now
 +  rejects builtin types with not defined __new__.
  
 -- Issue #23309: Avoid a deadlock at shutdown if a daemon thread is aborted
 -  while it is holding a lock to a buffered I/O object, and the main thread
 -  tries to use the same I/O object (typically stdout or stderr).  A fatal
 -  error is emitted instead.
 +- Issue #25555: Fix parser and AST: fill lineno and col_offset of "arg" node
 +  when compiling AST from Python objects.
  
 -- Issue #22977: Fixed formatting Windows error messages on Wine.
 -  Patch by Martin Panter.
 +- Issue #24802: Avoid buffer overreads when int(), float(), compile(), exec()
 +  and eval() are passed bytes-like objects.  These objects are not
 +  necessarily terminated by a null byte, but the functions assumed they were.
  
 -- Issue #23803: Fixed str.partition() and str.rpartition() when a separator
 -  is wider then partitioned string.
 +- Issue #24726: Fixed a crash and leaking NULL in repr() of OrderedDict that
 +  was mutated by direct calls of dict methods.
  
 -- Issue #23192: Fixed generator lambdas.  Patch by Bruno Cauet.
 +- Issue #25449: Iterating OrderedDict with keys with unstable hash now raises
 +  KeyError in C implementations as well as in Python implementation.
  
 -- Issue #23629: Fix the default __sizeof__ implementation for variable-sized
 -  objects.
 +- Issue #25395: Fixed crash when highly nested OrderedDict structures were
 +  garbage collected.
  
 -- Issue #24044: Fix possible null pointer dereference in list.sort in out of
 -  memory conditions.
 +- Issue #25274: sys.setrecursionlimit() now raises a RecursionError if the new
 +  recursion limit is too low depending at the current recursion depth. Modify
 +  also the "lower-water mark" formula to make it monotonic. This mark is used
 +  to decide when the overflowed flag of the thread state is reset.
  
 -- Issue #21354: PyCFunction_New function is exposed by python DLL again.
 +- Issue #24402: Fix input() to prompt to the redirected stdout when
 +  sys.stdout.fileno() fails.
  
 -Library
 --------
 +- Issue #24806: Prevent builtin types that are not allowed to be subclassed from
 +  being subclassed through multiple inheritance.
  
 -- Issue #25725: Fixed a reference leak in pickle.loads() when unpickling
 -  invalid data including tuple instructions.
 +- Issue #24848: Fixed a number of bugs in UTF-7 decoding of misformed data.
  
 -- Issue #25663: In the Readline completer, avoid listing duplicate global
 -  names, and search the global namespace before searching builtins.
 +- Issue #25280: Import trace messages emitted in verbose (-v) mode are no
 +  longer formatted twice.
  
 -- Issue #25688: Fixed file leak in ElementTree.iterparse() raising an error.
 +- Issue #25003: On Solaris 11.3 or newer, os.urandom() now uses the
 +  getrandom() function instead of the getentropy() function. The getentropy()
 +  function is blocking to generate very good quality entropy, os.urandom()
 +  doesn't need such high-quality entropy.
  
 -- Issue #23914: Fixed SystemError raised by unpickler on broken pickle data.
 +- Issue #25182: The stdprinter (used as sys.stderr before the io module is
 +  imported at startup) now uses the backslashreplace error handler.
  
 -- Issue #25691: Fixed crash on deleting ElementTree.Element attributes.
 +- Issue #25131: Make the line number and column offset of set/dict literals and
 +  comprehensions correspond to the opening brace.
  
 -- Issue #25624: ZipFile now always writes a ZIP_STORED header for directory
 -  entries.  Patch by Dingyuan Wang.
 +- Issue #25150: Hide the private _Py_atomic_xxx symbols from the public
 +  Python.h header to fix a compilation error with OpenMP. PyThreadState_GET()
 +  becomes an alias to PyThreadState_Get() to avoid ABI incompatibilies.
 +
 +Library
 +-------
 +
 +- Issue #25626: Change three zlib functions to accept sizes that fit in
 +  Py_ssize_t, but internally cap those sizes to UINT_MAX.  This resolves a
 +  regression in 3.5 where GzipFile.read() failed to read chunks larger than 2
 +  or 4 GiB.  The change affects the zlib.Decompress.decompress() max_length
 +  parameter, the zlib.decompress() bufsize parameter, and the
 +  zlib.Decompress.flush() length parameter.
  
  - Issue #25583: Avoid incorrect errors raised by os.makedirs(exist_ok=True)
    when the OS gives priority to errors such as EACCES over EEXIST.