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

Commit 5cadd3f

Browse files
bpo-39386: Prevent double awaiting of async iterator (pythonGH-18081)
(cherry picked from commit a96e06d) Co-authored-by: Andrew Svetlov <andrew.svetlov@gmail.com>
1 parent 6aeed01 commit 5cadd3f

File tree

3 files changed

+49
-4
lines changed

3 files changed

+49
-4
lines changed

Lib/test/test_asyncgen.py

+36
Original file line numberDiff line numberDiff line change
@@ -1128,6 +1128,42 @@ async def main():
11281128

11291129
self.assertEqual([], messages)
11301130

1131+
def test_async_gen_await_anext_twice(self):
1132+
async def async_iterate():
1133+
yield 1
1134+
yield 2
1135+
1136+
async def run():
1137+
it = async_iterate()
1138+
nxt = it.__anext__()
1139+
await nxt
1140+
with self.assertRaisesRegex(
1141+
RuntimeError,
1142+
r"cannot reuse already awaited __anext__\(\)/asend\(\)"
1143+
):
1144+
await nxt
1145+
1146+
await it.aclose() # prevent unfinished iterator warning
1147+
1148+
self.loop.run_until_complete(run())
1149+
1150+
def test_async_gen_await_aclose_twice(self):
1151+
async def async_iterate():
1152+
yield 1
1153+
yield 2
1154+
1155+
async def run():
1156+
it = async_iterate()
1157+
nxt = it.aclose()
1158+
await nxt
1159+
with self.assertRaisesRegex(
1160+
RuntimeError,
1161+
r"cannot reuse already awaited aclose\(\)/athrow\(\)"
1162+
):
1163+
await nxt
1164+
1165+
self.loop.run_until_complete(run())
1166+
11311167

11321168
if __name__ == "__main__":
11331169
unittest.main()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Prevent double awaiting of async iterator.

Objects/genobject.c

+12-4
Original file line numberDiff line numberDiff line change
@@ -1533,7 +1533,9 @@ async_gen_asend_send(PyAsyncGenASend *o, PyObject *arg)
15331533
PyObject *result;
15341534

15351535
if (o->ags_state == AWAITABLE_STATE_CLOSED) {
1536-
PyErr_SetNone(PyExc_StopIteration);
1536+
PyErr_SetString(
1537+
PyExc_RuntimeError,
1538+
"cannot reuse already awaited __anext__()/asend()");
15371539
return NULL;
15381540
}
15391541

@@ -1576,7 +1578,9 @@ async_gen_asend_throw(PyAsyncGenASend *o, PyObject *args)
15761578
PyObject *result;
15771579

15781580
if (o->ags_state == AWAITABLE_STATE_CLOSED) {
1579-
PyErr_SetNone(PyExc_StopIteration);
1581+
PyErr_SetString(
1582+
PyExc_RuntimeError,
1583+
"cannot reuse already awaited __anext__()/asend()");
15801584
return NULL;
15811585
}
15821586

@@ -1810,7 +1814,9 @@ async_gen_athrow_send(PyAsyncGenAThrow *o, PyObject *arg)
18101814

18111815
if (f == NULL || f->f_stacktop == NULL ||
18121816
o->agt_state == AWAITABLE_STATE_CLOSED) {
1813-
PyErr_SetNone(PyExc_StopIteration);
1817+
PyErr_SetString(
1818+
PyExc_RuntimeError,
1819+
"cannot reuse already awaited aclose()/athrow()");
18141820
return NULL;
18151821
}
18161822

@@ -1932,7 +1938,9 @@ async_gen_athrow_throw(PyAsyncGenAThrow *o, PyObject *args)
19321938
PyObject *retval;
19331939

19341940
if (o->agt_state == AWAITABLE_STATE_CLOSED) {
1935-
PyErr_SetNone(PyExc_StopIteration);
1941+
PyErr_SetString(
1942+
PyExc_RuntimeError,
1943+
"cannot reuse already awaited aclose()/athrow()");
19361944
return NULL;
19371945
}
19381946

0 commit comments

Comments
 (0)