From 31c2e9ec97581fedfbfb0e44e1756676abc938a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Mon, 13 Jan 2025 12:43:01 +0100 Subject: [PATCH 1/4] clear `StopAsyncIteration` before calling `_PyGen_SetStopIterationValue` --- Objects/genobject.c | 1 + Objects/iterobject.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/Objects/genobject.c b/Objects/genobject.c index e87f199c2504ba..a4872de296e2cf 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -633,6 +633,7 @@ gen_iternext(PyObject *self) int _PyGen_SetStopIterationValue(PyObject *value) { + assert(!PyErr_Occurred()); PyObject *e; if (value == NULL || diff --git a/Objects/iterobject.c b/Objects/iterobject.c index 135ced9ea1f268..ebb342ff109222 100644 --- a/Objects/iterobject.c +++ b/Objects/iterobject.c @@ -384,6 +384,7 @@ anextawaitable_iternext(anextawaitableobject *obj) return result; } if (PyErr_ExceptionMatches(PyExc_StopAsyncIteration)) { + PyErr_Clear(); _PyGen_SetStopIterationValue(obj->default_value); } return NULL; @@ -407,6 +408,7 @@ anextawaitable_proxy(anextawaitableobject *obj, char *meth, PyObject *arg) { * exception we replace it with a `StopIteration(default)`, as if * it was the return value of `__anext__()` coroutine. */ + PyErr_Clear(); _PyGen_SetStopIterationValue(obj->default_value); } return NULL; From 5db01cd3c20b6d73be8f76cba75b210c65f688b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Mon, 13 Jan 2025 12:48:39 +0100 Subject: [PATCH 2/4] blurb --- .../2025-01-13-12-48-30.gh-issue-128078.qOsl9B.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2025-01-13-12-48-30.gh-issue-128078.qOsl9B.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-01-13-12-48-30.gh-issue-128078.qOsl9B.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-01-13-12-48-30.gh-issue-128078.qOsl9B.rst new file mode 100644 index 00000000000000..498864a0aa3145 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-01-13-12-48-30.gh-issue-128078.qOsl9B.rst @@ -0,0 +1,2 @@ +Fix a :exc:`SystemError` when using :func:`anext` with a default tuple +value. Patch by Bénédikt Tran. From e115e173255fd10889a1284312f3c17e6c99958f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Mon, 13 Jan 2025 12:48:53 +0100 Subject: [PATCH 3/4] tests --- Lib/test/test_asyncgen.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Lib/test/test_asyncgen.py b/Lib/test/test_asyncgen.py index 5bfd789185c675..e9b741556ed0d5 100644 --- a/Lib/test/test_asyncgen.py +++ b/Lib/test/test_asyncgen.py @@ -1152,6 +1152,24 @@ async def run(): self.loop.run_until_complete(run()) + def test_async_gen_asyncio_anext_tuple_no_exceptions(self): + # StopAsyncIteration exceptions should be cleared. + # See: https://github.com/python/cpython/issues/128078. + + async def foo(): + if False: + yield (1, 2) + + async def run(): + it = foo().__aiter__() + with self.assertRaises(StopAsyncIteration): + await it.__anext__() + a, b = await anext(it, ('a', 'b')) + self.assertEqual(a, 'a') + self.assertEqual(b, 'b') + + self.loop.run_until_complete(run()) + def test_async_gen_asyncio_anext_stopiteration(self): async def foo(): try: From 933324363a12bcdce6f58f2e5dc8b22ad7ea8bf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Mon, 13 Jan 2025 13:28:30 +0100 Subject: [PATCH 4/4] Update Lib/test/test_asyncgen.py Co-authored-by: Kumar Aditya --- Lib/test/test_asyncgen.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_asyncgen.py b/Lib/test/test_asyncgen.py index e9b741556ed0d5..3f631a03c9bf72 100644 --- a/Lib/test/test_asyncgen.py +++ b/Lib/test/test_asyncgen.py @@ -1164,9 +1164,8 @@ async def run(): it = foo().__aiter__() with self.assertRaises(StopAsyncIteration): await it.__anext__() - a, b = await anext(it, ('a', 'b')) - self.assertEqual(a, 'a') - self.assertEqual(b, 'b') + res = await anext(it, ('a', 'b')) + self.assertEqual(res, ('a', 'b')) self.loop.run_until_complete(run())