From 6f2c02970ddcd3ea3f854b07525ff3dcafc53d36 Mon Sep 17 00:00:00 2001 From: Timofey Ivankov Date: Mon, 2 Nov 2026 13:12:17 +0300 Subject: [PATCH 1/4] gh-161166: Fix incorrect exception line in asyncio.Task.print_stack() --- Lib/asyncio/base_tasks.py | 11 +++++++++-- Lib/test/test_asyncio/test_tasks.py | 15 +++++++++++++++ ...2026-11-02-13-11-30.gh-issue-161166.zfFDlW.rst | 2 ++ 3 files changed, 26 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-11-02-13-11-30.gh-issue-161166.zfFDlW.rst diff --git a/Lib/asyncio/base_tasks.py b/Lib/asyncio/base_tasks.py index c907b6834137325..902a4c84422b9ec 100644 --- a/Lib/asyncio/base_tasks.py +++ b/Lib/asyncio/base_tasks.py @@ -67,10 +67,18 @@ def _task_get_stack(task, limit): def _task_print_stack(task, limit, file): + # gh-161166: use the traceback line number instead of the frame’s current line number + # because it can give false exception causes + exc = task._exception + tb = exc.__traceback__ if exc is not None else None extracted_list = [] checked = set() for f in task.get_stack(limit=limit): - lineno = f.f_lineno + if tb is not None: + lineno = tb.tb_lineno + tb = tb.tb_next + else: + lineno = f.f_lineno co = f.f_code filename = co.co_filename name = co.co_name @@ -80,7 +88,6 @@ def _task_print_stack(task, limit, file): line = linecache.getline(filename, lineno, f.f_globals) extracted_list.append((filename, lineno, name, line)) - exc = task._exception if not extracted_list: print(f'No stack for {task!r}', file=file) elif exc is not None: diff --git a/Lib/test/test_asyncio/test_tasks.py b/Lib/test/test_asyncio/test_tasks.py index d4d3863923e79e6..744635a71b16012 100644 --- a/Lib/test/test_asyncio/test_tasks.py +++ b/Lib/test/test_asyncio/test_tasks.py @@ -335,6 +335,21 @@ async def runner(): self.loop.run_until_complete(runner()) + def test_print_stack_exception_lineno(self): + # gh-161166 + async def coro(): + try: + 1 / 0 + finally: + cleaned = True + + task = self.new_task(self.loop, coro()) + test_utils.run_briefly(self.loop) + task.exception() + file = io.StringIO() + task.print_stack(file=file) + self.assertIn(' 1 / 0\n', file.getvalue()) + def test_task_repr(self): self.loop.set_debug(False) diff --git a/Misc/NEWS.d/next/Library/2026-11-02-13-11-30.gh-issue-161166.zfFDlW.rst b/Misc/NEWS.d/next/Library/2026-11-02-13-11-30.gh-issue-161166.zfFDlW.rst new file mode 100644 index 000000000000000..e012dfb7e235854 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-11-02-13-11-30.gh-issue-161166.zfFDlW.rst @@ -0,0 +1,2 @@ +Fix :meth:asyncio.Task.print_stack displaying an incorrect exception line +after a finally block. Patch by Timofei Ivankov. From 89a164d993fa679f7e15db93c84adf0c8f40f0dd Mon Sep 17 00:00:00 2001 From: Timofey Ivankov Date: Mon, 2 Nov 2026 13:24:57 +0300 Subject: [PATCH 2/4] fix lint --- .../Library/2026-11-02-13-11-30.gh-issue-161166.zfFDlW.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS.d/next/Library/2026-11-02-13-11-30.gh-issue-161166.zfFDlW.rst b/Misc/NEWS.d/next/Library/2026-11-02-13-11-30.gh-issue-161166.zfFDlW.rst index e012dfb7e235854..4d66a399f5e6550 100644 --- a/Misc/NEWS.d/next/Library/2026-11-02-13-11-30.gh-issue-161166.zfFDlW.rst +++ b/Misc/NEWS.d/next/Library/2026-11-02-13-11-30.gh-issue-161166.zfFDlW.rst @@ -1,2 +1,2 @@ -Fix :meth:asyncio.Task.print_stack displaying an incorrect exception line -after a finally block. Patch by Timofei Ivankov. +Fix :meth:`asyncio.Task.print_stack` displaying an incorrect exception line +after a ``finally`` block. Patch by Timofei Ivankov. From f1a0f958201615aba6d1bb5ddd644e57efb5aa81 Mon Sep 17 00:00:00 2001 From: Timofey Ivankov Date: Mon, 2 Nov 2026 17:40:32 +0300 Subject: [PATCH 3/4] remove comment --- Lib/asyncio/base_tasks.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/Lib/asyncio/base_tasks.py b/Lib/asyncio/base_tasks.py index 902a4c84422b9ec..d588be96fb0f6e7 100644 --- a/Lib/asyncio/base_tasks.py +++ b/Lib/asyncio/base_tasks.py @@ -67,8 +67,6 @@ def _task_get_stack(task, limit): def _task_print_stack(task, limit, file): - # gh-161166: use the traceback line number instead of the frame’s current line number - # because it can give false exception causes exc = task._exception tb = exc.__traceback__ if exc is not None else None extracted_list = [] From 7b35cc8c7e3733bb9edee0dc5ab1ab4cfb4dc98c Mon Sep 17 00:00:00 2001 From: Timofey Ivankov Date: Mon, 2 Nov 2026 17:57:52 +0300 Subject: [PATCH 4/4] fix lint --- Lib/test/test_asyncio/test_tasks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_asyncio/test_tasks.py b/Lib/test/test_asyncio/test_tasks.py index af7dda6f29ddec0..f16815474e2d196 100644 --- a/Lib/test/test_asyncio/test_tasks.py +++ b/Lib/test/test_asyncio/test_tasks.py @@ -349,7 +349,7 @@ async def coro(): file = io.StringIO() task.print_stack(file=file) self.assertIn(' 1 / 0\n', file.getvalue()) - + def test_get_stack_async_generator(self): # gh-161178 async def gen():