From 296fd8acd2b3d438107147ce14c578dd15d1f483 Mon Sep 17 00:00:00 2001 From: Tian Gao Date: Tue, 29 Apr 2025 19:17:17 -0400 Subject: [PATCH 1/4] Use rlcompleter for pdb's interact command --- Lib/pdb.py | 41 +++++++++++++++++++++++++++++++---------- Lib/test/test_pdb.py | 22 ++++++++++++++++++++++ 2 files changed, 53 insertions(+), 10 deletions(-) diff --git a/Lib/pdb.py b/Lib/pdb.py index e38621d4533e14..b02f0df544c18e 100644 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -1157,6 +1157,22 @@ def completedefault(self, text, line, begidx, endidx): state += 1 return matches + @contextmanager + def _enable_rlcompleter(self, ns): + try: + import readline + except ImportError: + yield + return + + try: + old_completer = readline.get_completer() + completer = Completer(ns) + readline.set_completer(completer.complete) + yield + finally: + readline.set_completer(old_completer) + # Pdb meta commands, only intended to be used internally by pdb def _pdbcmd_print_frame_status(self, arg): @@ -2242,9 +2258,10 @@ def do_interact(self, arg): contains all the (global and local) names found in the current scope. """ ns = {**self.curframe.f_globals, **self.curframe.f_locals} - console = _PdbInteractiveConsole(ns, message=self.message) - console.interact(banner="*pdb interact start*", - exitmsg="*exit from pdb interact command*") + with self._enable_rlcompleter(ns): + console = _PdbInteractiveConsole(ns, message=self.message) + console.interact(banner="*pdb interact start*", + exitmsg="*exit from pdb interact command*") def do_alias(self, arg): """alias [name [command]] @@ -2749,14 +2766,18 @@ def _read_reply(self): self.error(f"Ignoring invalid message from client: {msg}") def _complete_any(self, text, line, begidx, endidx): - if begidx == 0: - return self.completenames(text, line, begidx, endidx) - - cmd = self.parseline(line)[0] - if cmd: - compfunc = getattr(self, "complete_" + cmd, self.completedefault) - else: + # If we're in 'interact' mode, we need to use the default completer + if self._interact_state: compfunc = self.completedefault + else: + if begidx == 0: + return self.completenames(text, line, begidx, endidx) + + cmd = self.parseline(line)[0] + if cmd: + compfunc = getattr(self, "complete_" + cmd, self.completedefault) + else: + compfunc = self.completedefault return compfunc(text, line, begidx, endidx) def cmdloop(self, intro=None): diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index ae84fe3ce7d65a..b6f0ef991c2233 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -4855,6 +4855,28 @@ def func(): self.assertIn(b'4', output) self.assertNotIn(b'Error', output) + def test_interact_completion(self): + script = textwrap.dedent(""" + value = "speci" + import pdb; pdb.Pdb().set_trace() + """) + + # Enter interact mode + input = b"interact\n" + # Should fail to complete 'display' because that's a pdb command + input += b"disp\t\n" + # 'value' should still work + input += b"val\t + 'al'\n" + # Exit interact mode + input += b"exit()\n" + # continue + input += b"c\n" + + output = run_pty(script, input) + + self.assertIn(b"'disp' is not defined", output) + self.assertIn(b'special', output) + def load_tests(loader, tests, pattern): from test import test_pdb From eb8f22fb7072e72fb50e931a9fd5ba85efac0b15 Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Tue, 29 Apr 2025 23:20:56 +0000 Subject: [PATCH 2/4] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../next/Library/2025-04-29-23-20-52.gh-issue-133153.M-w9yC.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Library/2025-04-29-23-20-52.gh-issue-133153.M-w9yC.rst diff --git a/Misc/NEWS.d/next/Library/2025-04-29-23-20-52.gh-issue-133153.M-w9yC.rst b/Misc/NEWS.d/next/Library/2025-04-29-23-20-52.gh-issue-133153.M-w9yC.rst new file mode 100644 index 00000000000000..5de164ec5dc937 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-04-29-23-20-52.gh-issue-133153.M-w9yC.rst @@ -0,0 +1 @@ +Do not complete :mod:`pdb commands in ``interact`` mode of :mod:`pdb`. From 476f8f84f03170fda8cf78beaeaab26765388e6f Mon Sep 17 00:00:00 2001 From: Tian Gao Date: Tue, 29 Apr 2025 19:27:56 -0400 Subject: [PATCH 3/4] Update 2025-04-29-23-20-52.gh-issue-133153.M-w9yC.rst --- .../next/Library/2025-04-29-23-20-52.gh-issue-133153.M-w9yC.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2025-04-29-23-20-52.gh-issue-133153.M-w9yC.rst b/Misc/NEWS.d/next/Library/2025-04-29-23-20-52.gh-issue-133153.M-w9yC.rst index 5de164ec5dc937..c609fa698dca49 100644 --- a/Misc/NEWS.d/next/Library/2025-04-29-23-20-52.gh-issue-133153.M-w9yC.rst +++ b/Misc/NEWS.d/next/Library/2025-04-29-23-20-52.gh-issue-133153.M-w9yC.rst @@ -1 +1 @@ -Do not complete :mod:`pdb commands in ``interact`` mode of :mod:`pdb`. +Do not complete :mod:`pdb` commands in ``interact`` mode of :mod:`pdb`. From f961cf9a9a9f7d5a1091804c6ca16e79235dfdc2 Mon Sep 17 00:00:00 2001 From: Tian Gao Date: Wed, 30 Apr 2025 17:25:10 -0400 Subject: [PATCH 4/4] Add extra tests for tab at the beginning --- Lib/test/test_pdb.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index b6f0ef991c2233..be365a5a3ddeec 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -4867,6 +4867,11 @@ def test_interact_completion(self): input += b"disp\t\n" # 'value' should still work input += b"val\t + 'al'\n" + # Let's define a function to test + input += b"def f():\n" + input += b"\treturn 42\n" + input += b"\n" + input += b"f() * 2\n" # Exit interact mode input += b"exit()\n" # continue @@ -4876,6 +4881,7 @@ def test_interact_completion(self): self.assertIn(b"'disp' is not defined", output) self.assertIn(b'special', output) + self.assertIn(b'84', output) def load_tests(loader, tests, pattern):