]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-121468: Add current asyncio task as a convenience variable in pdb (#124367)
authorTian Gao <gaogaotiantian@hotmail.com>
Fri, 14 Mar 2025 18:46:26 +0000 (14:46 -0400)
committerGitHub <noreply@github.com>
Fri, 14 Mar 2025 18:46:26 +0000 (14:46 -0400)
Doc/library/pdb.rst
Doc/whatsnew/3.14.rst
Lib/pdb.py
Lib/test/test_pdb.py
Misc/NEWS.d/next/Library/2025-03-11-21-52-33.gh-issue-121468.WsEP02.rst [new file with mode: 0644]

index 1c92398677d04820744842c2839e9f9b03e76064..c4ddff378d9c838409458c8c6f82b2e17601994e 100644 (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
index 65ab57eb821c6c90d728f9b74bbd1324eeb718e6..b133719063652906f0204ae8c386579a85f4d132 100644 (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
 ------
index 2842f3d497b9782c8996fcd28eb520dd1746e8d1..0357e46ead3ec8ec200cb4f19a594a2a0008f78d 100644 (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"
index 910b8fcb74d1e3348ad6f6e35ffd66c3acc50d28..87afe093e7730e23eb257b78111a13945f097b64 100644 (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
 
diff --git a/Misc/NEWS.d/next/Library/2025-03-11-21-52-33.gh-issue-121468.WsEP02.rst b/Misc/NEWS.d/next/Library/2025-03-11-21-52-33.gh-issue-121468.WsEP02.rst
new file mode 100644 (file)
index 0000000..833f156
--- /dev/null
@@ -0,0 +1,2 @@
+``$_asynctask`` is added as a :mod:`pdb` convenience variable to
+access the current asyncio task if applicable.