Update some tests to 3.13.7 (#6171)

* Update `test_call.py` from 3.13.7

* Update `test_yield_from.py` from 3.13.7

* Update more tests to 3.13.7

* More tests to 3.13.7

* Remove patch from passing test
This commit is contained in:
Shahar Naveh authored and GitHub committed 2025-09-21 19:33:41 +09:00
1 parent 24f4fbad82
commit 3c01be29c4
9 files changed
+1331 -270

No files matched your search

+681 -201
View File
File diff suppressed because it is too large. Load diff
+2 -3
View File
@@ -344,10 +344,9 @@ class OtherFileTests:
class COtherFileTests(OtherFileTests, unittest.TestCase):
open = io.open
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
def testSetBufferSize(self):
super().testSetBufferSize()
return super().testSetBufferSize()
class PyOtherFileTests(OtherFileTests, unittest.TestCase):
open = staticmethod(pyio.open)
+16 -2
View File
@@ -185,6 +185,21 @@ class TestCause(unittest.TestCase):
else:
self.fail("No exception raised")
@unittest.expectedFailure # TODO: RUSTPYTHON; TypeError: 'classmethod' object is not callable
def test_class_cause_nonexception_result(self):
class ConstructsNone(BaseException):
@classmethod
def __new__(*args, **kwargs):
return None
try:
raise IndexError from ConstructsNone
except TypeError as e:
self.assertIn("should have returned an instance of BaseException", str(e))
except IndexError:
self.fail("Wrong kind of exception raised")
else:
self.fail("No exception raised")
def test_instance_cause(self):
cause = KeyError()
try:
@@ -233,8 +248,7 @@ class TestTracebackType(unittest.TestCase):
def raiser(self):
raise ValueError
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_attrs(self):
try:
self.raiser()
+76 -4
View File
@@ -177,6 +177,57 @@ class ScopeTests(unittest.TestCase):
self.assertEqual(foo(a=42), 50)
self.assertEqual(foo(), 25)
def testCellIsArgAndEscapes(self):
# We need to be sure that a cell passed in as an arg still
# gets wrapped in a new cell if the arg escapes into an
# inner function (closure).
def external():
value = 42
def inner():
return value
cell, = inner.__closure__
return cell
cell_ext = external()
def spam(arg):
def eggs():
return arg
return eggs
eggs = spam(cell_ext)
cell_closure, = eggs.__closure__
cell_eggs = eggs()
self.assertIs(cell_eggs, cell_ext)
self.assertIsNot(cell_eggs, cell_closure)
def testCellIsLocalAndEscapes(self):
# We need to be sure that a cell bound to a local still
# gets wrapped in a new cell if the local escapes into an
# inner function (closure).
def external():
value = 42
def inner():
return value
cell, = inner.__closure__
return cell
cell_ext = external()
def spam(arg):
cell = arg
def eggs():
return cell
return eggs
eggs = spam(cell_ext)
cell_closure, = eggs.__closure__
cell_eggs = eggs()
self.assertIs(cell_eggs, cell_ext)
self.assertIsNot(cell_eggs, cell_closure)
def testRecursion(self):
def f(x):
@@ -641,10 +692,7 @@ class ScopeTests(unittest.TestCase):
self.assertEqual(c.dec(), 1)
self.assertEqual(c.dec(), 0)
# TODO: RUSTPYTHON, figure out how to communicate that `y = 9` should be
# stored as a global rather than a STORE_NAME, even when
# the `global y` is in a nested subscope
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON; figure out how to communicate that `y = 9` should be stored as a global rather than a STORE_NAME, even when the `global y` is in a nested subscope
def testGlobalInParallelNestedFunctions(self):
# A symbol table bug leaked the global statement from one
# function to other nested functions in the same block.
@@ -763,6 +811,30 @@ class ScopeTests(unittest.TestCase):
gc_collect() # For PyPy or other GCs.
self.assertIsNone(ref())
def test_multiple_nesting(self):
# Regression test for https://github.com/python/cpython/issues/121863
class MultiplyNested:
def f1(self):
__arg = 1
class D:
def g(self, __arg):
return __arg
return D().g(_MultiplyNested__arg=2)
def f2(self):
__arg = 1
class D:
def g(self, __arg):
return __arg
return D().g
inst = MultiplyNested()
with self.assertRaises(TypeError):
inst.f1()
closure = inst.f2()
with self.assertRaises(TypeError):
closure(_MultiplyNested__arg=2)
if __name__ == '__main__':
unittest.main()
+1 -2
View File
@@ -286,8 +286,7 @@ class SliceTest(unittest.TestCase):
self.assertIsNot(s.stop, c.stop)
self.assertIsNot(s.step, c.step)
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_cycle(self):
class myobj(): pass
o = myobj()
+5 -10
View File
@@ -105,8 +105,7 @@ class TestLiterals(unittest.TestCase):
self.assertRaises(SyntaxError, eval, r""" '\U000000' """)
self.assertRaises(SyntaxError, eval, r""" '\U0000000' """)
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_eval_str_invalid_escape(self):
for b in range(1, 128):
if b in b"""\n\r"'01234567NU\\abfnrtuvx""":
@@ -145,8 +144,7 @@ class TestLiterals(unittest.TestCase):
self.assertRegex(str(w[0].message), 'invalid escape sequence')
self.assertEqual(w[0].filename, '<string>')
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_eval_str_invalid_octal_escape(self):
for i in range(0o400, 0o1000):
with self.assertWarns(SyntaxWarning):
@@ -172,8 +170,7 @@ class TestLiterals(unittest.TestCase):
self.assertEqual(exc.lineno, 2)
self.assertEqual(exc.offset, 1)
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_invalid_escape_locations_with_offset(self):
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter('error', category=SyntaxWarning)
@@ -223,8 +220,7 @@ class TestLiterals(unittest.TestCase):
self.assertRaises(SyntaxError, eval, r""" b'\x' """)
self.assertRaises(SyntaxError, eval, r""" b'\x0' """)
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_eval_bytes_invalid_escape(self):
for b in range(1, 128):
if b in b"""\n\r"'01234567\\abfnrtvx""":
@@ -250,8 +246,7 @@ class TestLiterals(unittest.TestCase):
self.assertEqual(exc.filename, '<string>')
self.assertEqual(exc.lineno, 2)
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_eval_bytes_invalid_octal_escape(self):
for i in range(0o400, 0o1000):
with self.assertWarns(SyntaxWarning):
+6 -11
View File
@@ -146,7 +146,7 @@ class StrtodTests(unittest.TestCase):
digits *= 5
exponent -= 1
@unittest.skip("TODO: RUSTPYTHON, fails on debug mode, flaky in release mode")
@unittest.skip('TODO: RUSTPYTHON; fails on debug mode, flaky in release mode')
def test_halfway_cases(self):
# test halfway cases for the round-half-to-even rule
for i in range(100 * TEST_SIZE):
@@ -173,8 +173,7 @@ class StrtodTests(unittest.TestCase):
s = '{}e{}'.format(digits, exponent)
self.check_strtod(s)
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_boundaries(self):
# boundaries expressed as triples (n, e, u), where
# n*10**e is an approximation to the boundary value and
@@ -195,8 +194,7 @@ class StrtodTests(unittest.TestCase):
u *= 10
e -= 1
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_underflow_boundary(self):
# test values close to 2**-1075, the underflow boundary; similar
# to boundary_tests, except that the random error doesn't scale
@@ -208,8 +206,7 @@ class StrtodTests(unittest.TestCase):
s = '{}e{}'.format(digits, exponent)
self.check_strtod(s)
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_bigcomp(self):
for ndigs in 5, 10, 14, 15, 16, 17, 18, 19, 20, 40, 41, 50:
dig10 = 10**ndigs
@@ -219,8 +216,7 @@ class StrtodTests(unittest.TestCase):
s = '{}e{}'.format(digits, exponent)
self.check_strtod(s)
# TODO: RUSTPYTHON, Incorrectly rounded str->float conversion for -07e-321
@unittest.skip("TODO: RUSTPYTHON; flaky test")
@unittest.skip('TODO: RUSTPYTHON; flaky test')
def test_parsing(self):
# make '0' more likely to be chosen than other digits
digits = '000000123456789'
@@ -288,8 +284,7 @@ class StrtodTests(unittest.TestCase):
self.assertEqual(float(negative_exp(20000)), 1.0)
self.assertEqual(float(negative_exp(30000)), 1.0)
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_particular(self):
# inputs that produced crashes or incorrectly rounded results with
# previous versions of dtoa.c, for various reasons
+1 -28
View File
@@ -1,14 +1,11 @@
"""Do a minimal test of all the modules that aren't otherwise tested."""
import importlib
import platform
import sys
from test import support
from test.support import import_helper
from test.support import warnings_helper
import unittest
class TestUntestedModules(unittest.TestCase):
@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON")
def test_untested_modules_can_be_imported(self):
untested = ('encodings',)
with warnings_helper.check_warnings(quiet=True):
@@ -21,31 +18,6 @@ class TestUntestedModules(unittest.TestCase):
self.fail('{} has tests even though test_sundry claims '
'otherwise'.format(name))
import distutils.bcppcompiler
import distutils.ccompiler
import distutils.cygwinccompiler
import distutils.filelist
import distutils.text_file
import distutils.unixccompiler
import distutils.command.bdist_dumb
if sys.platform.startswith('win') and not platform.win32_is_iot():
import distutils.command.bdist_msi
import distutils.command.bdist
import distutils.command.bdist_rpm
import distutils.command.build_clib
import distutils.command.build_ext
import distutils.command.build
import distutils.command.clean
import distutils.command.config
import distutils.command.install_data
import distutils.command.install_egg_info
import distutils.command.install_headers
import distutils.command.install_lib
import distutils.command.register
import distutils.command.sdist
import distutils.command.upload
import html.entities
try:
@@ -54,5 +26,6 @@ class TestUntestedModules(unittest.TestCase):
if support.verbose:
print("skipping tty")
if __name__ == "__main__":
unittest.main()
+543 -9
View File
@@ -538,8 +538,7 @@ class TestPEP380Operation(unittest.TestCase):
"finishing g",
])
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_broken_getattr_handling(self):
"""
Test subiterator with a broken getattr implementation
@@ -787,8 +786,7 @@ class TestPEP380Operation(unittest.TestCase):
repr(value),
])
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_throwing_GeneratorExit_into_subgen_that_returns(self):
"""
Test throwing GeneratorExit into a subgenerator that
@@ -819,8 +817,7 @@ class TestPEP380Operation(unittest.TestCase):
"Enter f",
])
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_throwing_GeneratorExit_into_subgenerator_that_yields(self):
"""
Test throwing GeneratorExit into a subgenerator that
@@ -887,8 +884,7 @@ class TestPEP380Operation(unittest.TestCase):
yield from ()
self.assertRaises(StopIteration, next, g())
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_delegating_generators_claim_to_be_running(self):
# Check with basic iteration
def one():
@@ -904,6 +900,7 @@ class TestPEP380Operation(unittest.TestCase):
yield 2
g1 = one()
self.assertEqual(list(g1), [0, 1, 2, 3])
# Check with send
g1 = one()
res = [next(g1)]
@@ -913,6 +910,9 @@ class TestPEP380Operation(unittest.TestCase):
except StopIteration:
pass
self.assertEqual(res, [0, 1, 2, 3])
@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: Lists differ: [0, 1, 2] != [0, 1, 2, 3]
def test_delegating_generators_claim_to_be_running_with_throw(self):
# Check with throw
class MyErr(Exception):
pass
@@ -949,8 +949,10 @@ class TestPEP380Operation(unittest.TestCase):
except:
self.assertEqual(res, [0, 1, 2, 3])
raise
def test_delegating_generators_claim_to_be_running_with_close(self):
# Check with close
class MyIt(object):
class MyIt:
def __iter__(self):
return self
def __next__(self):
@@ -1057,6 +1059,538 @@ class TestPEP380Operation(unittest.TestCase):
g.send((1, 2, 3, 4))
self.assertEqual(v, (1, 2, 3, 4))
class TestInterestingEdgeCases(unittest.TestCase):
def assert_stop_iteration(self, iterator):
with self.assertRaises(StopIteration) as caught:
next(iterator)
self.assertIsNone(caught.exception.value)
self.assertIsNone(caught.exception.__context__)
def assert_generator_raised_stop_iteration(self):
return self.assertRaisesRegex(RuntimeError, r"^generator raised StopIteration$")
def assert_generator_ignored_generator_exit(self):
return self.assertRaisesRegex(RuntimeError, r"^generator ignored GeneratorExit$")
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_close_and_throw_work(self):
yielded_first = object()
yielded_second = object()
returned = object()
def inner():
yield yielded_first
yield yielded_second
return returned
def outer():
return (yield from inner())
with self.subTest("close"):
g = outer()
self.assertIs(next(g), yielded_first)
g.close()
self.assert_stop_iteration(g)
with self.subTest("throw GeneratorExit"):
g = outer()
self.assertIs(next(g), yielded_first)
thrown = GeneratorExit()
with self.assertRaises(GeneratorExit) as caught:
g.throw(thrown)
self.assertIs(caught.exception, thrown)
self.assertIsNone(caught.exception.__context__)
self.assert_stop_iteration(g)
with self.subTest("throw StopIteration"):
g = outer()
self.assertIs(next(g), yielded_first)
thrown = StopIteration()
# PEP 479:
with self.assert_generator_raised_stop_iteration() as caught:
g.throw(thrown)
self.assertIs(caught.exception.__context__, thrown)
self.assertIsNone(caught.exception.__context__.__context__)
self.assert_stop_iteration(g)
with self.subTest("throw BaseException"):
g = outer()
self.assertIs(next(g), yielded_first)
thrown = BaseException()
with self.assertRaises(BaseException) as caught:
g.throw(thrown)
self.assertIs(caught.exception, thrown)
self.assertIsNone(caught.exception.__context__)
self.assert_stop_iteration(g)
with self.subTest("throw Exception"):
g = outer()
self.assertIs(next(g), yielded_first)
thrown = Exception()
with self.assertRaises(Exception) as caught:
g.throw(thrown)
self.assertIs(caught.exception, thrown)
self.assertIsNone(caught.exception.__context__)
self.assert_stop_iteration(g)
@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: GeneratorExit() is not GeneratorExit()
def test_close_and_throw_raise_generator_exit(self):
yielded_first = object()
yielded_second = object()
returned = object()
def inner():
try:
yield yielded_first
yield yielded_second
return returned
finally:
raise raised
def outer():
return (yield from inner())
with self.subTest("close"):
g = outer()
self.assertIs(next(g), yielded_first)
raised = GeneratorExit()
# GeneratorExit is suppressed. This is consistent with PEP 342:
# https://peps.python.org/pep-0342/#new-generator-method-close
g.close()
self.assert_stop_iteration(g)
with self.subTest("throw GeneratorExit"):
g = outer()
self.assertIs(next(g), yielded_first)
raised = GeneratorExit()
thrown = GeneratorExit()
with self.assertRaises(GeneratorExit) as caught:
g.throw(thrown)
# The raised GeneratorExit is suppressed, but the thrown one
# propagates. This is consistent with PEP 380:
# https://peps.python.org/pep-0380/#proposal
self.assertIs(caught.exception, thrown)
self.assertIsNone(caught.exception.__context__)
self.assert_stop_iteration(g)
with self.subTest("throw StopIteration"):
g = outer()
self.assertIs(next(g), yielded_first)
raised = GeneratorExit()
thrown = StopIteration()
with self.assertRaises(GeneratorExit) as caught:
g.throw(thrown)
self.assertIs(caught.exception, raised)
self.assertIs(caught.exception.__context__, thrown)
self.assertIsNone(caught.exception.__context__.__context__)
self.assert_stop_iteration(g)
with self.subTest("throw BaseException"):
g = outer()
self.assertIs(next(g), yielded_first)
raised = GeneratorExit()
thrown = BaseException()
with self.assertRaises(GeneratorExit) as caught:
g.throw(thrown)
self.assertIs(caught.exception, raised)
self.assertIs(caught.exception.__context__, thrown)
self.assertIsNone(caught.exception.__context__.__context__)
self.assert_stop_iteration(g)
with self.subTest("throw Exception"):
g = outer()
self.assertIs(next(g), yielded_first)
raised = GeneratorExit()
thrown = Exception()
with self.assertRaises(GeneratorExit) as caught:
g.throw(thrown)
self.assertIs(caught.exception, raised)
self.assertIs(caught.exception.__context__, thrown)
self.assertIsNone(caught.exception.__context__.__context__)
self.assert_stop_iteration(g)
@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: RuntimeError not raised
def test_close_and_throw_raise_stop_iteration(self):
yielded_first = object()
yielded_second = object()
returned = object()
def inner():
try:
yield yielded_first
yield yielded_second
return returned
finally:
raise raised
def outer():
return (yield from inner())
with self.subTest("close"):
g = outer()
self.assertIs(next(g), yielded_first)
raised = StopIteration()
# PEP 479:
with self.assert_generator_raised_stop_iteration() as caught:
g.close()
self.assertIs(caught.exception.__context__, raised)
self.assertIsInstance(caught.exception.__context__.__context__, GeneratorExit)
self.assertIsNone(caught.exception.__context__.__context__.__context__)
self.assert_stop_iteration(g)
with self.subTest("throw GeneratorExit"):
g = outer()
self.assertIs(next(g), yielded_first)
raised = StopIteration()
thrown = GeneratorExit()
# PEP 479:
with self.assert_generator_raised_stop_iteration() as caught:
g.throw(thrown)
self.assertIs(caught.exception.__context__, raised)
# This isn't the same GeneratorExit as thrown! It's the one created
# by calling inner.close():
self.assertIsInstance(caught.exception.__context__.__context__, GeneratorExit)
self.assertIsNone(caught.exception.__context__.__context__.__context__)
self.assert_stop_iteration(g)
with self.subTest("throw StopIteration"):
g = outer()
self.assertIs(next(g), yielded_first)
raised = StopIteration()
thrown = StopIteration()
# PEP 479:
with self.assert_generator_raised_stop_iteration() as caught:
g.throw(thrown)
self.assertIs(caught.exception.__context__, raised)
self.assertIs(caught.exception.__context__.__context__, thrown)
self.assertIsNone(caught.exception.__context__.__context__.__context__)
self.assert_stop_iteration(g)
with self.subTest("throw BaseException"):
g = outer()
self.assertIs(next(g), yielded_first)
raised = StopIteration()
thrown = BaseException()
# PEP 479:
with self.assert_generator_raised_stop_iteration() as caught:
g.throw(thrown)
self.assertIs(caught.exception.__context__, raised)
self.assertIs(caught.exception.__context__.__context__, thrown)
self.assertIsNone(caught.exception.__context__.__context__.__context__)
self.assert_stop_iteration(g)
with self.subTest("throw Exception"):
g = outer()
self.assertIs(next(g), yielded_first)
raised = StopIteration()
thrown = Exception()
# PEP 479:
with self.assert_generator_raised_stop_iteration() as caught:
g.throw(thrown)
self.assertIs(caught.exception.__context__, raised)
self.assertIs(caught.exception.__context__.__context__, thrown)
self.assertIsNone(caught.exception.__context__.__context__.__context__)
self.assert_stop_iteration(g)
def test_close_and_throw_raise_base_exception(self):
yielded_first = object()
yielded_second = object()
returned = object()
def inner():
try:
yield yielded_first
yield yielded_second
return returned
finally:
raise raised
def outer():
return (yield from inner())
with self.subTest("close"):
g = outer()
self.assertIs(next(g), yielded_first)
raised = BaseException()
with self.assertRaises(BaseException) as caught:
g.close()
self.assertIs(caught.exception, raised)
self.assertIsInstance(caught.exception.__context__, GeneratorExit)
self.assertIsNone(caught.exception.__context__.__context__)
self.assert_stop_iteration(g)
with self.subTest("throw GeneratorExit"):
g = outer()
self.assertIs(next(g), yielded_first)
raised = BaseException()
thrown = GeneratorExit()
with self.assertRaises(BaseException) as caught:
g.throw(thrown)
self.assertIs(caught.exception, raised)
# This isn't the same GeneratorExit as thrown! It's the one created
# by calling inner.close():
self.assertIsInstance(caught.exception.__context__, GeneratorExit)
self.assertIsNone(caught.exception.__context__.__context__)
self.assert_stop_iteration(g)
with self.subTest("throw StopIteration"):
g = outer()
self.assertIs(next(g), yielded_first)
raised = BaseException()
thrown = StopIteration()
with self.assertRaises(BaseException) as caught:
g.throw(thrown)
self.assertIs(caught.exception, raised)
self.assertIs(caught.exception.__context__, thrown)
self.assertIsNone(caught.exception.__context__.__context__)
self.assert_stop_iteration(g)
with self.subTest("throw BaseException"):
g = outer()
self.assertIs(next(g), yielded_first)
raised = BaseException()
thrown = BaseException()
with self.assertRaises(BaseException) as caught:
g.throw(thrown)
self.assertIs(caught.exception, raised)
self.assertIs(caught.exception.__context__, thrown)
self.assertIsNone(caught.exception.__context__.__context__)
self.assert_stop_iteration(g)
with self.subTest("throw Exception"):
g = outer()
self.assertIs(next(g), yielded_first)
raised = BaseException()
thrown = Exception()
with self.assertRaises(BaseException) as caught:
g.throw(thrown)
self.assertIs(caught.exception, raised)
self.assertIs(caught.exception.__context__, thrown)
self.assertIsNone(caught.exception.__context__.__context__)
self.assert_stop_iteration(g)
def test_close_and_throw_raise_exception(self):
yielded_first = object()
yielded_second = object()
returned = object()
def inner():
try:
yield yielded_first
yield yielded_second
return returned
finally:
raise raised
def outer():
return (yield from inner())
with self.subTest("close"):
g = outer()
self.assertIs(next(g), yielded_first)
raised = Exception()
with self.assertRaises(Exception) as caught:
g.close()
self.assertIs(caught.exception, raised)
self.assertIsInstance(caught.exception.__context__, GeneratorExit)
self.assertIsNone(caught.exception.__context__.__context__)
self.assert_stop_iteration(g)
with self.subTest("throw GeneratorExit"):
g = outer()
self.assertIs(next(g), yielded_first)
raised = Exception()
thrown = GeneratorExit()
with self.assertRaises(Exception) as caught:
g.throw(thrown)
self.assertIs(caught.exception, raised)
# This isn't the same GeneratorExit as thrown! It's the one created
# by calling inner.close():
self.assertIsInstance(caught.exception.__context__, GeneratorExit)
self.assertIsNone(caught.exception.__context__.__context__)
self.assert_stop_iteration(g)
with self.subTest("throw StopIteration"):
g = outer()
self.assertIs(next(g), yielded_first)
raised = Exception()
thrown = StopIteration()
with self.assertRaises(Exception) as caught:
g.throw(thrown)
self.assertIs(caught.exception, raised)
self.assertIs(caught.exception.__context__, thrown)
self.assertIsNone(caught.exception.__context__.__context__)
self.assert_stop_iteration(g)
with self.subTest("throw BaseException"):
g = outer()
self.assertIs(next(g), yielded_first)
raised = Exception()
thrown = BaseException()
with self.assertRaises(Exception) as caught:
g.throw(thrown)
self.assertIs(caught.exception, raised)
self.assertIs(caught.exception.__context__, thrown)
self.assertIsNone(caught.exception.__context__.__context__)
self.assert_stop_iteration(g)
with self.subTest("throw Exception"):
g = outer()
self.assertIs(next(g), yielded_first)
raised = Exception()
thrown = Exception()
with self.assertRaises(Exception) as caught:
g.throw(thrown)
self.assertIs(caught.exception, raised)
self.assertIs(caught.exception.__context__, thrown)
self.assertIsNone(caught.exception.__context__.__context__)
self.assert_stop_iteration(g)
@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: None is not StopIteration()
def test_close_and_throw_yield(self):
yielded_first = object()
yielded_second = object()
returned = object()
def inner():
try:
yield yielded_first
finally:
yield yielded_second
return returned
def outer():
return (yield from inner())
with self.subTest("close"):
g = outer()
self.assertIs(next(g), yielded_first)
# No chaining happens. This is consistent with PEP 342:
# https://peps.python.org/pep-0342/#new-generator-method-close
with self.assert_generator_ignored_generator_exit() as caught:
g.close()
self.assertIsNone(caught.exception.__context__)
self.assert_stop_iteration(g)
with self.subTest("throw GeneratorExit"):
g = outer()
self.assertIs(next(g), yielded_first)
thrown = GeneratorExit()
# No chaining happens. This is consistent with PEP 342:
# https://peps.python.org/pep-0342/#new-generator-method-close
with self.assert_generator_ignored_generator_exit() as caught:
g.throw(thrown)
self.assertIsNone(caught.exception.__context__)
self.assert_stop_iteration(g)
with self.subTest("throw StopIteration"):
g = outer()
self.assertIs(next(g), yielded_first)
thrown = StopIteration()
self.assertEqual(g.throw(thrown), yielded_second)
# PEP 479:
with self.assert_generator_raised_stop_iteration() as caught:
next(g)
self.assertIs(caught.exception.__context__, thrown)
self.assertIsNone(caught.exception.__context__.__context__)
self.assert_stop_iteration(g)
with self.subTest("throw BaseException"):
g = outer()
self.assertIs(next(g), yielded_first)
thrown = BaseException()
self.assertEqual(g.throw(thrown), yielded_second)
with self.assertRaises(BaseException) as caught:
next(g)
self.assertIs(caught.exception, thrown)
self.assertIsNone(caught.exception.__context__)
self.assert_stop_iteration(g)
with self.subTest("throw Exception"):
g = outer()
self.assertIs(next(g), yielded_first)
thrown = Exception()
self.assertEqual(g.throw(thrown), yielded_second)
with self.assertRaises(Exception) as caught:
next(g)
self.assertIs(caught.exception, thrown)
self.assertIsNone(caught.exception.__context__)
self.assert_stop_iteration(g)
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_close_and_throw_return(self):
yielded_first = object()
yielded_second = object()
returned = object()
def inner():
try:
yield yielded_first
yield yielded_second
finally:
return returned
def outer():
return (yield from inner())
with self.subTest("close"):
g = outer()
self.assertIs(next(g), yielded_first)
# StopIteration is suppressed. This is consistent with PEP 342:
# https://peps.python.org/pep-0342/#new-generator-method-close
g.close()
self.assert_stop_iteration(g)
with self.subTest("throw GeneratorExit"):
g = outer()
self.assertIs(next(g), yielded_first)
thrown = GeneratorExit()
# StopIteration is suppressed. This is consistent with PEP 342:
# https://peps.python.org/pep-0342/#new-generator-method-close
with self.assertRaises(GeneratorExit) as caught:
g.throw(thrown)
self.assertIs(caught.exception, thrown)
self.assertIsNone(caught.exception.__context__)
self.assert_stop_iteration(g)
with self.subTest("throw StopIteration"):
g = outer()
self.assertIs(next(g), yielded_first)
thrown = StopIteration()
with self.assertRaises(StopIteration) as caught:
g.throw(thrown)
self.assertIs(caught.exception.value, returned)
self.assertIsNone(caught.exception.__context__)
self.assert_stop_iteration(g)
with self.subTest("throw BaseException"):
g = outer()
self.assertIs(next(g), yielded_first)
thrown = BaseException()
with self.assertRaises(StopIteration) as caught:
g.throw(thrown)
self.assertIs(caught.exception.value, returned)
self.assertIsNone(caught.exception.__context__)
self.assert_stop_iteration(g)
with self.subTest("throw Exception"):
g = outer()
self.assertIs(next(g), yielded_first)
thrown = Exception()
with self.assertRaises(StopIteration) as caught:
g.throw(thrown)
self.assertIs(caught.exception.value, returned)
self.assertIsNone(caught.exception.__context__)
self.assert_stop_iteration(g)
if __name__ == '__main__':
unittest.main()