https://github.com/python/cpython/commit/e5c699280deac076cddfef37c8af917a550f6ac3
commit: e5c699280deac076cddfef37c8af917a550f6ac3
branch: main
author: Thomas Grainger <[email protected]>
committer: encukou <[email protected]>
date: 2024-05-06T17:13:15Z
summary:

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 <[email protected]>

---------

Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com>
Co-authored-by: Petr Viktorin <[email protected]>

files:
A Misc/NEWS.d/next/Core and 
Builtins/2024-05-01-07-06-48.gh-issue-117714.Ip_dm5.rst
M Lib/test/test_asyncgen.py
M Objects/genobject.c

diff --git a/Lib/test/test_asyncgen.py b/Lib/test/test_asyncgen.py
index 1985ede656e7a0..4f2278bb263681 100644
--- a/Lib/test/test_asyncgen.py
+++ b/Lib/test/test_asyncgen.py
@@ -571,6 +571,54 @@ async def gen():
         self.assertTrue(inspect.isawaitable(aclose))
         aclose.close()
 
+    def test_async_gen_asend_close_runtime_error(self):
+        import types
+
+        @types.coroutine
+        def _async_yield(v):
+            return (yield v)
+
+        async def agenfn():
+            try:
+                await _async_yield(None)
+            except GeneratorExit:
+                await _async_yield(None)
+            return
+            yield
+
+        agen = agenfn()
+        gen = agen.asend(None)
+        gen.send(None)
+        with self.assertRaisesRegex(RuntimeError, "coroutine ignored 
GeneratorExit"):
+            gen.close()
+
+    def test_async_gen_athrow_close_runtime_error(self):
+        import types
+
+        @types.coroutine
+        def _async_yield(v):
+            return (yield v)
+
+        class MyExc(Exception):
+            pass
+
+        async def agenfn():
+            try:
+                yield
+            except MyExc:
+                try:
+                    await _async_yield(None)
+                except GeneratorExit:
+                    await _async_yield(None)
+
+        agen = agenfn()
+        with self.assertRaises(StopIteration):
+            agen.asend(None).send(None)
+        gen = agen.athrow(MyExc)
+        gen.send(None)
+        with self.assertRaisesRegex(RuntimeError, "coroutine ignored 
GeneratorExit"):
+            gen.close()
+
 
 class AsyncGenAsyncioTest(unittest.TestCase):
 
diff --git a/Misc/NEWS.d/next/Core and 
Builtins/2024-05-01-07-06-48.gh-issue-117714.Ip_dm5.rst b/Misc/NEWS.d/next/Core 
and Builtins/2024-05-01-07-06-48.gh-issue-117714.Ip_dm5.rst
new file mode 100644
index 00000000000000..d8ec242fcb65b9
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and 
Builtins/2024-05-01-07-06-48.gh-issue-117714.Ip_dm5.rst 
@@ -0,0 +1 @@
+update ``async_generator.athrow().close()`` and 
``async_generator.asend().close()`` to close their section of the underlying 
async generator
diff --git a/Objects/genobject.c b/Objects/genobject.c
index 89bb21a8674b9f..acdcf579a940ef 100644
--- a/Objects/genobject.c
+++ b/Objects/genobject.c
@@ -1846,8 +1846,25 @@ async_gen_asend_throw(PyAsyncGenASend *o, PyObject 
*const *args, Py_ssize_t narg
 static PyObject *
 async_gen_asend_close(PyAsyncGenASend *o, PyObject *args)
 {
-    o->ags_state = AWAITABLE_STATE_CLOSED;
-    Py_RETURN_NONE;
+    PyObject *result;
+    if (o->ags_state == AWAITABLE_STATE_CLOSED) {
+        Py_RETURN_NONE;
+    }
+    result = async_gen_asend_throw(o, &PyExc_GeneratorExit, 1);
+    if (result == NULL) {
+        if (PyErr_ExceptionMatches(PyExc_StopIteration) ||
+            PyErr_ExceptionMatches(PyExc_StopAsyncIteration) ||
+            PyErr_ExceptionMatches(PyExc_GeneratorExit))
+        {
+            PyErr_Clear();
+            Py_RETURN_NONE;
+        }
+        return result;
+    } else {
+        Py_DECREF(result);
+        PyErr_SetString(PyExc_RuntimeError, "coroutine ignored GeneratorExit");
+        return NULL;
+    }
 }
 
 static void
@@ -2291,8 +2308,25 @@ async_gen_athrow_iternext(PyAsyncGenAThrow *o)
 static PyObject *
 async_gen_athrow_close(PyAsyncGenAThrow *o, PyObject *args)
 {
-    o->agt_state = AWAITABLE_STATE_CLOSED;
-    Py_RETURN_NONE;
+    PyObject *result;
+    if (o->agt_state == AWAITABLE_STATE_CLOSED) {
+        Py_RETURN_NONE;
+    }
+    result = async_gen_athrow_throw(o, &PyExc_GeneratorExit, 1);
+    if (result == NULL) {
+        if (PyErr_ExceptionMatches(PyExc_StopIteration) ||
+            PyErr_ExceptionMatches(PyExc_StopAsyncIteration) ||
+            PyErr_ExceptionMatches(PyExc_GeneratorExit))
+        {
+            PyErr_Clear();
+            Py_RETURN_NONE;
+        }
+        return result;
+    } else {
+        Py_DECREF(result);
+        PyErr_SetString(PyExc_RuntimeError, "coroutine ignored GeneratorExit");
+        return NULL;
+    }
 }
 
 

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]

Reply via email to