[Python-checkins] cpython (merge 3.6 -> default): Merge 3.6 (issue #28721)
yury.selivanov
python-checkins at python.org
Wed Nov 16 18:16:47 EST 2016
https://hg.python.org/cpython/rev/22cd78026ad1
changeset: 105162:22cd78026ad1
parent: 105160:44874b20e612
parent: 105161:0f12a1d3a737
user: Yury Selivanov <yury at magic.io>
date: Wed Nov 16 18:16:32 2016 -0500
summary:
Merge 3.6 (issue #28721)
files:
Lib/test/test_asyncgen.py | 140 ++++++++++++++++++++++++++
Misc/NEWS | 3 +
Objects/genobject.c | 14 ++-
3 files changed, 154 insertions(+), 3 deletions(-)
diff --git a/Lib/test/test_asyncgen.py b/Lib/test/test_asyncgen.py
--- a/Lib/test/test_asyncgen.py
+++ b/Lib/test/test_asyncgen.py
@@ -450,6 +450,41 @@
self.loop.run_until_complete(run())
+ def test_async_gen_asyncio_anext_06(self):
+ DONE = 0
+
+ # test synchronous generators
+ def foo():
+ try:
+ yield
+ except:
+ pass
+ g = foo()
+ g.send(None)
+ with self.assertRaises(StopIteration):
+ g.send(None)
+
+ # now with asynchronous generators
+
+ async def gen():
+ nonlocal DONE
+ try:
+ yield
+ except:
+ pass
+ DONE = 1
+
+ async def run():
+ nonlocal DONE
+ g = gen()
+ await g.asend(None)
+ with self.assertRaises(StopAsyncIteration):
+ await g.asend(None)
+ DONE += 10
+
+ self.loop.run_until_complete(run())
+ self.assertEqual(DONE, 11)
+
def test_async_gen_asyncio_anext_tuple(self):
async def foo():
try:
@@ -594,6 +629,76 @@
self.loop.run_until_complete(run())
self.assertEqual(DONE, 1)
+ def test_async_gen_asyncio_aclose_10(self):
+ DONE = 0
+
+ # test synchronous generators
+ def foo():
+ try:
+ yield
+ except:
+ pass
+ g = foo()
+ g.send(None)
+ g.close()
+
+ # now with asynchronous generators
+
+ async def gen():
+ nonlocal DONE
+ try:
+ yield
+ except:
+ pass
+ DONE = 1
+
+ async def run():
+ nonlocal DONE
+ g = gen()
+ await g.asend(None)
+ await g.aclose()
+ DONE += 10
+
+ self.loop.run_until_complete(run())
+ self.assertEqual(DONE, 11)
+
+ def test_async_gen_asyncio_aclose_11(self):
+ DONE = 0
+
+ # test synchronous generators
+ def foo():
+ try:
+ yield
+ except:
+ pass
+ yield
+ g = foo()
+ g.send(None)
+ with self.assertRaisesRegex(RuntimeError, 'ignored GeneratorExit'):
+ g.close()
+
+ # now with asynchronous generators
+
+ async def gen():
+ nonlocal DONE
+ try:
+ yield
+ except:
+ pass
+ yield
+ DONE += 1
+
+ async def run():
+ nonlocal DONE
+ g = gen()
+ await g.asend(None)
+ with self.assertRaisesRegex(RuntimeError, 'ignored GeneratorExit'):
+ await g.aclose()
+ DONE += 10
+
+ self.loop.run_until_complete(run())
+ self.assertEqual(DONE, 10)
+
def test_async_gen_asyncio_asend_01(self):
DONE = 0
@@ -801,6 +906,41 @@
self.loop.run_until_complete(run())
self.assertEqual(DONE, 1)
+ def test_async_gen_asyncio_athrow_03(self):
+ DONE = 0
+
+ # test synchronous generators
+ def foo():
+ try:
+ yield
+ except:
+ pass
+ g = foo()
+ g.send(None)
+ with self.assertRaises(StopIteration):
+ g.throw(ValueError)
+
+ # now with asynchronous generators
+
+ async def gen():
+ nonlocal DONE
+ try:
+ yield
+ except:
+ pass
+ DONE = 1
+
+ async def run():
+ nonlocal DONE
+ g = gen()
+ await g.asend(None)
+ with self.assertRaises(StopAsyncIteration):
+ await g.athrow(ValueError)
+ DONE += 10
+
+ self.loop.run_until_complete(run())
+ self.assertEqual(DONE, 11)
+
def test_async_gen_asyncio_athrow_tuple(self):
async def gen():
try:
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -122,6 +122,9 @@
- Issue #26182: Fix a refleak in code that raises DeprecationWarning.
+- Issue #28721: Fix asynchronous generators aclose() and athrow() to
+ handle StopAsyncIteration propagation properly.
+
Library
-------
diff --git a/Objects/genobject.c b/Objects/genobject.c
--- a/Objects/genobject.c
+++ b/Objects/genobject.c
@@ -1931,9 +1931,17 @@
return NULL;
check_error:
- if (PyErr_ExceptionMatches(PyExc_StopAsyncIteration)
- || PyErr_ExceptionMatches(PyExc_GeneratorExit)
- ) {
+ if (PyErr_ExceptionMatches(PyExc_StopAsyncIteration)) {
+ o->agt_state = AWAITABLE_STATE_CLOSED;
+ if (o->agt_args == NULL) {
+ /* when aclose() is called we don't want to propagate
+ StopAsyncIteration; just raise StopIteration, signalling
+ that 'aclose()' is done. */
+ PyErr_Clear();
+ PyErr_SetNone(PyExc_StopIteration);
+ }
+ }
+ else if (PyErr_ExceptionMatches(PyExc_GeneratorExit)) {
o->agt_state = AWAITABLE_STATE_CLOSED;
PyErr_Clear(); /* ignore these errors */
PyErr_SetNone(PyExc_StopIteration);
--
Repository URL: https://hg.python.org/cpython
More information about the Python-checkins
mailing list