From c0e9deee075d2eda54d110cfcedd4ab665b62bf6 Mon Sep 17 00:00:00 2001 From: iaroslav <98962283+iaroslavkrasikov@users.noreply.github.com> Date: Tue, 28 Jul 2026 08:06:39 +0500 Subject: [PATCH 1/2] gh-154791: Fix asyncio Future losing traceback on repeated result() calls --- Lib/test/test_asyncio/test_futures2.py | 20 +++++++++++++++++++ ...-07-28-08-02-41.gh-issue-154791.ey7POa.rst | 4 ++++ Modules/_asynciomodule.c | 1 - 3 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-28-08-02-41.gh-issue-154791.ey7POa.rst diff --git a/Lib/test/test_asyncio/test_futures2.py b/Lib/test/test_asyncio/test_futures2.py index cf90835ce87cc30..1878cf8adf63a3b 100644 --- a/Lib/test/test_asyncio/test_futures2.py +++ b/Lib/test/test_asyncio/test_futures2.py @@ -28,6 +28,26 @@ async def raise_exc(): else: self.fail('TypeError was not raised') + async def test_future_traceback_preserved_after_suppress(self): + async def raise_exc(): + raise TypeError(42) + + future = self.cls(raise_exc()) + try: + await future + except TypeError: + pass + + try: + await future + except TypeError as e: + tb = ''.join(traceback.format_tb(e.__traceback__)) + self.assertIn('raise_exc', tb, + 'Original raise site lost after first result() call') + else: + self.fail('TypeError was not raised') + + async def test_task_exc_handler_correct_context(self): # see https://github.com/python/cpython/issues/96704 name = contextvars.ContextVar('name', default='foo') diff --git a/Misc/NEWS.d/next/Library/2026-07-28-08-02-41.gh-issue-154791.ey7POa.rst b/Misc/NEWS.d/next/Library/2026-07-28-08-02-41.gh-issue-154791.ey7POa.rst new file mode 100644 index 000000000000000..cb6a7e19b4477f9 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-28-08-02-41.gh-issue-154791.ey7POa.rst @@ -0,0 +1,4 @@ +Fix `asyncio._CFuture` losing the initial exception traceback frames when +`Future.result()` is called more than once. Previously, the C implementation +cleared the stored traceback after the first call, causing subsequent raises +to omit the original raise site. The Python implementation was unaffected. diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c index 0cd41d0b4c4d0dc..ec6f35f161136c1 100644 --- a/Modules/_asynciomodule.c +++ b/Modules/_asynciomodule.c @@ -769,7 +769,6 @@ future_get_result(asyncio_state *state, FutureObj *fut, PyObject **result) return -1; } *result = Py_NewRef(fut->fut_exception); - Py_CLEAR(fut->fut_exception_tb); return 1; } From b4a11722d149cff6fc79b98665ea10aa8fd2ff93 Mon Sep 17 00:00:00 2001 From: iaroslav <98962283+iaroslavkrasikov@users.noreply.github.com> Date: Tue, 28 Jul 2026 17:54:26 +0500 Subject: [PATCH 2/2] Fix NEWS note --- .../2026-07-28-08-02-41.gh-issue-154791.ey7POa.rst | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Misc/NEWS.d/next/Library/2026-07-28-08-02-41.gh-issue-154791.ey7POa.rst b/Misc/NEWS.d/next/Library/2026-07-28-08-02-41.gh-issue-154791.ey7POa.rst index cb6a7e19b4477f9..35008e35314b907 100644 --- a/Misc/NEWS.d/next/Library/2026-07-28-08-02-41.gh-issue-154791.ey7POa.rst +++ b/Misc/NEWS.d/next/Library/2026-07-28-08-02-41.gh-issue-154791.ey7POa.rst @@ -1,4 +1,5 @@ -Fix `asyncio._CFuture` losing the initial exception traceback frames when -`Future.result()` is called more than once. Previously, the C implementation -cleared the stored traceback after the first call, causing subsequent raises -to omit the original raise site. The Python implementation was unaffected. +Fix :class:`asyncio.Future` (C implementation) losing the initial exception +traceback frames when ``Future.result()`` is called more than once. Previously, +the C implementation cleared the stored traceback after the first call, causing +subsequent raises to omit the original raise site. The pure-Python +implementation was unaffected.