summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
authorSerhiy Storchaka <storchaka@gmail.com>2016-11-06 16:47:03 (GMT)
committerSerhiy Storchaka <storchaka@gmail.com>2016-11-06 16:47:03 (GMT)
commit60e49aa7560ca70bc5de461abc68eb72d8739e17 (patch)
treececbf64f1c2c52048c04d337132af485aeffd87a /Lib
parentf66f03bd358c3c481292f2624b8c947f4f77c370 (diff)
parent24411f8a8daace4ebf8abd41091b681160b4fb89 (diff)
downloadcpython-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.py79
-rw-r--r--Lib/test/test_coroutines.py61
-rw-r--r--Lib/test/test_generators.py21
-rw-r--r--Lib/test/test_yield_from.py93
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):
"""