Skip to content

Commit 7d369d4

Browse files
authored
GH-117536: GH-117894: fix athrow().throw(...) unawaited warning (GH-117851)
1 parent 975081b commit 7d369d4

File tree

4 files changed

+81
-13
lines changed

4 files changed

+81
-13
lines changed

Lib/test/test_asyncgen.py

+71-12
Original file line numberDiff line numberDiff line change
@@ -399,9 +399,8 @@ async def gen():
399399

400400
with self.assertWarns(DeprecationWarning):
401401
x = gen().athrow(GeneratorExit, GeneratorExit(), None)
402-
with self.assertWarnsRegex(RuntimeWarning,
403-
f"coroutine method 'athrow' of '{gen.__qualname__}' "
404-
f"was never awaited"):
402+
with self.assertRaises(GeneratorExit):
403+
x.send(None)
405404
del x
406405
gc_collect()
407406

@@ -1572,11 +1571,6 @@ async def main():
15721571
self.assertIsInstance(message['exception'], ZeroDivisionError)
15731572
self.assertIn('unhandled exception during asyncio.run() shutdown',
15741573
message['message'])
1575-
with self.assertWarnsRegex(RuntimeWarning,
1576-
f"coroutine method 'aclose' of '{async_iterate.__qualname__}' "
1577-
f"was never awaited"):
1578-
del message, messages
1579-
gc_collect()
15801574

15811575
def test_async_gen_expression_01(self):
15821576
async def arange(n):
@@ -1630,10 +1624,6 @@ async def main():
16301624
asyncio.run(main())
16311625

16321626
self.assertEqual([], messages)
1633-
with self.assertWarnsRegex(RuntimeWarning,
1634-
f"coroutine method 'aclose' of '{async_iterate.__qualname__}' "
1635-
f"was never awaited"):
1636-
gc_collect()
16371627

16381628
def test_async_gen_await_same_anext_coro_twice(self):
16391629
async def async_iterate():
@@ -1671,6 +1661,62 @@ async def run():
16711661

16721662
self.loop.run_until_complete(run())
16731663

1664+
def test_async_gen_throw_same_aclose_coro_twice(self):
1665+
async def async_iterate():
1666+
yield 1
1667+
yield 2
1668+
1669+
it = async_iterate()
1670+
nxt = it.aclose()
1671+
with self.assertRaises(StopIteration):
1672+
nxt.throw(GeneratorExit)
1673+
1674+
with self.assertRaisesRegex(
1675+
RuntimeError,
1676+
r"cannot reuse already awaited aclose\(\)/athrow\(\)"
1677+
):
1678+
nxt.throw(GeneratorExit)
1679+
1680+
def test_async_gen_throw_custom_same_aclose_coro_twice(self):
1681+
async def async_iterate():
1682+
yield 1
1683+
yield 2
1684+
1685+
it = async_iterate()
1686+
1687+
class MyException(Exception):
1688+
pass
1689+
1690+
nxt = it.aclose()
1691+
with self.assertRaises(MyException):
1692+
nxt.throw(MyException)
1693+
1694+
with self.assertRaisesRegex(
1695+
RuntimeError,
1696+
r"cannot reuse already awaited aclose\(\)/athrow\(\)"
1697+
):
1698+
nxt.throw(MyException)
1699+
1700+
def test_async_gen_throw_custom_same_athrow_coro_twice(self):
1701+
async def async_iterate():
1702+
yield 1
1703+
yield 2
1704+
1705+
it = async_iterate()
1706+
1707+
class MyException(Exception):
1708+
pass
1709+
1710+
nxt = it.athrow(MyException)
1711+
with self.assertRaises(MyException):
1712+
nxt.throw(MyException)
1713+
1714+
with self.assertRaisesRegex(
1715+
RuntimeError,
1716+
r"cannot reuse already awaited aclose\(\)/athrow\(\)"
1717+
):
1718+
nxt.throw(MyException)
1719+
16741720
def test_async_gen_aclose_twice_with_different_coros(self):
16751721
# Regression test for https://bugs.python.org/issue39606
16761722
async def async_iterate():
@@ -1752,6 +1798,19 @@ async def gen():
17521798
g.aclose()
17531799
gc_collect()
17541800

1801+
def test_aclose_throw(self):
1802+
async def gen():
1803+
return
1804+
yield
1805+
1806+
class MyException(Exception):
1807+
pass
1808+
1809+
g = gen()
1810+
with self.assertRaises(MyException):
1811+
g.aclose().throw(MyException)
1812+
del g
1813+
gc_collect()
17551814

17561815

17571816
if __name__ == "__main__":
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix a :exc:`RuntimeWarning` when calling ``agen.aclose().throw(Exception)``.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Prevent ``agen.aclose()`` objects being re-used after ``.throw()``.

Objects/genobject.c

+8-1
Original file line numberDiff line numberDiff line change
@@ -2208,7 +2208,11 @@ async_gen_athrow_throw(PyAsyncGenAThrow *o, PyObject *const *args, Py_ssize_t na
22082208

22092209
retval = gen_throw((PyGenObject*)o->agt_gen, args, nargs);
22102210
if (o->agt_args) {
2211-
return async_gen_unwrap_value(o->agt_gen, retval);
2211+
retval = async_gen_unwrap_value(o->agt_gen, retval);
2212+
if (retval == NULL) {
2213+
o->agt_state = AWAITABLE_STATE_CLOSED;
2214+
}
2215+
return retval;
22122216
} else {
22132217
/* aclose() mode */
22142218
if (retval && _PyAsyncGenWrappedValue_CheckExact(retval)) {
@@ -2218,6 +2222,9 @@ async_gen_athrow_throw(PyAsyncGenAThrow *o, PyObject *const *args, Py_ssize_t na
22182222
PyErr_SetString(PyExc_RuntimeError, ASYNC_GEN_IGNORED_EXIT_MSG);
22192223
return NULL;
22202224
}
2225+
if (retval == NULL) {
2226+
o->agt_state = AWAITABLE_STATE_CLOSED;
2227+
}
22212228
if (PyErr_ExceptionMatches(PyExc_StopAsyncIteration) ||
22222229
PyErr_ExceptionMatches(PyExc_GeneratorExit))
22232230
{

0 commit comments

Comments
 (0)