diff options
author | Kristján Valur Jónsson <sweskman@gmail.com> | 2013-12-05 10:03:45 (GMT) |
---|---|---|
committer | Kristján Valur Jónsson <sweskman@gmail.com> | 2013-12-05 10:03:45 (GMT) |
commit | 222b284911d1d4057f2034c41aa810693fc64f02 (patch) | |
tree | d5e0b04a485749d91d8dd8789ddda2d860905d51 /Lib/test/test_weakset.py | |
parent | c289fa75564872d33e5911e0b44e657ae9e7fbcc (diff) | |
download | cpython-222b284911d1d4057f2034c41aa810693fc64f02.zip cpython-222b284911d1d4057f2034c41aa810693fc64f02.tar.gz cpython-222b284911d1d4057f2034c41aa810693fc64f02.tar.bz2 |
Issue #7105: weak dict iterators are fragile because of unpredictable GC runs
Backport the fix from pyton 3.x for this issue.
Diffstat (limited to 'Lib/test/test_weakset.py')
-rw-r--r-- | Lib/test/test_weakset.py | 49 |
1 files changed, 49 insertions, 0 deletions
diff --git a/Lib/test/test_weakset.py b/Lib/test/test_weakset.py index fb9e8d7..6b34a8d 100644 --- a/Lib/test/test_weakset.py +++ b/Lib/test/test_weakset.py @@ -11,6 +11,7 @@ import warnings import collections import gc import contextlib +from UserString import UserString as ustr class Foo: @@ -448,6 +449,54 @@ class TestWeakSet(unittest.TestCase): self.assertGreaterEqual(n2, 0) self.assertLessEqual(n2, n1) + def test_weak_destroy_while_iterating(self): + # Issue #7105: iterators shouldn't crash when a key is implicitly removed + # Create new items to be sure no-one else holds a reference + items = [ustr(c) for c in ('a', 'b', 'c')] + s = WeakSet(items) + it = iter(s) + next(it) # Trigger internal iteration + # Destroy an item + del items[-1] + gc.collect() # just in case + # We have removed either the first consumed items, or another one + self.assertIn(len(list(it)), [len(items), len(items) - 1]) + del it + # The removal has been committed + self.assertEqual(len(s), len(items)) + + def test_weak_destroy_and_mutate_while_iterating(self): + # Issue #7105: iterators shouldn't crash when a key is implicitly removed + items = [ustr(c) for c in string.ascii_letters] + s = WeakSet(items) + @contextlib.contextmanager + def testcontext(): + try: + it = iter(s) + next(it) + # Schedule an item for removal and recreate it + u = ustr(str(items.pop())) + gc.collect() # just in case + yield u + finally: + it = None # should commit all removals + + with testcontext() as u: + self.assertFalse(u in s) + with testcontext() as u: + self.assertRaises(KeyError, s.remove, u) + self.assertFalse(u in s) + with testcontext() as u: + s.add(u) + self.assertTrue(u in s) + t = s.copy() + with testcontext() as u: + s.update(t) + self.assertEqual(len(s), len(t)) + with testcontext() as u: + s.clear() + self.assertEqual(len(s), 0) + def test_main(verbose=None): test_support.run_unittest(TestWeakSet) |