Skip to content

Commit b5b09e5

Browse files
graingertblurb-it[bot]encukou
authored andcommitted
pythonGH-117714: implement athrow().close() and asend().close() using throw (pythonGH-117906)
* pythonGH-117714: replace athrow().close() and asend().close() stubs with implimentations * test athrow().close() and asend().close() raises RuntimeError * 📜🤖 Added by blurb_it. * Update Objects/genobject.c Co-authored-by: Petr Viktorin <[email protected]> --------- Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> Co-authored-by: Petr Viktorin <[email protected]>
1 parent 80b23c9 commit b5b09e5

File tree

3 files changed

+87
-4
lines changed

3 files changed

+87
-4
lines changed

Lib/test/test_asyncgen.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -571,6 +571,54 @@ async def gen():
571571
self.assertTrue(inspect.isawaitable(aclose))
572572
aclose.close()
573573

574+
def test_async_gen_asend_close_runtime_error(self):
575+
import types
576+
577+
@types.coroutine
578+
def _async_yield(v):
579+
return (yield v)
580+
581+
async def agenfn():
582+
try:
583+
await _async_yield(None)
584+
except GeneratorExit:
585+
await _async_yield(None)
586+
return
587+
yield
588+
589+
agen = agenfn()
590+
gen = agen.asend(None)
591+
gen.send(None)
592+
with self.assertRaisesRegex(RuntimeError, "coroutine ignored GeneratorExit"):
593+
gen.close()
594+
595+
def test_async_gen_athrow_close_runtime_error(self):
596+
import types
597+
598+
@types.coroutine
599+
def _async_yield(v):
600+
return (yield v)
601+
602+
class MyExc(Exception):
603+
pass
604+
605+
async def agenfn():
606+
try:
607+
yield
608+
except MyExc:
609+
try:
610+
await _async_yield(None)
611+
except GeneratorExit:
612+
await _async_yield(None)
613+
614+
agen = agenfn()
615+
with self.assertRaises(StopIteration):
616+
agen.asend(None).send(None)
617+
gen = agen.athrow(MyExc)
618+
gen.send(None)
619+
with self.assertRaisesRegex(RuntimeError, "coroutine ignored GeneratorExit"):
620+
gen.close()
621+
574622

575623
class AsyncGenAsyncioTest(unittest.TestCase):
576624

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
update ``async_generator.athrow().close()`` and ``async_generator.asend().close()`` to close their section of the underlying async generator

Objects/genobject.c

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1846,8 +1846,25 @@ async_gen_asend_throw(PyAsyncGenASend *o, PyObject *const *args, Py_ssize_t narg
18461846
static PyObject *
18471847
async_gen_asend_close(PyAsyncGenASend *o, PyObject *args)
18481848
{
1849-
o->ags_state = AWAITABLE_STATE_CLOSED;
1850-
Py_RETURN_NONE;
1849+
PyObject *result;
1850+
if (o->ags_state == AWAITABLE_STATE_CLOSED) {
1851+
Py_RETURN_NONE;
1852+
}
1853+
result = async_gen_asend_throw(o, &PyExc_GeneratorExit, 1);
1854+
if (result == NULL) {
1855+
if (PyErr_ExceptionMatches(PyExc_StopIteration) ||
1856+
PyErr_ExceptionMatches(PyExc_StopAsyncIteration) ||
1857+
PyErr_ExceptionMatches(PyExc_GeneratorExit))
1858+
{
1859+
PyErr_Clear();
1860+
Py_RETURN_NONE;
1861+
}
1862+
return result;
1863+
} else {
1864+
Py_DECREF(result);
1865+
PyErr_SetString(PyExc_RuntimeError, "coroutine ignored GeneratorExit");
1866+
return NULL;
1867+
}
18511868
}
18521869

18531870
static void
@@ -2291,8 +2308,25 @@ async_gen_athrow_iternext(PyAsyncGenAThrow *o)
22912308
static PyObject *
22922309
async_gen_athrow_close(PyAsyncGenAThrow *o, PyObject *args)
22932310
{
2294-
o->agt_state = AWAITABLE_STATE_CLOSED;
2295-
Py_RETURN_NONE;
2311+
PyObject *result;
2312+
if (o->agt_state == AWAITABLE_STATE_CLOSED) {
2313+
Py_RETURN_NONE;
2314+
}
2315+
result = async_gen_athrow_throw(o, &PyExc_GeneratorExit, 1);
2316+
if (result == NULL) {
2317+
if (PyErr_ExceptionMatches(PyExc_StopIteration) ||
2318+
PyErr_ExceptionMatches(PyExc_StopAsyncIteration) ||
2319+
PyErr_ExceptionMatches(PyExc_GeneratorExit))
2320+
{
2321+
PyErr_Clear();
2322+
Py_RETURN_NONE;
2323+
}
2324+
return result;
2325+
} else {
2326+
Py_DECREF(result);
2327+
PyErr_SetString(PyExc_RuntimeError, "coroutine ignored GeneratorExit");
2328+
return NULL;
2329+
}
22962330
}
22972331

22982332

0 commit comments

Comments
 (0)