Skip to content
This repository was archived by the owner on Feb 13, 2025. It is now read-only.

Commit 70719e7

Browse files
author
Anselm Kruis
committed
Merge branch 3.8 into 3.8-slp
The Stackless test suite does not pass for the outcome of this merge.
2 parents 7f779f4 + 8dbdf5f commit 70719e7

File tree

3 files changed

+41
-6
lines changed

3 files changed

+41
-6
lines changed

Lib/test/test_asyncgen.py

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1128,7 +1128,7 @@ async def main():
11281128

11291129
self.assertEqual([], messages)
11301130

1131-
def test_async_gen_await_anext_twice(self):
1131+
def test_async_gen_await_same_anext_coro_twice(self):
11321132
async def async_iterate():
11331133
yield 1
11341134
yield 2
@@ -1147,7 +1147,7 @@ async def run():
11471147

11481148
self.loop.run_until_complete(run())
11491149

1150-
def test_async_gen_await_aclose_twice(self):
1150+
def test_async_gen_await_same_aclose_coro_twice(self):
11511151
async def async_iterate():
11521152
yield 1
11531153
yield 2
@@ -1164,6 +1164,32 @@ async def run():
11641164

11651165
self.loop.run_until_complete(run())
11661166

1167+
def test_async_gen_aclose_twice_with_different_coros(self):
1168+
# Regression test for https://bugs.python.org/issue39606
1169+
async def async_iterate():
1170+
yield 1
1171+
yield 2
1172+
1173+
async def run():
1174+
it = async_iterate()
1175+
await it.aclose()
1176+
await it.aclose()
1177+
1178+
self.loop.run_until_complete(run())
1179+
1180+
def test_async_gen_aclose_after_exhaustion(self):
1181+
# Regression test for https://bugs.python.org/issue39606
1182+
async def async_iterate():
1183+
yield 1
1184+
yield 2
1185+
1186+
async def run():
1187+
it = async_iterate()
1188+
async for _ in it:
1189+
pass
1190+
await it.aclose()
1191+
1192+
self.loop.run_until_complete(run())
11671193

11681194
if __name__ == "__main__":
11691195
unittest.main()
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix regression caused by fix for bpo-39386, that prevented calling
2+
``aclose`` on an async generator that had already been closed or exhausted.

Objects/genobject.c

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2010,16 +2010,22 @@ async_gen_athrow_send(PyAsyncGenAThrow *o, PyObject *arg)
20102010
PyFrameObject *f = gen->gi_frame;
20112011
PyObject *retval;
20122012

2013-
if (f == NULL || f->f_stacktop == NULL ||
2014-
o->agt_state == AWAITABLE_STATE_CLOSED) {
2013+
if (o->agt_state == AWAITABLE_STATE_CLOSED) {
20152014
PyErr_SetString(
20162015
PyExc_RuntimeError,
20172016
"cannot reuse already awaited aclose()/athrow()");
20182017
return NULL;
20192018
}
20202019

2020+
if (f == NULL || f->f_stacktop == NULL) {
2021+
o->agt_state = AWAITABLE_STATE_CLOSED;
2022+
PyErr_SetNone(PyExc_StopIteration);
2023+
return NULL;
2024+
}
2025+
20212026
if (o->agt_state == AWAITABLE_STATE_INIT) {
20222027
if (o->agt_gen->ag_running_async) {
2028+
o->agt_state = AWAITABLE_STATE_CLOSED;
20232029
if (o->agt_args == NULL) {
20242030
PyErr_SetString(
20252031
PyExc_RuntimeError,
@@ -2091,7 +2097,6 @@ async_gen_athrow_send(PyAsyncGenAThrow *o, PyObject *arg)
20912097
/* aclose() mode */
20922098
if (retval) {
20932099
if (_PyAsyncGenWrappedValue_CheckExact(retval)) {
2094-
o->agt_gen->ag_running_async = 0;
20952100
Py_DECREF(retval);
20962101
goto yield_close;
20972102
}
@@ -2106,16 +2111,17 @@ async_gen_athrow_send(PyAsyncGenAThrow *o, PyObject *arg)
21062111

21072112
yield_close:
21082113
o->agt_gen->ag_running_async = 0;
2114+
o->agt_state = AWAITABLE_STATE_CLOSED;
21092115
PyErr_SetString(
21102116
PyExc_RuntimeError, ASYNC_GEN_IGNORED_EXIT_MSG);
21112117
return NULL;
21122118

21132119
check_error:
21142120
o->agt_gen->ag_running_async = 0;
2121+
o->agt_state = AWAITABLE_STATE_CLOSED;
21152122
if (PyErr_ExceptionMatches(PyExc_StopAsyncIteration) ||
21162123
PyErr_ExceptionMatches(PyExc_GeneratorExit))
21172124
{
2118-
o->agt_state = AWAITABLE_STATE_CLOSED;
21192125
if (o->agt_args == NULL) {
21202126
/* when aclose() is called we don't want to propagate
21212127
StopAsyncIteration or GeneratorExit; just raise
@@ -2149,6 +2155,7 @@ async_gen_athrow_throw(PyAsyncGenAThrow *o, PyObject *args)
21492155
/* aclose() mode */
21502156
if (retval && _PyAsyncGenWrappedValue_CheckExact(retval)) {
21512157
o->agt_gen->ag_running_async = 0;
2158+
o->agt_state = AWAITABLE_STATE_CLOSED;
21522159
Py_DECREF(retval);
21532160
PyErr_SetString(PyExc_RuntimeError, ASYNC_GEN_IGNORED_EXIT_MSG);
21542161
return NULL;

0 commit comments

Comments
 (0)