gh-121468: Add current asyncio task as a convenience variable in pdb (#124367)

This commit is contained in:
Tian Gao 2025-03-14 14:46:26 -04:00 committed by GitHub
parent c107b15ab8
commit 27fc62cf4f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 49 additions and 3 deletions

View file

@ -313,16 +313,20 @@ sets a global variable ``$foo`` which you can use in the debugger session. The
less likely to interfere with your program compared to using normal variables
like ``foo = 1``.
There are three preset *convenience variables*:
There are four preset *convenience variables*:
* ``$_frame``: the current frame you are debugging
* ``$_retval``: the return value if the frame is returning
* ``$_exception``: the exception if the frame is raising an exception
* ``$_asynctask``: the asyncio task if pdb stops in an async function
.. versionadded:: 3.12
Added the *convenience variable* feature.
.. versionadded:: 3.14
Added the ``$_asynctask`` convenience variable.
.. index::
pair: .pdbrc; file
triple: debugger; configuration; file

View file

@ -830,6 +830,9 @@ pdb
fill in a 4-space indentation now, instead of inserting a ``\t`` character.
(Contributed by Tian Gao in :gh:`130471`.)
* ``$_asynctask`` is added to access the current asyncio task if applicable.
(Contributed by Tian Gao in :gh:`124367`.)
pickle
------

View file

@ -79,6 +79,7 @@ import types
import codeop
import pprint
import signal
import asyncio
import inspect
import textwrap
import tokenize
@ -363,6 +364,8 @@ class Pdb(bdb.Bdb, cmd.Cmd):
self._chained_exceptions = tuple()
self._chained_exception_index = 0
self._current_task = None
def set_trace(self, frame=None, *, commands=None):
Pdb._last_pdb_instance = self
if frame is None:
@ -405,7 +408,8 @@ class Pdb(bdb.Bdb, cmd.Cmd):
tb = tb.tb_next
self.curframe = self.stack[self.curindex][0]
self.set_convenience_variable(self.curframe, '_frame', self.curframe)
if self._current_task:
self.set_convenience_variable(self.curframe, '_asynctask', self._current_task)
self._save_initial_file_mtime(self.curframe)
if self._chained_exceptions:
@ -616,6 +620,13 @@ class Pdb(bdb.Bdb, cmd.Cmd):
self._chained_exceptions = tuple()
self._chained_exception_index = 0
def _get_asyncio_task(self):
try:
task = asyncio.current_task()
except RuntimeError:
task = None
return task
def interaction(self, frame, tb_or_exc):
# Restore the previous signal handler at the Pdb prompt.
if Pdb._previous_sigint_handler:
@ -626,6 +637,8 @@ class Pdb(bdb.Bdb, cmd.Cmd):
else:
Pdb._previous_sigint_handler = None
self._current_task = self._get_asyncio_task()
_chained_exceptions, tb = self._get_tb_and_exceptions(tb_or_exc)
if isinstance(tb_or_exc, BaseException):
assert tb is not None, "main exception must have a traceback"

View file

@ -16,7 +16,7 @@ import zipfile
from contextlib import ExitStack, redirect_stdout
from io import StringIO
from test import support
from test.support import force_not_colorized, os_helper
from test.support import force_not_colorized, has_socket_support, os_helper
from test.support.import_helper import import_module
from test.support.pty_helper import run_pty, FakeInput
from test.support.script_helper import kill_python
@ -2059,6 +2059,30 @@ def test_pdb_next_command_for_generator():
"""
if not SKIP_CORO_TESTS:
if has_socket_support:
def test_pdb_asynctask():
"""Testing $_asynctask is accessible in async context
>>> import asyncio
>>> async def test():
... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace()
>>> def test_function():
... asyncio.run(test())
>>> with PdbTestInput([ # doctest: +ELLIPSIS
... '$_asynctask',
... 'continue',
... ]):
... test_function()
> <doctest test.test_pdb.test_pdb_asynctask[1]>(2)test()
-> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace()
(Pdb) $_asynctask
<Task pending name='Task-1' coro=<test() running at <doctest test.test_pdb.test_pdb_asynctask[1]>:2> ...
(Pdb) continue
"""
def test_pdb_next_command_for_coroutine():
"""Testing skip unwinding stack on yield for coroutines for "next" command

View file

@ -0,0 +1,2 @@
``$_asynctask`` is added as a :mod:`pdb` convenience variable to
access the current asyncio task if applicable.