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

Commit b76d5e9

Browse files
bpo-39386: Prevent double awaiting of async iterator (pythonGH-18081)
(cherry picked from commit a96e06d) Co-authored-by: Andrew Svetlov <[email protected]>
1 parent 2469066 commit b76d5e9

File tree

3 files changed

+49
-4
lines changed

3 files changed

+49
-4
lines changed

Lib/test/test_asyncgen.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1117,6 +1117,42 @@ async def main():
11171117

11181118
self.assertEqual([], messages)
11191119

1120+
def test_async_gen_await_anext_twice(self):
1121+
async def async_iterate():
1122+
yield 1
1123+
yield 2
1124+
1125+
async def run():
1126+
it = async_iterate()
1127+
nxt = it.__anext__()
1128+
await nxt
1129+
with self.assertRaisesRegex(
1130+
RuntimeError,
1131+
r"cannot reuse already awaited __anext__\(\)/asend\(\)"
1132+
):
1133+
await nxt
1134+
1135+
await it.aclose() # prevent unfinished iterator warning
1136+
1137+
self.loop.run_until_complete(run())
1138+
1139+
def test_async_gen_await_aclose_twice(self):
1140+
async def async_iterate():
1141+
yield 1
1142+
yield 2
1143+
1144+
async def run():
1145+
it = async_iterate()
1146+
nxt = it.aclose()
1147+
await nxt
1148+
with self.assertRaisesRegex(
1149+
RuntimeError,
1150+
r"cannot reuse already awaited aclose\(\)/athrow\(\)"
1151+
):
1152+
await nxt
1153+
1154+
self.loop.run_until_complete(run())
1155+
11201156

11211157
if __name__ == "__main__":
11221158
unittest.main()
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Prevent double awaiting of async iterator.

Objects/genobject.c

Lines changed: 12 additions & 4 deletions
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

@@ -1568,7 +1570,9 @@ async_gen_asend_throw(PyAsyncGenASend *o, PyObject *args)
15681570
PyObject *result;
15691571

15701572
if (o->ags_state == AWAITABLE_STATE_CLOSED) {
1571-
PyErr_SetNone(PyExc_StopIteration);
1573+
PyErr_SetString(
1574+
PyExc_RuntimeError,
1575+
"cannot reuse already awaited __anext__()/asend()");
15721576
return NULL;
15731577
}
15741578

@@ -1802,7 +1806,9 @@ async_gen_athrow_send(PyAsyncGenAThrow *o, PyObject *arg)
18021806

18031807
if (f == NULL || f->f_stacktop == NULL ||
18041808
o->agt_state == AWAITABLE_STATE_CLOSED) {
1805-
PyErr_SetNone(PyExc_StopIteration);
1809+
PyErr_SetString(
1810+
PyExc_RuntimeError,
1811+
"cannot reuse already awaited aclose()/athrow()");
18061812
return NULL;
18071813
}
18081814

@@ -1906,7 +1912,9 @@ async_gen_athrow_throw(PyAsyncGenAThrow *o, PyObject *args)
19061912
PyObject *retval;
19071913

19081914
if (o->agt_state == AWAITABLE_STATE_CLOSED) {
1909-
PyErr_SetNone(PyExc_StopIteration);
1915+
PyErr_SetString(
1916+
PyExc_RuntimeError,
1917+
"cannot reuse already awaited aclose()/athrow()");
19101918
return NULL;
19111919
}
19121920

0 commit comments

Comments
 (0)