8000 gh-124400: Use the normal command path for breakpoint commands (#124401) · python/cpython@b577460 · GitHub
[go: up one dir, main page]

Skip to content

Commit b577460

Browse files
gh-124400: Use the normal command path for breakpoint commands (#124401)
Co-authored-by: Irit Katriel <1055913+iritkatriel@users.noreply.github.com>
1 parent 4b83c03 commit b577460

File tree

4 files changed

+77
-40
lines changed

4 files changed

+77
-40
lines changed

Doc/library/pdb.rst

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -439,17 +439,20 @@ can be overridden by the local file.
439439

440440
Specifying any command resuming execution
441441
(currently :pdbcmd:`continue`, :pdbcmd:`step`, :pdbcmd:`next`,
442-
:pdbcmd:`return`, :pdbcmd:`jump`, :pdbcmd:`quit` and their abbreviations)
442+
:pdbcmd:`return`, :pdbcmd:`until`, :pdbcmd:`jump`, :pdbcmd:`quit` and their abbreviations)
443443
terminates the command list (as if
444444
that command was immediately followed by end). This is because any time you
445445
resume execution (even with a simple next or step), you may encounter another
446446
breakpoint—which could have its own command list, leading to ambiguities about
447447
which list to execute.
448448

449-
If you use the ``silent`` command in the command list, the usual message about
450-
stopping at a breakpoint is not printed. This may be desirable for breakpoints
451-
that are to print a specific message and then continue. If none of the other
452-
commands print anything, you see no sign that the breakpoint was reached.
449+
If the list of commands contains the ``silent`` command, or a command that
450+
resumes execution, then the breakpoint message containing information about
451+
the frame is not displayed.
452+
453+
.. versionchanged:: 3.14
454+
Frame information will not be displayed if a command that resumes execution
455+
is present in the command list.
453456

454457
.. pdbcommand:: s(tep)
455458

Lib/pdb.py

Lines changed: 20 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -350,10 +350,6 @@ def __init__(self, completekey='tab', stdin=None, stdout=None, skip=None,
350350
pass
351351

352352
self.commands = {} # associates a command list to breakpoint numbers
353-
self.commands_doprompt = {} # for each bp num, tells if the prompt
354-
# must be disp. after execing the cmd list
355-
self.commands_silent = {} # for each bp num, tells if the stack trace
356-
# must be disp. after execing the cmd list
357353
self.commands_defining = False # True while in the process of defining
358354
# a command list
359355
self.commands_bnum = None # The breakpoint number for which we are
@@ -437,8 +433,8 @@ def user_line(self, frame):
437433
or frame.f_lineno <= 0):
438434
return
439435
self._wait_for_mainpyfile = False
440-
if self.bp_commands(frame):
441-
self.interaction(frame, None)
436+
self.bp_commands(frame)
437+
self.interaction(frame, None)
442438

443439
user_opcode = user_line
444440

@@ -453,18 +449,9 @@ def bp_commands(self, frame):
453449
self.currentbp in self.commands:
454450
currentbp = self.currentbp
455451
self.currentbp = 0
456-
lastcmd_back = self.lastcmd
457-
self.setup(frame, None)
458452
for line in self.commands[currentbp]:
459-
self.onecmd(line)
460-
self.lastcmd = lastcmd_back
461-
if not self.commands_silent[currentbp]:
462-
self.print_stack_entry(self.stack[self.curindex])
463-
if self.commands_doprompt[currentbp]:
464-
self._cmdloop()
465-
self.forget()
466-
return
467-
return 1
453+
self.cmdqueue.append(line)
454+
self.cmdqueue.append(f'_pdbcmd_restore_lastcmd {self.lastcmd}')
468455

469456
def user_return(self, frame, return_value):
470457
"""This function is called when a return trap is set here."""
@@ -863,15 +850,15 @@ def handle_command_def(self, line):
863850
cmd, arg, line = self.parseline(line)
864851
if not cmd:
865852
return False
866-
if cmd == 'silent':
867-
self.commands_silent[self.commands_bnum] = True
868-
return False # continue to handle other cmd def in the cmd list
869-
elif cmd == 'end':
853+
if cmd == 'end':
870854
return True # end of cmd list
871855
elif cmd == 'EOF':
872856
print('')
873857
return True # end of cmd list
874858
cmdlist = self.commands[self.commands_bnum]
859+
if cmd == 'silent':
860+
cmdlist.append('_pdbcmd_silence_frame_status')
861+
return False # continue to handle other cmd def in the cmd list
875862
if arg:
876863
cmdlist.append(cmd+' '+arg)
877864
else:
@@ -883,7 +870,6 @@ def handle_command_def(self, line):
883870
func = self.default
884871
# one of the resuming commands
885872
if func.__name__ < 9E88 span class=pl-c1>in self.commands_resuming:
886-
self.commands_doprompt[self.commands_bnum] = False
887873
return True
888874
return False
889875

@@ -996,6 +982,13 @@ def _pdbcmd_print_frame_status(self, arg):
996982
self.print_stack_trace(0)
997983
self._show_display()
998984

985+
def _pdbcmd_silence_frame_status(self, arg):
986+
if self.cmdqueue and self.cmdqueue[-1] == '_pdbcmd_print_frame_status':
987+
self.cmdqueue.pop()
988+
989+
def _pdbcmd_restore_lastcmd(self, arg):
990+
self.lastcmd = arg
991+
999992
# Command definitions, called by cmdloop()
1000993
# The argument is the remaining string on the command line
1001994
# Return true to exit from the command loop
@@ -1054,14 +1047,10 @@ def do_commands(self, arg):
10541047
self.commands_bnum = bnum
10551048
# Save old definitions for the case of a keyboard interrupt.
10561049
if bnum in self.commands:
1057-
old_command_defs = (self.commands[bnum],
1058-
self.commands_doprompt[bnum],
1059-
self.commands_silent[bnum])
1050+
old_commands = self.commands[bnum]
10601051
else:
1061-
old_command_defs = None
1052+
old_commands = None
10621053
self.commands[bnum] = []
1063-
self.commands_doprompt[bnum] = True
1064-
self.commands_silent[bnum] = False
10651054

10661055
prompt_back = self.prompt
10671056
self.prompt = '(com) '
@@ -1070,14 +1059,10 @@ def do_commands(self, arg):
10701059
self.cmdloop()
10711060
except KeyboardInterrupt:
10721061
# Restore old definitions.
1073-
if old_command_defs:
1074-
self.commands[bnum] = old_command_defs[0]
1075-
self.commands_doprompt[bnum] = old_command_defs[1]
1076-
self.commands_silent[bnum] = old_command_defs[2]
1062+
if old_commands:
1063+
self.commands[bnum] = old_commands
10771064
else:
10781065
del self.commands[bnum]
1079-
del self.commands_doprompt[bnum]
1080-
del self.commands_silent[bnum]
10811066
self.error('command definition aborted, old commands restored')
10821067
finally:
10831068
self.commands_defining = False
@@ -2093,7 +2078,7 @@ def complete_unalias(self, text, line, begidx, endidx):
20932078

20942079
# List of all the commands making the program resume execution.
20952080
commands_resuming = ['do_continue', 'do_step', 'do_next', 'do_return',
2096-
'do_quit', 'do_jump']
2081+
'do_until', 'do_quit', 'do_jump']
20972082

20982083
# Print a traceback starting at the top stack frame.
20992084
# The most recently entered frame is printed last;

Lib/test/test_pdb.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,54 @@ def test_pdb_breakpoint_commands():
363363
4
364364
"""
365365

366+
def test_pdb_commands():
367+
"""Test the commands command of pdb.
368+
369+
>>> def test_function():
370+
... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace()
371+
... print(1)
372+
... print(2)
373+
... print(3)
374+
375+
>>> reset_Breakpoint()
376+
377+
>>> with PdbTestInput([ # doctest: +NORMALIZE_WHITESPACE
378+
... 'b 3',
379+
... 'commands',
380+
... 'silent', # suppress the frame status output
381+
... 'p "hello"',
382+
... 'end',
383+
... 'b 4',
384+
... 'commands',
385+
... 'until 5', # no output, should stop at line 5
386+
... 'continue', # hit breakpoint at line 3
387+
... '', # repeat continue, hit breakpoint at line 4 then `until` to line 5
388+
... '',
389+
... ]):
390+
... test_function()
391+
> <doctest test.test_pdb.test_pdb_commands[0]>(2)test_function()
392+
-> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace()
393+
(Pdb) b 3
394+
Breakpoint 1 at <doctest test.test_pdb.test_pdb_commands[0]>:3
395+
(Pdb) commands
396+
(com) silent
397+
(com) p "hello"
398+
(com) end
399+
(Pdb) b 4
400+
Breakpoint 2 at <doctest test.test_pdb.test_pdb_commands[0]>:4
401+
(Pdb) commands
402+
(com) until 5
403+
(Pdb) continue
404+
'hello'
405+
(Pdb)
406+
1
407+
2
408+
> <doctest test.test_pdb.test_pdb_commands[0]>(5)test_function()
409+
-> print(3)
410+
(Pdb)
411+
3
412+
"""
413+
366414
def test_pdb_breakpoint_with_filename():
367415
"""Breakpoints with filename:lineno
368416
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fixed a :mod:`pdb` bug where ``until`` has no effect when it appears in a ``commands`` sequence. Also avoid printing the frame information at a breakpoint that has a command list containing a command that resumes execution.

0 commit comments

Comments
 (0)
0