summaryrefslogtreecommitdiffstats
path: root/Lib/test/test_itertools.py
diff options
context:
space:
mode:
authorBrandt Bucher <brandtbucher@gmail.com>2020-12-07 20:07:48 (GMT)
committerGitHub <noreply@github.com>2020-12-07 20:07:48 (GMT)
commit60463e8e4f79e5b5e96dc43fb83ded373b489e33 (patch)
treea396c7ee5d9b3db595fac4980fc0700e4fe8a2e9 /Lib/test/test_itertools.py
parente9a6dcdefabb6c19074566f4ee0e02daaf57be18 (diff)
downloadcpython-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.py47
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):