From b4843679a2e5a8528469a0d88717b155240122ca Mon Sep 17 00:00:00 2001 From: Thomas Grainger Date: Wed, 24 Apr 2024 13:20:19 +0100 Subject: [PATCH 1/2] GH-117536: GH-117894: fix athrow().throw(...) unawaited warning (GH-117851) (cherry picked from commit 7d369d471cf2b067c4d795d70b75201c48b46f5b) --- Lib/test/test_asyncgen.py | 62 ++++++++++++++++++- ...-04-13-16-55-53.gh-issue-117536.xkVbfv.rst | 1 + ...-04-15-13-53-59.gh-issue-117894.8LpZ6m.rst | 1 + Objects/genobject.c | 9 ++- 4 files changed, 71 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-04-13-16-55-53.gh-issue-117536.xkVbfv.rst create mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-04-15-13-53-59.gh-issue-117894.8LpZ6m.rst diff --git a/Lib/test/test_asyncgen.py b/Lib/test/test_asyncgen.py index 9a9343781cd40c..ee7e3968b00b26 100644 --- a/Lib/test/test_asyncgen.py +++ b/Lib/test/test_asyncgen.py @@ -395,7 +395,11 @@ async def gen(): yield 123 with self.assertWarns(DeprecationWarning): - gen().athrow(GeneratorExit, GeneratorExit(), None) + x = gen().athrow(GeneratorExit, GeneratorExit(), None) + with self.assertRaises(GeneratorExit): + x.send(None) + del x + gc_collect() def test_async_gen_api_01(self): async def gen(): @@ -1653,6 +1657,62 @@ async def run(): self.loop.run_until_complete(run()) + def test_async_gen_throw_same_aclose_coro_twice(self): + async def async_iterate(): + yield 1 + yield 2 + + it = async_iterate() + nxt = it.aclose() + with self.assertRaises(StopIteration): + nxt.throw(GeneratorExit) + + with self.assertRaisesRegex( + RuntimeError, + r"cannot reuse already awaited aclose\(\)/athrow\(\)" + ): + nxt.throw(GeneratorExit) + + def test_async_gen_throw_custom_same_aclose_coro_twice(self): + async def async_iterate(): + yield 1 + yield 2 + + it = async_iterate() + + class MyException(Exception): + pass + + nxt = it.aclose() + with self.assertRaises(MyException): + nxt.throw(MyException) + + with self.assertRaisesRegex( + RuntimeError, + r"cannot reuse already awaited aclose\(\)/athrow\(\)" + ): + nxt.throw(MyException) + + def test_async_gen_throw_custom_same_athrow_coro_twice(self): + async def async_iterate(): + yield 1 + yield 2 + + it = async_iterate() + + class MyException(Exception): + pass + + nxt = it.athrow(MyException) + with self.assertRaises(MyException): + nxt.throw(MyException) + + with self.assertRaisesRegex( + RuntimeError, + r"cannot reuse already awaited aclose\(\)/athrow\(\)" + ): + nxt.throw(MyException) + def test_async_gen_aclose_twice_with_different_coros(self): # Regression test for https://bugs.python.org/issue39606 async def async_iterate(): diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-04-13-16-55-53.gh-issue-117536.xkVbfv.rst b/Misc/NEWS.d/next/Core and Builtins/2024-04-13-16-55-53.gh-issue-117536.xkVbfv.rst new file mode 100644 index 00000000000000..2492fd163cb549 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2024-04-13-16-55-53.gh-issue-117536.xkVbfv.rst @@ -0,0 +1 @@ +Fix a :exc:`RuntimeWarning` when calling ``agen.aclose().throw(Exception)``. diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-04-15-13-53-59.gh-issue-117894.8LpZ6m.rst b/Misc/NEWS.d/next/Core and Builtins/2024-04-15-13-53-59.gh-issue-117894.8LpZ6m.rst new file mode 100644 index 00000000000000..bd32500a54ee21 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2024-04-15-13-53-59.gh-issue-117894.8LpZ6m.rst @@ -0,0 +1 @@ +Prevent ``agen.aclose()`` objects being re-used after ``.throw()``. diff --git a/Objects/genobject.c b/Objects/genobject.c index bc58409c181360..3fc2ac083d1c15 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -2223,7 +2223,11 @@ async_gen_athrow_throw(PyAsyncGenAThrow *o, PyObject *const *args, Py_ssize_t na retval = gen_throw((PyGenObject*)o->agt_gen, args, nargs); if (o->agt_args) { - return async_gen_unwrap_value(o->agt_gen, retval); + retval = async_gen_unwrap_value(o->agt_gen, retval); + if (retval == NULL) { + o->agt_state = AWAITABLE_STATE_CLOSED; + } + return retval; } else { /* aclose() mode */ if (retval && _PyAsyncGenWrappedValue_CheckExact(retval)) { @@ -2233,6 +2237,9 @@ async_gen_athrow_throw(PyAsyncGenAThrow *o, PyObject *const *args, Py_ssize_t na PyErr_SetString(PyExc_RuntimeError, ASYNC_GEN_IGNORED_EXIT_MSG); return NULL; } + if (retval == NULL) { + o->agt_state = AWAITABLE_STATE_CLOSED; + } if (PyErr_ExceptionMatches(PyExc_StopAsyncIteration) || PyErr_ExceptionMatches(PyExc_GeneratorExit)) { From 338efdab1e0aab591dc315c03318c494dbfaba17 Mon Sep 17 00:00:00 2001 From: Thomas Grainger Date: Wed, 24 Apr 2024 13:59:57 +0100 Subject: [PATCH 2/2] remove blurb only applicable on 3.13 --- .../2024-04-13-16-55-53.gh-issue-117536.xkVbfv.rst | 1 - 1 file changed, 1 deletion(-) delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-04-13-16-55-53.gh-issue-117536.xkVbfv.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-04-13-16-55-53.gh-issue-117536.xkVbfv.rst b/Misc/NEWS.d/next/Core and Builtins/2024-04-13-16-55-53.gh-issue-117536.xkVbfv.rst deleted file mode 100644 index 2492fd163cb549..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-04-13-16-55-53.gh-issue-117536.xkVbfv.rst +++ /dev/null @@ -1 +0,0 @@ -Fix a :exc:`RuntimeWarning` when calling ``agen.aclose().throw(Exception)``.