summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Grainger <tagrain@gmail.com>2024-04-24 12:20:19 (GMT)
committerGitHub <noreply@github.com>2024-04-24 12:20:19 (GMT)
commit7d369d471cf2b067c4d795d70b75201c48b46f5b (patch)
tree5e2314e99e11ddcf8de3289ed1ea2073dae9883b
parent975081b11e052c9f8deb42c5876104651736302e (diff)
downloadcpython-7d369d471cf2b067c4d795d70b75201c48b46f5b.zip
cpython-7d369d471cf2b067c4d795d70b75201c48b46f5b.tar.gz
cpython-7d369d471cf2b067c4d795d70b75201c48b46f5b.tar.bz2
GH-117536: GH-117894: fix athrow().throw(...) unawaited warning (GH-117851)
-rw-r--r--Lib/test/test_asyncgen.py83
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2024-04-13-16-55-53.gh-issue-117536.xkVbfv.rst1
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2024-04-15-13-53-59.gh-issue-117894.8LpZ6m.rst1
-rw-r--r--Objects/genobject.c9
4 files changed, 81 insertions, 13 deletions
diff --git a/Lib/test/test_asyncgen.py b/Lib/test/test_asyncgen.py
index 39605dc..a1e9e1b 100644
--- a/Lib/test/test_asyncgen.py
+++ b/Lib/test/test_asyncgen.py
@@ -399,9 +399,8 @@ class AsyncGenTest(unittest.TestCase):
with self.assertWarns(DeprecationWarning):
x = gen().athrow(GeneratorExit, GeneratorExit(), None)
- with self.assertWarnsRegex(RuntimeWarning,
- f"coroutine method 'athrow' of '{gen.__qualname__}' "
- f"was never awaited"):
+ with self.assertRaises(GeneratorExit):
+ x.send(None)
del x
gc_collect()
@@ -1572,11 +1571,6 @@ class AsyncGenAsyncioTest(unittest.TestCase):
self.assertIsInstance(message['exception'], ZeroDivisionError)
self.assertIn('unhandled exception during asyncio.run() shutdown',
message['message'])
- with self.assertWarnsRegex(RuntimeWarning,
- f"coroutine method 'aclose' of '{async_iterate.__qualname__}' "
- f"was never awaited"):
- del message, messages
- gc_collect()
def test_async_gen_expression_01(self):
async def arange(n):
@@ -1630,10 +1624,6 @@ class AsyncGenAsyncioTest(unittest.TestCase):
asyncio.run(main())
self.assertEqual([], messages)
- with self.assertWarnsRegex(RuntimeWarning,
- f"coroutine method 'aclose' of '{async_iterate.__qualname__}' "
- f"was never awaited"):
- gc_collect()
def test_async_gen_await_same_anext_coro_twice(self):
async def async_iterate():
@@ -1671,6 +1661,62 @@ class AsyncGenAsyncioTest(unittest.TestCase):
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():
@@ -1752,6 +1798,19 @@ class TestUnawaitedWarnings(unittest.TestCase):
g.aclose()
gc_collect()
+ def test_aclose_throw(self):
+ async def gen():
+ return
+ yield
+
+ class MyException(Exception):
+ pass
+
+ g = gen()
+ with self.assertRaises(MyException):
+ g.aclose().throw(MyException)
+ del g
+ gc_collect()
if __name__ == "__main__":
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 0000000..2492fd1
--- /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 0000000..bd32500
--- /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 8d1dbb7..5d7da49 100644
--- a/Objects/genobject.c
+++ b/Objects/genobject.c
@@ -2208,7 +2208,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)) {
@@ -2218,6 +2222,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))
{