]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-131123: Support completion in `pdb` for convenience variable attributes (#131124)
authorTian Gao <gaogaotiantian@hotmail.com>
Wed, 12 Mar 2025 21:23:53 +0000 (17:23 -0400)
committerGitHub <noreply@github.com>
Wed, 12 Mar 2025 21:23:53 +0000 (17:23 -0400)
Lib/pdb.py
Lib/test/test_pdb.py
Misc/NEWS.d/next/Library/2025-03-11-23-58-45.gh-issue-131123.WB6tPh.rst [new file with mode: 0644]

index 75fc29068fa843908b7f3c93eac7b6ca28c0499d..2842f3d497b9782c8996fcd28eb520dd1746e8d1 100644 (file)
@@ -975,17 +975,16 @@ class Pdb(bdb.Bdb, cmd.Cmd):
         # complete builtins, and they clutter the namespace quite heavily, so we
         # leave them out.
         ns = {**self.curframe.f_globals, **self.curframe.f_locals}
-        if text.startswith("$"):
-            # Complete convenience variables
-            conv_vars = self.curframe.f_globals.get('__pdb_convenience_variables', {})
-            return [f"${name}" for name in conv_vars if name.startswith(text[1:])]
         if '.' in text:
             # Walk an attribute chain up to the last part, similar to what
             # rlcompleter does.  This will bail if any of the parts are not
             # simple attribute access, which is what we want.
             dotted = text.split('.')
             try:
-                obj = ns[dotted[0]]
+                if dotted[0].startswith('$'):
+                    obj = self.curframe.f_globals['__pdb_convenience_variables'][dotted[0][1:]]
+                else:
+                    obj = ns[dotted[0]]
                 for part in dotted[1:-1]:
                     obj = getattr(obj, part)
             except (KeyError, AttributeError):
@@ -993,6 +992,10 @@ class Pdb(bdb.Bdb, cmd.Cmd):
             prefix = '.'.join(dotted[:-1]) + '.'
             return [prefix + n for n in dir(obj) if n.startswith(dotted[-1])]
         else:
+            if text.startswith("$"):
+                # Complete convenience variables
+                conv_vars = self.curframe.f_globals.get('__pdb_convenience_variables', {})
+                return [f"${name}" for name in conv_vars if name.startswith(text[1:])]
             # Complete a simple name.
             return [n for n in ns.keys() if n.startswith(text)]
 
index 94332f1daee47960a6e95df9249c621f67a659ed..910b8fcb74d1e3348ad6f6e35ffd66c3acc50d28 100644 (file)
@@ -4478,6 +4478,25 @@ class PdbTestReadline(unittest.TestCase):
 
         self.assertIn(b'special', output)
 
+    def test_convvar_completion(self):
+        script = textwrap.dedent("""
+            import pdb; pdb.Pdb().set_trace()
+        """)
+
+        # Complete: $_frame
+        input = b"$_fram\t\n"
+
+        # Complete: $_frame.f_lineno + 100
+        input += b"$_frame.f_line\t + 100\n"
+
+        # Continue
+        input += b"c\n"
+
+        output = run_pty(script, input)
+
+        self.assertIn(b'<frame at 0x', output)
+        self.assertIn(b'102', output)
+
     def test_local_namespace(self):
         script = textwrap.dedent("""
             def f():
diff --git a/Misc/NEWS.d/next/Library/2025-03-11-23-58-45.gh-issue-131123.WB6tPh.rst b/Misc/NEWS.d/next/Library/2025-03-11-23-58-45.gh-issue-131123.WB6tPh.rst
new file mode 100644 (file)
index 0000000..b9ecc97
--- /dev/null
@@ -0,0 +1 @@
+Supported completions for attributes of convenience variables in :mod:`pdb`.