Update test_generators from v3.14.2

This commit is contained in:
CPython Developers
2026-02-11 16:47:11 +09:00
committed by Jeong, YunWon
parent e616f250af
commit cafde31502

View File

@@ -6,6 +6,7 @@ import doctest
import unittest
import weakref
import inspect
import textwrap
import types
from test import support
@@ -48,7 +49,6 @@ class SignalAndYieldFromTest(unittest.TestCase):
class FinalizationTest(unittest.TestCase):
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_frame_resurrect(self):
# A generator frame can be resurrected by a generator's finalization.
def gen():
@@ -68,7 +68,7 @@ class FinalizationTest(unittest.TestCase):
del frame
support.gc_collect()
@unittest.expectedFailure # TODO: RUSTPYTHON
@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: False is not true
def test_refcycle(self):
# A generator caught in a refcycle gets finalized anyway.
old_garbage = gc.garbage[:]
@@ -84,7 +84,7 @@ class FinalizationTest(unittest.TestCase):
g = gen()
next(g)
g.send(g)
self.assertGreater(sys.getrefcount(g), 2)
self.assertGreaterEqual(sys.getrefcount(g), 2)
self.assertFalse(finalized)
del g
support.gc_collect()
@@ -114,6 +114,28 @@ class FinalizationTest(unittest.TestCase):
gen.send(2)
self.assertEqual(cm.exception.value, 2)
@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: 0 != 1
def test_generator_resurrect(self):
# Test that a resurrected generator still has a valid gi_code
resurrected = []
# Resurrect a generator in a finalizer
exec(textwrap.dedent("""
def gen():
try:
yield
except:
resurrected.append(g)
g = gen()
next(g)
"""), {"resurrected": resurrected})
support.gc_collect()
self.assertEqual(len(resurrected), 1)
self.assertIsInstance(resurrected[0].gi_code, types.CodeType)
class GeneratorTest(unittest.TestCase):
@@ -248,6 +270,28 @@ class GeneratorTest(unittest.TestCase):
#This should not raise
loop()
def test_genexpr_only_calls_dunder_iter_once(self):
class Iterator:
def __init__(self):
self.val = 0
def __next__(self):
if self.val == 2:
raise StopIteration
self.val += 1
return self.val
# No __iter__ method
class C:
def __iter__(self):
return Iterator()
self.assertEqual([1, 2], list(i for i in C()))
class ModifyUnderlyingIterableTest(unittest.TestCase):
iterables = [
@@ -276,23 +320,27 @@ class ModifyUnderlyingIterableTest(unittest.TestCase):
yield x
return gen(range(10))
def process_tests(self, get_generator):
def process_tests(self, get_generator, is_expr):
err_iterator = "'.*' object is not an iterator"
err_iterable = "'.*' object is not iterable"
for obj in self.iterables:
g_obj = get_generator(obj)
with self.subTest(g_obj=g_obj, obj=obj):
self.assertListEqual(list(g_obj), list(obj))
if is_expr:
self.assertRaisesRegex(TypeError, err_iterator, list, g_obj)
else:
self.assertListEqual(list(g_obj), list(obj))
g_iter = get_generator(iter(obj))
with self.subTest(g_iter=g_iter, obj=obj):
self.assertListEqual(list(g_iter), list(obj))
err_regex = "'.*' object is not iterable"
for obj in self.non_iterables:
g_obj = get_generator(obj)
with self.subTest(g_obj=g_obj):
self.assertRaisesRegex(TypeError, err_regex, list, g_obj)
err = err_iterator if is_expr else err_iterable
self.assertRaisesRegex(TypeError, err, list, g_obj)
@unittest.expectedFailure # AssertionError: TypeError not raised by list
def test_modify_f_locals(self):
def modify_f_locals(g, local, obj):
g.gi_frame.f_locals[local] = obj
@@ -304,10 +352,9 @@ class ModifyUnderlyingIterableTest(unittest.TestCase):
def get_generator_genfunc(obj):
return modify_f_locals(self.genfunc(), 'it', obj)
self.process_tests(get_generator_genexpr)
self.process_tests(get_generator_genfunc)
self.process_tests(get_generator_genexpr, True)
self.process_tests(get_generator_genfunc, False)
@unittest.expectedFailure # AssertionError: "'.*' object is not iterable" does not match "'complex' object is not an iterator"
def test_new_gen_from_gi_code(self):
def new_gen_from_gi_code(g, obj):
generator_func = types.FunctionType(g.gi_code, {})
@@ -319,8 +366,8 @@ class ModifyUnderlyingIterableTest(unittest.TestCase):
def get_generator_genfunc(obj):
return new_gen_from_gi_code(self.genfunc(), obj)
self.process_tests(get_generator_genexpr)
self.process_tests(get_generator_genfunc)
self.process_tests(get_generator_genexpr, True)
self.process_tests(get_generator_genfunc, False)
class ExceptionTest(unittest.TestCase):
@@ -451,7 +498,6 @@ class ExceptionTest(unittest.TestCase):
self.assertEqual(next(g), "done")
self.assertIsNone(sys.exception())
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_except_throw_bad_exception(self):
class E(Exception):
def __new__(cls, *args, **kwargs):
@@ -543,7 +589,6 @@ class GeneratorCloseTest(unittest.TestCase):
gen.send(None)
self.assertIsNone(gen.close())
@unittest.expectedFailure # AssertionError: None != 0
def test_close_return_value(self):
def f():
try:
@@ -590,7 +635,6 @@ class GeneratorCloseTest(unittest.TestCase):
next(gen)
self.assertIsNone(gen.close())
@unittest.expectedFailure # AssertionError: None != 0
def test_close_closed(self):
def f():
try:
@@ -616,7 +660,6 @@ class GeneratorCloseTest(unittest.TestCase):
with self.assertRaises(RuntimeError):
gen.close()
@unittest.expectedFailure # AssertionError: <test.test_generators.GeneratorCloseTest.test_close_releases_frame_locals.<locals>.Foo object at 0xb400007e3c212160> is not None
def test_close_releases_frame_locals(self):
# See gh-118272
@@ -679,7 +722,6 @@ class GeneratorDeallocTest(unittest.TestCase):
self.assertIn('a', frame_locals)
self.assertEqual(frame_locals['a'], 42)
@unittest.expectedFailure # AssertionError: 'a' not found in {'frame_locals1': None}
def test_frame_locals_outlive_generator(self):
frame_locals1 = None
@@ -828,7 +870,8 @@ class GeneratorStackTraceTest(unittest.TestCase):
while frame:
name = frame.f_code.co_name
# Stop checking frames when we get to our test helper.
if name.startswith('check_') or name.startswith('call_'):
if (name.startswith('check_') or name.startswith('call_')
or name.startswith('test')):
break
names.append(name)
@@ -869,9 +912,27 @@ class GeneratorStackTraceTest(unittest.TestCase):
self.check_yield_from_example(call_throw)
def test_throw_with_yield_from_custom_generator(self):
class CustomGen:
def __init__(self, test):
self.test = test
def throw(self, *args):
self.test.check_stack_names(sys._getframe(), ['throw', 'g'])
def __iter__(self):
return self
def __next__(self):
return 42
def g(target):
yield from target
gen = g(CustomGen(self))
gen.send(None)
gen.throw(RuntimeError)
class YieldFromTests(unittest.TestCase):
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_generator_gi_yieldfrom(self):
def a():
self.assertEqual(inspect.getgeneratorstate(gen_b), inspect.GEN_RUNNING)
@@ -1077,7 +1138,7 @@ Specification: Generators and Exception Propagation
File "<stdin>", line 1, in ?
File "<stdin>", line 2, in g
File "<stdin>", line 2, in f
ZeroDivisionError: integer division or modulo by zero
ZeroDivisionError: division by zero
>>> next(k) # and the generator cannot be resumed
Traceback (most recent call last):
File "<stdin>", line 1, in ?
@@ -2632,14 +2693,18 @@ Our ill-behaved code should be invoked during GC:
>>> with support.catch_unraisable_exception() as cm:
... g = f()
... next(g)
... gen_repr = repr(g)
... del g
...
... cm.unraisable.err_msg == (f'Exception ignored while closing '
... f'generator {gen_repr}')
... cm.unraisable.exc_type == RuntimeError
... "generator ignored GeneratorExit" in str(cm.unraisable.exc_value)
... cm.unraisable.exc_traceback is not None
True
True
True
True
And errors thrown during closing should propagate:
@@ -2744,10 +2809,12 @@ to test.
... invoke("del failed")
...
>>> with support.catch_unraisable_exception() as cm:
... l = Leaker()
... del l
... leaker = Leaker()
... del_repr = repr(type(leaker).__del__)
... del leaker
...
... cm.unraisable.object == Leaker.__del__
... cm.unraisable.err_msg == (f'Exception ignored while '
... f'calling deallocator {del_repr}')
... cm.unraisable.exc_type == RuntimeError
... str(cm.unraisable.exc_value) == "del failed"
... cm.unraisable.exc_traceback is not None
@@ -2774,7 +2841,7 @@ __test__ = {"tut": tutorial_tests,
}
def load_tests(loader, tests, pattern):
# tests.addTest(doctest.DocTestSuite()) # TODO: RUSTPYTHON
tests.addTest(doctest.DocTestSuite())
return tests