8000 bpo-33786: Fix asynchronous generators to handle GeneratorExit in ath… · python/cpython@8de73d5 · GitHub
[go: up one dir, main page]

Skip to content

Commit 8de73d5

Browse files
authored
bpo-33786: Fix asynchronous generators to handle GeneratorExit in athrow() (GH-7467) (GH-7507)
1 parent d071ab1 commit 8de73d5

File tree

3 files changed

+64
-8
lines changed

3 files changed

+64
-8
lines changed

Lib/test/test_asyncgen.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,31 @@ def sync_iterate(g):
111111
res.append(str(type(ex)))
112112
return res
113113

114+
def async_iterate(g):
115+
res = []
116+
while True:
117+
an = g.__anext__()
118+
try:
119+
while True:
120+
try:
121+
an.__next__()
122+
except StopIteration as ex:
123+
if ex.args:
124+
res.append(ex.args[0])
125+
break
126+
else:
127+
res.append('EMPTY StopIteration')
128+
break
129+
except StopAsyncIteration:
130+
raise
131+
except Exception as ex:
132+
res.append(str(type(ex)))
133+
break
134+
except StopAsyncIteration:
135+
res.append('STOP')
136+
break
137+
return res
138+
114139
def async_iterate(g):
115140
res = []
116141
while True:
@@ -300,6 +325,37 @@ async def gen():
300325
"non-None value .* async generator"):
301326
gen().__anext__().send(100)
302327

328+
def test_async_gen_exception_11(self):
329+
def sync_gen():
330+
yield 10
331+
yield 20
332+
333+
def sync_gen_wrapper():
334+
yield 1
335+
sg = sync_gen()
336+
sg.send(None)
337+
try:
338+
sg.throw(GeneratorExit())
339+
except GeneratorExit:
340+
yield 2
341+
yield 3
342+
343+
async def async_gen():
344+
yield 10
345+
yield 20
346+
347+
async def async_gen_wrapper():
348+
yield 1
349+
asg = async_gen()
350+
await asg.asend(None)
351+
try:
352+
await asg.athrow(GeneratorExit())
353+
except GeneratorExit:
354+
yield 2
355+
yield 3
356+
357+
self.compare_generators(sync_gen_wrapper(), async_gen_wrapper())
358+
303359
def test_async_gen_api_01(self):
304360
async def gen():
305361
yield 123
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix asynchronous generators to handle GeneratorExit in athrow() correctly

Objects/genobject.c

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1939,21 +1939,20 @@ async_gen_athrow_send(PyAsyncGenAThrow *o, PyObject *arg)
19391939
return NULL;
19401940

19411941
check_error:
1942-
if (PyErr_ExceptionMatches(PyExc_StopAsyncIteration)) {
1942+
if (PyErr_ExceptionMatches(PyExc_StopAsyncIteration) ||
1943+
PyErr_ExceptionMatches(PyExc_GeneratorExit))
1944+
{
19431945
o->agt_state = AWAITABLE_STATE_CLOSED;
19441946
if (o->agt_args == NULL) {
19451947
/* when aclose() is called we don't want to propagate
1946-
StopAsyncIteration; just raise StopIteration, signalling
1947-
that 'aclose()' is done. */
1948+
StopAsyncIteration or GeneratorExit; just raise
1949+
StopIteration, signalling that this 'aclose()' await
1950+
is done.
1951+
*/
19481952
PyErr_Clear();
19491953
PyErr_SetNone(PyExc_StopIteration);
19501954
}
19511955
}
1952-
else if (PyErr_ExceptionMatches(PyExc_GeneratorExit)) {
1953-
o->agt_state = AWAITABLE_STATE_CLOSED;
1954-
PyErr_Clear(); /* ignore these errors */
1955-
PyErr_SetNone(PyExc_StopIteration);
1956-
}
19571956
return NULL;
19581957
}
19591958

0 commit comments

Comments
 (0)
0