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

(cherry picked from commit a96e06db77)

Co-authored-by: Andrew Svetlov <andrew.svetlov@gmail.com>
This commit is contained in:
Miss Islington (bot) 2020-01-20 15:07:54 -08:00 committed by GitHub
parent 2469066a4b
commit b76d5e9ee6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 49 additions and 4 deletions

View File

@ -1117,6 +1117,42 @@ class AsyncGenAsyncioTest(unittest.TestCase):
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__":
unittest.main()

View File

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

View File

@ -1533,7 +1533,9 @@ async_gen_asend_send(PyAsyncGenASend *o, PyObject *arg)
PyObject *result;
if (o->ags_state == AWAITABLE_STATE_CLOSED) {
PyErr_SetNone(PyExc_StopIteration);
PyErr_SetString(
PyExc_RuntimeError,
"cannot reuse already awaited __anext__()/asend()");
return NULL;
}
@ -1568,7 +1570,9 @@ async_gen_asend_throw(PyAsyncGenASend *o, PyObject *args)
PyObject *result;
if (o->ags_state == AWAITABLE_STATE_CLOSED) {
PyErr_SetNone(PyExc_StopIteration);
PyErr_SetString(
PyExc_RuntimeError,
"cannot reuse already awaited __anext__()/asend()");
return NULL;
}
@ -1802,7 +1806,9 @@ async_gen_athrow_send(PyAsyncGenAThrow *o, PyObject *arg)
if (f == NULL || f->f_stacktop == NULL ||
o->agt_state == AWAITABLE_STATE_CLOSED) {
PyErr_SetNone(PyExc_StopIteration);
PyErr_SetString(
PyExc_RuntimeError,
"cannot reuse already awaited aclose()/athrow()");
return NULL;
}
@ -1906,7 +1912,9 @@ async_gen_athrow_throw(PyAsyncGenAThrow *o, PyObject *args)
PyObject *retval;
if (o->agt_state == AWAITABLE_STATE_CLOSED) {
PyErr_SetNone(PyExc_StopIteration);
PyErr_SetString(
PyExc_RuntimeError,
"cannot reuse already awaited aclose()/athrow()");
return NULL;
}