mirror of
https://github.com/python/cpython.git
synced 2025-12-31 04:23:37 +00:00
gh-133153: Use rlcompleter for pdb's interact command (#133176)
This commit is contained in:
parent
0e21ed7c09
commit
327f5ff9fa
3 changed files with 60 additions and 10 deletions
41
Lib/pdb.py
41
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):
|
||||
|
|
|
|||
|
|
@ -4855,6 +4855,34 @@ 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"
|
||||
# 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
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
Do not complete :mod:`pdb` commands in ``interact`` mode of :mod:`pdb`.
|
||||
Loading…
Add table
Add a link
Reference in a new issue