bpo-39386: Prevent double awaiting of async iterator (GH-18081)

This commit is contained in:
Andrew Svetlov 2020-01-21 00:49:30 +02:00 committed by GitHub
parent 2c49becc69
commit a96e06db77
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 49 additions and 4 deletions

View File

@ -1128,6 +1128,42 @@ class AsyncGenAsyncioTest(unittest.TestCase):
self.assertEqual([], messages) self.assertEqual([], messages)
def test_async_gen_await_anext_twice(self):
async def async_iterate():
yield 1
yield 2
async def run():
it = async_iterate()
nxt = it.__anext__()
await nxt
with self.assertRaisesRegex(
RuntimeError,
r"cannot reuse already awaited __anext__\(\)/asend\(\)"
):
await nxt
await it.aclose() # prevent unfinished iterator warning
self.loop.run_until_complete(run())
def test_async_gen_await_aclose_twice(self):
async def async_iterate():
yield 1
yield 2
async def run():
it = async_iterate()
nxt = it.aclose()
await nxt
with self.assertRaisesRegex(
RuntimeError,
r"cannot reuse already awaited aclose\(\)/athrow\(\)"
):
await nxt
self.loop.run_until_complete(run())
if __name__ == "__main__": if __name__ == "__main__":
unittest.main() unittest.main()

View File

@ -0,0 +1 @@
Prevent double awaiting of async iterator.

View File

@ -1518,7 +1518,9 @@ async_gen_asend_send(PyAsyncGenASend *o, PyObject *arg)
PyObject *result; PyObject *result;
if (o->ags_state == AWAITABLE_STATE_CLOSED) { if (o->ags_state == AWAITABLE_STATE_CLOSED) {
PyErr_SetNone(PyExc_StopIteration); PyErr_SetString(
PyExc_RuntimeError,
"cannot reuse already awaited __anext__()/asend()");
return NULL; return NULL;
} }
@ -1561,7 +1563,9 @@ async_gen_asend_throw(PyAsyncGenASend *o, PyObject *args)
PyObject *result; PyObject *result;
if (o->ags_state == AWAITABLE_STATE_CLOSED) { if (o->ags_state == AWAITABLE_STATE_CLOSED) {
PyErr_SetNone(PyExc_StopIteration); PyErr_SetString(
PyExc_RuntimeError,
"cannot reuse already awaited __anext__()/asend()");
return NULL; return NULL;
} }
@ -1795,7 +1799,9 @@ async_gen_athrow_send(PyAsyncGenAThrow *o, PyObject *arg)
if (f == NULL || f->f_stacktop == NULL || if (f == NULL || f->f_stacktop == NULL ||
o->agt_state == AWAITABLE_STATE_CLOSED) { o->agt_state == AWAITABLE_STATE_CLOSED) {
PyErr_SetNone(PyExc_StopIteration); PyErr_SetString(
PyExc_RuntimeError,
"cannot reuse already awaited aclose()/athrow()");
return NULL; return NULL;
} }
@ -1917,7 +1923,9 @@ async_gen_athrow_throw(PyAsyncGenAThrow *o, PyObject *args)
PyObject *retval; PyObject *retval;
if (o->agt_state == AWAITABLE_STATE_CLOSED) { if (o->agt_state == AWAITABLE_STATE_CLOSED) {
PyErr_SetNone(PyExc_StopIteration); PyErr_SetString(
PyExc_RuntimeError,
"cannot reuse already awaited aclose()/athrow()");
return NULL; return NULL;
} }