summaryrefslogtreecommitdiffstats
path: root/Lib/test/test_dict.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/test/test_dict.py')
-rw-r--r--Lib/test/test_dict.py125
1 files changed, 78 insertions, 47 deletions
diff --git a/Lib/test/test_dict.py b/Lib/test/test_dict.py
index bd3040a..bd79728 100644
--- a/Lib/test/test_dict.py
+++ b/Lib/test/test_dict.py
@@ -837,57 +837,60 @@ class DictTest(unittest.TestCase):
self._tracked(MyDict())
def test_iterator_pickling(self):
- data = {1:"a", 2:"b", 3:"c"}
- it = iter(data)
- d = pickle.dumps(it)
- it = pickle.loads(d)
- self.assertEqual(sorted(it), sorted(data))
-
- it = pickle.loads(d)
- try:
- drop = next(it)
- except StopIteration:
- return
- d = pickle.dumps(it)
- it = pickle.loads(d)
- del data[drop]
- self.assertEqual(sorted(it), sorted(data))
+ for proto in range(pickle.HIGHEST_PROTOCOL + 1):
+ data = {1:"a", 2:"b", 3:"c"}
+ it = iter(data)
+ d = pickle.dumps(it, proto)
+ it = pickle.loads(d)
+ self.assertEqual(sorted(it), sorted(data))
+
+ it = pickle.loads(d)
+ try:
+ drop = next(it)
+ except StopIteration:
+ continue
+ d = pickle.dumps(it, proto)
+ it = pickle.loads(d)
+ del data[drop]
+ self.assertEqual(sorted(it), sorted(data))
def test_itemiterator_pickling(self):
- data = {1:"a", 2:"b", 3:"c"}
- # dictviews aren't picklable, only their iterators
- itorg = iter(data.items())
- d = pickle.dumps(itorg)
- it = pickle.loads(d)
- # note that the type of type of the unpickled iterator
- # is not necessarily the same as the original. It is
- # merely an object supporting the iterator protocol, yielding
- # the same objects as the original one.
- # self.assertEqual(type(itorg), type(it))
- self.assertTrue(isinstance(it, collections.abc.Iterator))
- self.assertEqual(dict(it), data)
-
- it = pickle.loads(d)
- drop = next(it)
- d = pickle.dumps(it)
- it = pickle.loads(d)
- del data[drop[0]]
- self.assertEqual(dict(it), data)
+ for proto in range(pickle.HIGHEST_PROTOCOL + 1):
+ data = {1:"a", 2:"b", 3:"c"}
+ # dictviews aren't picklable, only their iterators
+ itorg = iter(data.items())
+ d = pickle.dumps(itorg, proto)
+ it = pickle.loads(d)
+ # note that the type of type of the unpickled iterator
+ # is not necessarily the same as the original. It is
+ # merely an object supporting the iterator protocol, yielding
+ # the same objects as the original one.
+ # self.assertEqual(type(itorg), type(it))
+ self.assertIsInstance(it, collections.abc.Iterator)
+ self.assertEqual(dict(it), data)
+
+ it = pickle.loads(d)
+ drop = next(it)
+ d = pickle.dumps(it, proto)
+ it = pickle.loads(d)
+ del data[drop[0]]
+ self.assertEqual(dict(it), data)
def test_valuesiterator_pickling(self):
- data = {1:"a", 2:"b", 3:"c"}
- # data.values() isn't picklable, only its iterator
- it = iter(data.values())
- d = pickle.dumps(it)
- it = pickle.loads(d)
- self.assertEqual(sorted(list(it)), sorted(list(data.values())))
-
- it = pickle.loads(d)
- drop = next(it)
- d = pickle.dumps(it)
- it = pickle.loads(d)
- values = list(it) + [drop]
- self.assertEqual(sorted(values), sorted(list(data.values())))
+ for proto in range(pickle.HIGHEST_PROTOCOL):
+ data = {1:"a", 2:"b", 3:"c"}
+ # data.values() isn't picklable, only its iterator
+ it = iter(data.values())
+ d = pickle.dumps(it, proto)
+ it = pickle.loads(d)
+ self.assertEqual(sorted(list(it)), sorted(list(data.values())))
+
+ it = pickle.loads(d)
+ drop = next(it)
+ d = pickle.dumps(it, proto)
+ it = pickle.loads(d)
+ values = list(it) + [drop]
+ self.assertEqual(sorted(values), sorted(list(data.values())))
def test_instance_dict_getattr_str_subclass(self):
class Foo:
@@ -906,6 +909,34 @@ class DictTest(unittest.TestCase):
f.a = 'a'
self.assertEqual(f.__dict__, {1:1, 'a':'a'})
+ def check_reentrant_insertion(self, mutate):
+ # This object will trigger mutation of the dict when replaced
+ # by another value. Note this relies on refcounting: the test
+ # won't achieve its purpose on fully-GCed Python implementations.
+ class Mutating:
+ def __del__(self):
+ mutate(d)
+
+ d = {k: Mutating() for k in 'abcdefghijklmnopqr'}
+ for k in list(d):
+ d[k] = k
+
+ def test_reentrant_insertion(self):
+ # Reentrant insertion shouldn't crash (see issue #22653)
+ def mutate(d):
+ d['b'] = 5
+ self.check_reentrant_insertion(mutate)
+
+ def mutate(d):
+ d.update(self.__dict__)
+ d.clear()
+ self.check_reentrant_insertion(mutate)
+
+ def mutate(d):
+ while d:
+ d.popitem()
+ self.check_reentrant_insertion(mutate)
+
def test_merge_and_mutate(self):
class X:
def __hash__(self):