diff options
author | Brandt Bucher <brandtbucher@gmail.com> | 2020-12-07 20:07:48 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-12-07 20:07:48 (GMT) |
commit | 60463e8e4f79e5b5e96dc43fb83ded373b489e33 (patch) | |
tree | a396c7ee5d9b3db595fac4980fc0700e4fe8a2e9 /Lib/test/test_itertools.py | |
parent | e9a6dcdefabb6c19074566f4ee0e02daaf57be18 (diff) | |
download | cpython-60463e8e4f79e5b5e96dc43fb83ded373b489e33.zip cpython-60463e8e4f79e5b5e96dc43fb83ded373b489e33.tar.gz cpython-60463e8e4f79e5b5e96dc43fb83ded373b489e33.tar.bz2 |
bpo-42536: GC track recycled tuples (GH-23623) (GH-23651)
Several built-in and standard library types now ensure that their internal result tuples are always tracked by the garbage collector:
- collections.OrderedDict.items
- dict.items
- enumerate
- functools.reduce
- itertools.combinations
- itertools.combinations_with_replacement
- itertools.permutations
- itertools.product
- itertools.zip_longest
- zip
Previously, they could have become untracked by a prior garbage collection.
(cherry picked from commit 226a012d1cd61f42ecd3056c554922f359a1a35d)
Diffstat (limited to 'Lib/test/test_itertools.py')
-rw-r--r-- | Lib/test/test_itertools.py | 47 |
1 files changed, 47 insertions, 0 deletions
diff --git a/Lib/test/test_itertools.py b/Lib/test/test_itertools.py index 702cf08..7101264 100644 --- a/Lib/test/test_itertools.py +++ b/Lib/test/test_itertools.py @@ -12,6 +12,8 @@ from functools import reduce import sys import struct import threading +import gc + maxsize = support.MAX_Py_ssize_t minsize = -maxsize-1 @@ -1554,6 +1556,51 @@ class TestBasicOps(unittest.TestCase): self.assertRaises(StopIteration, next, f(lambda x:x, [])) self.assertRaises(StopIteration, next, f(lambda x:x, StopNow())) + @support.cpython_only + def test_combinations_result_gc(self): + # bpo-42536: combinations's tuple-reuse speed trick breaks the GC's + # assumptions about what can be untracked. Make sure we re-track result + # tuples whenever we reuse them. + it = combinations([None, []], 1) + next(it) + gc.collect() + # That GC collection probably untracked the recycled internal result + # tuple, which has the value (None,). Make sure it's re-tracked when + # it's mutated and returned from __next__: + self.assertTrue(gc.is_tracked(next(it))) + + @support.cpython_only + def test_combinations_with_replacement_result_gc(self): + # Ditto for combinations_with_replacement. + it = combinations_with_replacement([None, []], 1) + next(it) + gc.collect() + self.assertTrue(gc.is_tracked(next(it))) + + @support.cpython_only + def test_permutations_result_gc(self): + # Ditto for permutations. + it = permutations([None, []], 1) + next(it) + gc.collect() + self.assertTrue(gc.is_tracked(next(it))) + + @support.cpython_only + def test_product_result_gc(self): + # Ditto for product. + it = product([None, []]) + next(it) + gc.collect() + self.assertTrue(gc.is_tracked(next(it))) + + @support.cpython_only + def test_zip_longest_result_gc(self): + # Ditto for zip_longest. + it = zip_longest([[]]) + gc.collect() + self.assertTrue(gc.is_tracked(next(it))) + + class TestExamples(unittest.TestCase): def test_accumulate(self): |