diff options
author | Serhiy Storchaka <storchaka@gmail.com> | 2016-11-06 16:47:03 (GMT) |
---|---|---|
committer | Serhiy Storchaka <storchaka@gmail.com> | 2016-11-06 16:47:03 (GMT) |
commit | 60e49aa7560ca70bc5de461abc68eb72d8739e17 (patch) | |
tree | cecbf64f1c2c52048c04d337132af485aeffd87a /Lib | |
parent | f66f03bd358c3c481292f2624b8c947f4f77c370 (diff) | |
parent | 24411f8a8daace4ebf8abd41091b681160b4fb89 (diff) | |
download | cpython-60e49aa7560ca70bc5de461abc68eb72d8739e17.zip cpython-60e49aa7560ca70bc5de461abc68eb72d8739e17.tar.gz cpython-60e49aa7560ca70bc5de461abc68eb72d8739e17.tar.bz2 |
Issue #23996: Added _PyGen_SetStopIterationValue for safe raising
StopIteration with value. More safely handle non-normalized exceptions
in -_PyGen_FetchStopIterationValue.
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/test/test_asyncgen.py | 79 | ||||
-rw-r--r-- | Lib/test/test_coroutines.py | 61 | ||||
-rw-r--r-- | Lib/test/test_generators.py | 21 | ||||
-rw-r--r-- | Lib/test/test_yield_from.py | 93 |
4 files changed, 225 insertions, 29 deletions
diff --git a/Lib/test/test_asyncgen.py b/Lib/test/test_asyncgen.py index c24fbea..68d2029 100644 --- a/Lib/test/test_asyncgen.py +++ b/Lib/test/test_asyncgen.py @@ -450,6 +450,48 @@ class AsyncGenAsyncioTest(unittest.TestCase): self.loop.run_until_complete(run()) + def test_async_gen_asyncio_anext_tuple(self): + async def foo(): + try: + yield (1,) + except ZeroDivisionError: + yield (2,) + + async def run(): + it = foo().__aiter__() + + self.assertEqual(await it.__anext__(), (1,)) + with self.assertRaises(StopIteration) as cm: + it.__anext__().throw(ZeroDivisionError) + self.assertEqual(cm.exception.args[0], (2,)) + with self.assertRaises(StopAsyncIteration): + await it.__anext__() + + self.loop.run_until_complete(run()) + + def test_async_gen_asyncio_anext_stopiteration(self): + async def foo(): + try: + yield StopIteration(1) + except ZeroDivisionError: + yield StopIteration(3) + + async def run(): + it = foo().__aiter__() + + v = await it.__anext__() + self.assertIsInstance(v, StopIteration) + self.assertEqual(v.value, 1) + with self.assertRaises(StopIteration) as cm: + it.__anext__().throw(ZeroDivisionError) + v = cm.exception.args[0] + self.assertIsInstance(v, StopIteration) + self.assertEqual(v.value, 3) + with self.assertRaises(StopAsyncIteration): + await it.__anext__() + + self.loop.run_until_complete(run()) + def test_async_gen_asyncio_aclose_06(self): async def foo(): try: @@ -759,6 +801,43 @@ class AsyncGenAsyncioTest(unittest.TestCase): self.loop.run_until_complete(run()) self.assertEqual(DONE, 1) + def test_async_gen_asyncio_athrow_tuple(self): + async def gen(): + try: + yield 1 + except ZeroDivisionError: + yield (2,) + + async def run(): + g = gen() + v = await g.asend(None) + self.assertEqual(v, 1) + v = await g.athrow(ZeroDivisionError) + self.assertEqual(v, (2,)) + with self.assertRaises(StopAsyncIteration): + await g.asend(None) + + self.loop.run_until_complete(run()) + + def test_async_gen_asyncio_athrow_stopiteration(self): + async def gen(): + try: + yield 1 + except ZeroDivisionError: + yield StopIteration(2) + + async def run(): + g = gen() + v = await g.asend(None) + self.assertEqual(v, 1) + v = await g.athrow(ZeroDivisionError) + self.assertIsInstance(v, StopIteration) + self.assertEqual(v.value, 2) + with self.assertRaises(StopAsyncIteration): + await g.asend(None) + + self.loop.run_until_complete(run()) + def test_async_gen_asyncio_shutdown_01(self): finalized = 0 diff --git a/Lib/test/test_coroutines.py b/Lib/test/test_coroutines.py index f2839a7..50e439a 100644 --- a/Lib/test/test_coroutines.py +++ b/Lib/test/test_coroutines.py @@ -838,6 +838,21 @@ class CoroutineTest(unittest.TestCase): coro.close() self.assertEqual(CHK, 1) + def test_coro_wrapper_send_tuple(self): + async def foo(): + return (10,) + + result = run_async__await__(foo()) + self.assertEqual(result, ([], (10,))) + + def test_coro_wrapper_send_stop_iterator(self): + async def foo(): + return StopIteration(10) + + result = run_async__await__(foo()) + self.assertIsInstance(result[1], StopIteration) + self.assertEqual(result[1].value, 10) + def test_cr_await(self): @types.coroutine def a(): @@ -1665,6 +1680,52 @@ class CoroutineTest(unittest.TestCase): warnings.simplefilter("error") run_async(foo()) + def test_for_tuple(self): + class Done(Exception): pass + + class AIter(tuple): + i = 0 + def __aiter__(self): + return self + async def __anext__(self): + if self.i >= len(self): + raise StopAsyncIteration + self.i += 1 + return self[self.i - 1] + + result = [] + async def foo(): + async for i in AIter([42]): + result.append(i) + raise Done + + with self.assertRaises(Done): + foo().send(None) + self.assertEqual(result, [42]) + + def test_for_stop_iteration(self): + class Done(Exception): pass + + class AIter(StopIteration): + i = 0 + def __aiter__(self): + return self + async def __anext__(self): + if self.i: + raise StopAsyncIteration + self.i += 1 + return self.value + + result = [] + async def foo(): + async for i in AIter(42): + result.append(i) + raise Done + + with self.assertRaises(Done): + foo().send(None) + self.assertEqual(result, [42]) + def test_comp_1(self): async def f(i): return i diff --git a/Lib/test/test_generators.py b/Lib/test/test_generators.py index f4b33af..f81c82f 100644 --- a/Lib/test/test_generators.py +++ b/Lib/test/test_generators.py @@ -277,6 +277,27 @@ class ExceptionTest(unittest.TestCase): # hence no warning. next(g) + def test_return_tuple(self): + def g(): + return (yield 1) + + gen = g() + self.assertEqual(next(gen), 1) + with self.assertRaises(StopIteration) as cm: + gen.send((2,)) + self.assertEqual(cm.exception.value, (2,)) + + def test_return_stopiteration(self): + def g(): + return (yield 1) + + gen = g() + self.assertEqual(next(gen), 1) + with self.assertRaises(StopIteration) as cm: + gen.send(StopIteration(2)) + self.assertIsInstance(cm.exception.value, StopIteration) + self.assertEqual(cm.exception.value.value, 2) + class YieldFromTests(unittest.TestCase): def test_generator_gi_yieldfrom(self): diff --git a/Lib/test/test_yield_from.py b/Lib/test/test_yield_from.py index 23ffbed..7e9711e 100644 --- a/Lib/test/test_yield_from.py +++ b/Lib/test/test_yield_from.py @@ -384,9 +384,10 @@ class TestPEP380Operation(unittest.TestCase): trace.append("Starting g1") yield "g1 ham" ret = yield from g2() - trace.append("g2 returned %s" % (ret,)) - ret = yield from g2(42) - trace.append("g2 returned %s" % (ret,)) + trace.append("g2 returned %r" % (ret,)) + for v in 1, (2,), StopIteration(3): + ret = yield from g2(v) + trace.append("g2 returned %r" % (ret,)) yield "g1 eggs" trace.append("Finishing g1") def g2(v = None): @@ -410,7 +411,17 @@ class TestPEP380Operation(unittest.TestCase): "Yielded g2 spam", "Yielded g2 more spam", "Finishing g2", - "g2 returned 42", + "g2 returned 1", + "Starting g2", + "Yielded g2 spam", + "Yielded g2 more spam", + "Finishing g2", + "g2 returned (2,)", + "Starting g2", + "Yielded g2 spam", + "Yielded g2 more spam", + "Finishing g2", + "g2 returned StopIteration(3,)", "Yielded g1 eggs", "Finishing g1", ]) @@ -670,14 +681,16 @@ class TestPEP380Operation(unittest.TestCase): next(gi) trace.append("f SHOULD NOT BE HERE") except StopIteration as e: - trace.append("f caught %s" % (repr(e),)) + trace.append("f caught %r" % (e,)) def g(r): trace.append("g starting") yield - trace.append("g returning %s" % (r,)) + trace.append("g returning %r" % (r,)) return r f(None) - f(42) + f(1) + f((2,)) + f(StopIteration(3)) self.assertEqual(trace,[ "g starting", "f resuming g", @@ -685,8 +698,16 @@ class TestPEP380Operation(unittest.TestCase): "f caught StopIteration()", "g starting", "f resuming g", - "g returning 42", - "f caught StopIteration(42,)", + "g returning 1", + "f caught StopIteration(1,)", + "g starting", + "f resuming g", + "g returning (2,)", + "f caught StopIteration((2,),)", + "g starting", + "f resuming g", + "g returning StopIteration(3,)", + "f caught StopIteration(StopIteration(3,),)", ]) def test_send_and_return_with_value(self): @@ -706,22 +727,34 @@ class TestPEP380Operation(unittest.TestCase): def g(r): trace.append("g starting") x = yield - trace.append("g received %s" % (x,)) - trace.append("g returning %s" % (r,)) + trace.append("g received %r" % (x,)) + trace.append("g returning %r" % (r,)) return r f(None) - f(42) - self.assertEqual(trace,[ + f(1) + f((2,)) + f(StopIteration(3)) + self.assertEqual(trace, [ "g starting", "f sending spam to g", - "g received spam", + "g received 'spam'", "g returning None", "f caught StopIteration()", "g starting", "f sending spam to g", - "g received spam", - "g returning 42", - "f caught StopIteration(42,)", + "g received 'spam'", + "g returning 1", + 'f caught StopIteration(1,)', + 'g starting', + 'f sending spam to g', + "g received 'spam'", + 'g returning (2,)', + 'f caught StopIteration((2,),)', + 'g starting', + 'f sending spam to g', + "g received 'spam'", + 'g returning StopIteration(3,)', + 'f caught StopIteration(StopIteration(3,),)' ]) def test_catching_exception_from_subgen_and_returning(self): @@ -729,27 +762,29 @@ class TestPEP380Operation(unittest.TestCase): Test catching an exception thrown into a subgenerator and returning a value """ - trace = [] def inner(): try: yield 1 except ValueError: trace.append("inner caught ValueError") - return 2 + return value def outer(): v = yield from inner() - trace.append("inner returned %r to outer" % v) + trace.append("inner returned %r to outer" % (v,)) yield v - g = outer() - trace.append(next(g)) - trace.append(g.throw(ValueError)) - self.assertEqual(trace,[ - 1, - "inner caught ValueError", - "inner returned 2 to outer", - 2, - ]) + + for value in 2, (2,), StopIteration(2): + trace = [] + g = outer() + trace.append(next(g)) + trace.append(repr(g.throw(ValueError))) + self.assertEqual(trace, [ + 1, + "inner caught ValueError", + "inner returned %r to outer" % (value,), + repr(value), + ]) def test_throwing_GeneratorExit_into_subgen_that_returns(self): """ |