Skip to content

Commit 4ffc569

Browse files
bpo-35409: Ignore GeneratorExit in async_gen_athrow_throw (GH-14755)
Ignore `GeneratorExit` exceptions when throwing an exception into the `aclose` coroutine of an asynchronous generator. https://bugs.python.org/issue35409 (cherry picked from commit 8e0de2a) Co-authored-by: Vincent Michel <[email protected]>
1 parent 2b928d9 commit 4ffc569

File tree

3 files changed

+40
-0
lines changed

3 files changed

+40
-0
lines changed

Lib/test/test_asyncgen.py

+27
Original file line numberDiff line numberDiff line change
@@ -696,6 +696,33 @@ async def run():
696696
self.loop.run_until_complete(run())
697697
self.assertEqual(DONE, 10)
698698

699+
def test_async_gen_asyncio_aclose_12(self):
700+
DONE = 0
701+
702+
async def target():
703+
await asyncio.sleep(0.01)
704+
1 / 0
705+
706+
async def foo():
707+
nonlocal DONE
708+
task = asyncio.create_task(target())
709+
try:
710+
yield 1
711+
finally:
712+
try:
713+
await task
714+
except ZeroDivisionError:
715+
DONE = 1
716+
717+
async def run():
718+
gen = foo()
719+
it = gen.__aiter__()
720+
await it.__anext__()
721+
await gen.aclose()
722+
723+
self.loop.run_until_complete(run())
724+
self.assertEqual(DONE, 1)
725+
699726
def test_async_gen_asyncio_asend_01(self):
700727
DONE = 0
701728

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Ignore GeneratorExit exceptions when throwing an exception into the aclose
2+
coroutine of an asynchronous generator.

Objects/genobject.c

+11
Original file line numberDiff line numberDiff line change
@@ -1920,6 +1920,17 @@ async_gen_athrow_throw(PyAsyncGenAThrow *o, PyObject *args)
19201920
PyErr_SetString(PyExc_RuntimeError, ASYNC_GEN_IGNORED_EXIT_MSG);
19211921
return NULL;
19221922
}
1923+
if (PyErr_ExceptionMatches(PyExc_StopAsyncIteration) ||
1924+
PyErr_ExceptionMatches(PyExc_GeneratorExit))
1925+
{
1926+
/* when aclose() is called we don't want to propagate
1927+
StopAsyncIteration or GeneratorExit; just raise
1928+
StopIteration, signalling that this 'aclose()' await
1929+
is done.
1930+
*/
1931+
PyErr_Clear();
1932+
PyErr_SetNone(PyExc_StopIteration);
1933+
}
19231934
return retval;
19241935
}
19251936
}

0 commit comments

Comments
 (0)