Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit e5c6992

Browse filesBrowse files
graingertblurb-it[bot]encukou
authored
GH-117714: implement athrow().close() and asend().close() using throw (GH-117906)
* GH-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 <encukou@gmail.com> --------- Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> Co-authored-by: Petr Viktorin <encukou@gmail.com>
1 parent 1ff626e commit e5c6992
Copy full SHA for e5c6992

File tree

3 files changed

+87
-4
lines changed
Filter options

3 files changed

+87
-4
lines changed

‎Lib/test/test_asyncgen.py

Copy file name to clipboardExpand all lines: Lib/test/test_asyncgen.py
+48Lines 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

+1Lines 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

Copy file name to clipboardExpand all lines: Objects/genobject.c
+38-4Lines 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 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.