From b52866953a64c5e0fe57784fbcfc6bec87861563 Mon Sep 17 00:00:00 2001 From: Tian Gao Date: Wed, 12 Mar 2025 17:23:53 -0400 Subject: gh-131123: Support completion in `pdb` for convenience variable attributes (#131124) --- Lib/pdb.py | 13 ++++++++----- Lib/test/test_pdb.py | 19 +++++++++++++++++++ .../2025-03-11-23-58-45.gh-issue-131123.WB6tPh.rst | 1 + 3 files changed, 28 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2025-03-11-23-58-45.gh-issue-131123.WB6tPh.rst diff --git a/Lib/pdb.py b/Lib/pdb.py index 75fc290..2842f3d 100644 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -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)] diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index 94332f1..910b8fc 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -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'