Skip to content

Commit c23190e

Browse files
Use pyrepl for pdb
1 parent 1ac9d13 commit c23190e

File tree

1 file changed

+63
-1
lines changed

1 file changed

+63
-1
lines changed

Lib/pdb.py

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@
9191
import tempfile
9292
import textwrap
9393
import tokenize
94+
import functools
9495
import itertools
9596
import traceback
9697
import linecache
@@ -348,6 +349,37 @@ def get_default_backend():
348349
return _default_backend
349350

350351

352+
class PdbPyReplInput:
353+
def __init__(self, pdb_instance, prompt):
354+
from _pyrepl.readline import _setup
355+
self.pdb_instance = pdb_instance
356+
self.prompt = prompt
357+
self.console = code.InteractiveConsole()
358+
_setup({})
359+
360+
def readline(self):
361+
from _pyrepl.simple_interact import _more_lines
362+
from _pyrepl.readline import get_completer, multiline_input, set_completer
363+
364+
def more_lines(text):
365+
cmd, _, line = self.pdb_instance.parseline(text)
366+
if not line or not cmd:
367+
return False
368+
func = getattr(self.pdb_instance, 'do_' + cmd, None)
369+
if func is not None:
370+
return False
371+
return _more_lines(self.console, text)
372+
373+
try:
374+
pyrepl_completer = get_completer()
375+
set_completer(self.pdb_instance.complete)
376+
return multiline_input(more_lines, self.prompt, '... ') + '\n'
377+
except EOFError:
378+
return 'EOF'
379+
finally:
380+
set_completer(pyrepl_completer)
381+
382+
351383
class Pdb(bdb.Bdb, cmd.Cmd):
352384
_previous_sigint_handler = None
353385

@@ -382,6 +414,10 @@ def __init__(self, completekey='tab', stdin=None, stdout=None, skip=None,
382414
except ImportError:
383415
pass
384416

417+
if self.use_rawinput and stdin is None:
418+
self.pyrepl_input = PdbPyReplInput(self, self.prompt)
419+
else:
420+
self.pyrepl_input = None
385421
self.allow_kbdint = False
386422
self.nosigint = nosigint
387423
# Consider these characters as part of the command so when the users type
@@ -620,14 +656,40 @@ def user_exception(self, frame, exc_info):
620656
self.message('%s%s' % (prefix, self._format_exc(exc_value)))
621657
self.interaction(frame, exc_traceback)
622658

659+
@contextmanager
660+
def _replace_attribute(self, attrs):
661+
original_attrs = {}
662+
for attr, value in attrs.items():
663+
original_attrs[attr] = getattr(self, attr)
664+
setattr(self, attr, value)
665+
try:
666+
yield
667+
finally:
668+
for attr, value in original_attrs.items():
669+
setattr(self, attr, value)
670+
671+
@contextmanager
672+
def _maybe_use_pyrepl_as_stdin(self):
673+
if self.pyrepl_input is None:
674+
yield
675+
return
676+
677+
with self._replace_attribute({
678+
'stdin': self.pyrepl_input,
679+
'use_rawinput': False,
680+
'prompt': '',
681+
}):
682+
yield
683+
623684
# General interaction function
624685
def _cmdloop(self):
625686
while True:
626687
try:
627688
# keyboard interrupts allow for an easy way to cancel
628689
# the current command, so allow them during interactive input
629690
self.allow_kbdint = True
630-
self.cmdloop()
691+
with self._maybe_use_pyrepl_as_stdin():
692+
self.cmdloop()
631693
self.allow_kbdint = False
632694
break
633695
except KeyboardInterrupt:

0 commit comments

Comments
 (0)