@@ -318,12 +318,34 @@ def namespace(self):
318318
319319
320320class _PdbInteractiveConsole (code .InteractiveConsole ):
321- def __init__ (self , ns , message ):
321+ def __init__ (self , ns = None , message = None ):
322322 self ._message = message
323323 super ().__init__ (locals = ns , local_exit = True )
324324
325325 def write (self , data ):
326- self ._message (data , end = '' )
326+ if self ._message is not None :
327+ self ._message (data , end = '' )
328+ else :
329+ super ().write (data )
330+
331+ def more_lines (self , text ):
332+ # Generic Python multi-line completeness heuristic.
333+ # Strips pyrepl's trailing auto-indent before compiling.
334+ # This should be functionally identical to simple_interact._more_lines
335+ src = text .rstrip (" \t " )
336+ n = len (src )
337+ if n > 0 and text [n - 1 ] == '\n ' :
338+ text = src
339+ try :
340+ code_obj = self .compile (text , "<stdin>" , "single" )
341+ except (OverflowError , SyntaxError , ValueError ):
342+ lines = text .splitlines (keepends = True )
343+ if len (lines ) == 1 :
344+ return False
345+ last = lines [- 1 ]
346+ return ((last .startswith ((" " , "\t " )) or last .strip () != "" )
347+ and not last .endswith ("\n " ))
348+ return code_obj is None
327349
328350
329351# Interaction prompt line will separate file and call info from code
@@ -355,10 +377,13 @@ def get_default_backend():
355377def _pyrepl_available ():
356378 """return whether pdb should use _pyrepl for input"""
357379 if not os .getenv ("PYTHON_BASIC_REPL" ):
358- from _pyrepl .main import CAN_USE_PYREPL
359-
360- return CAN_USE_PYREPL
361- return False
380+ CAN_USE_PYREPL = False
381+ else :
382+ try :
383+ from _pyrepl .main import CAN_USE_PYREPL
384+ except ModuleNotFoundError :
385+ CAN_USE_PYREPL = False
386+ return CAN_USE_PYREPL
362387
363388
364389class PdbPyReplInput :
@@ -367,7 +392,7 @@ def __init__(self, pdb_instance, stdin, stdout, prompt):
367392
368393 self .pdb_instance = pdb_instance
369394 self .prompt = prompt
370- self .console = code . InteractiveConsole ()
395+ self .console = _PdbInteractiveConsole ()
371396 if not (os .isatty (stdin .fileno ())):
372397 raise ValueError ("stdin is not a TTY" )
373398 self .readline_wrapper = _pyrepl .readline ._ReadlineWrapper (
@@ -377,9 +402,12 @@ def __init__(self, pdb_instance, stdin, stdout, prompt):
377402 completer_delims = frozenset (' \t \n `@#%^&*()=+[{]}\\ |;:\' ",<>?' )
378403 )
379404 )
405+ try :
406+ self .readline_wrapper .read_history_file ()
407+ except (FileNotFoundError , PermissionError , OSError ):
408+ pass
380409
381410 def readline (self ):
382- from _pyrepl .simple_interact import _more_lines
383411
384412 def more_lines (text ):
385413 if text .strip () == "\x1a " :
@@ -392,18 +420,24 @@ def more_lines(text):
392420 func = getattr (self .pdb_instance , 'do_' + cmd , None )
393421 if func is not None :
394422 return False
395- return _more_lines ( self .console , text )
423+ return self .console . more_lines ( text )
396424
397425 try :
398426 pyrepl_completer = self .readline_wrapper .get_completer ()
399427 self .readline_wrapper .set_completer (self .complete )
400- return (
428+ multiline = (
401429 self .readline_wrapper .multiline_input (
402430 more_lines ,
403431 self .prompt ,
404432 '... ' + ' ' * (len (self .prompt ) - 4 )
405433 ) + '\n '
406434 )
435+ try :
436+ self .readline_wrapper .append_history_file ()
437+ except (FileNotFoundError , PermissionError , OSError ) as e :
438+ import warnings
439+ warnings .warn (f"failed to open the history file for writing: { e } " )
440+ return multiline
407441 except EOFError :
408442 return 'EOF'
409443 finally :
@@ -421,7 +455,7 @@ def complete(self, text, state):
421455 stripped = len (origline ) - len (line )
422456 begidx = self .readline_wrapper .get_begidx () - stripped
423457 endidx = self .readline_wrapper .get_endidx () - stripped
424- if begidx > 0 :
458+ if begidx > 0 :
425459 cmd , args , foo = self .pdb_instance .parseline (line )
426460 if not cmd :
427461 compfunc = self .pdb_instance .completedefault
@@ -2484,19 +2518,20 @@ def do_interact(self, arg):
24842518 """
24852519 ns = {** self .curframe .f_globals , ** self .curframe .f_locals }
24862520 console = _PdbInteractiveConsole (ns , message = self .message )
2521+ banner = "*pdb interact start*"
2522+ exitmsg = "*exit from pdb interact command*"
24872523 if self .pyrepl_input is not None :
24882524 from _pyrepl .simple_interact import run_multiline_interactive_console
2489- self .message ("*pdb interact start*" )
2525+ self .message (banner )
24902526 try :
24912527 run_multiline_interactive_console (console )
24922528 except SystemExit :
24932529 pass
2494- self .message ("*exit from pdb interact command*" )
2530+ self .message (exitmsg )
24952531 else :
24962532 with self ._enable_rlcompleter (ns ):
2497- console = _PdbInteractiveConsole (ns , message = self .message )
2498- console .interact (banner = "*pdb interact start*" ,
2499- exitmsg = "*exit from pdb interact command*" )
2533+ console .interact (banner = banner ,
2534+ exitmsg = exitmsg )
25002535
25012536 def do_alias (self , arg ):
25022537 """alias [name [command]]
0 commit comments