aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--Lib/pdb.py41
-rw-r--r--Lib/test/test_pdb.py28
-rw-r--r--Misc/NEWS.d/next/Library/2025-04-29-23-20-52.gh-issue-133153.M-w9yC.rst1
3 files changed, 60 insertions, 10 deletions
diff --git a/Lib/pdb.py b/Lib/pdb.py
index e2c7468c50c..343cf4404d7 100644
--- a/Lib/pdb.py
+++ b/Lib/pdb.py
@@ -1157,6 +1157,22 @@ class Pdb(bdb.Bdb, cmd.Cmd):
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 @@ class Pdb(bdb.Bdb, cmd.Cmd):
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 @@ class _PdbServer(Pdb):
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 ae84fe3ce7d..be365a5a3dd 100644
--- a/Lib/test/test_pdb.py
+++ b/Lib/test/test_pdb.py
@@ -4855,6 +4855,34 @@ class PdbTestReadline(unittest.TestCase):
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"
+ # Let's define a function to test <tab>
+ 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
+ input += b"c\n"
+
+ output = run_pty(script, input)
+
+ self.assertIn(b"'disp' is not defined", output)
+ self.assertIn(b'special', output)
+ self.assertIn(b'84', output)
+
def load_tests(loader, tests, pattern):
from test import test_pdb
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 00000000000..c609fa698dc
--- /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`.