diff --git a/Doc/library/pdb.rst b/Doc/library/pdb.rst index 42888366278..5b145ecda78 100644 --- a/Doc/library/pdb.rst +++ b/Doc/library/pdb.rst @@ -235,7 +235,8 @@ tbreak [[*filename*:]\ *lineno* | *function*\ [, *condition*]] Temporary breakpoint, which is removed automatically when it is first hit. The arguments are the same as break. -cl(ear) [*bpnumber* [*bpnumber ...*]] +cl(ear) [*filename:lineno* | *bpnumber* [*bpnumber ...*]] + With a *filename:lineno* argument, clear all the breakpoints at this line. With a space separated list of breakpoint numbers, clear those breakpoints. Without argument, clear all breaks (but first ask confirmation). diff --git a/Lib/bdb.py b/Lib/bdb.py index f16414d506f..3ed25fe1010 100644 --- a/Lib/bdb.py +++ b/Lib/bdb.py @@ -249,6 +249,12 @@ class Bdb: list.append(lineno) bp = Breakpoint(filename, lineno, temporary, cond, funcname) + def _prune_breaks(self, filename, lineno): + if (filename, lineno) not in Breakpoint.bplist: + self.breaks[filename].remove(lineno) + if not self.breaks[filename]: + del self.breaks[filename] + def clear_break(self, filename, lineno): filename = self.canonic(filename) if not filename in self.breaks: @@ -260,10 +266,7 @@ class Bdb: # pair, then remove the breaks entry for bp in Breakpoint.bplist[filename, lineno][:]: bp.deleteMe() - if (filename, lineno) not in Breakpoint.bplist: - self.breaks[filename].remove(lineno) - if not self.breaks[filename]: - del self.breaks[filename] + self._prune_breaks(filename, lineno) def clear_bpbynumber(self, arg): try: @@ -276,7 +279,8 @@ class Bdb: return 'Breakpoint number (%d) out of range' % number if not bp: return 'Breakpoint (%d) already deleted' % number - self.clear_break(bp.file, bp.line) + bp.deleteMe() + self._prune_breaks(bp.file, bp.line) def clear_all_file_breaks(self, filename): filename = self.canonic(filename) diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index 9ab0b33a040..2589141615b 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -54,6 +54,107 @@ def test_pdb_displayhook(): (Pdb) continue """ +def test_pdb_breakpoint_commands(): + """Test basic commands related to breakpoints. + + >>> def test_function(): + ... import pdb; pdb.Pdb().set_trace() + ... print(1) + ... print(2) + ... print(3) + ... print(4) + + First, need to clear bdb state that might be left over from previous tests. + Otherwise, the new breakpoints might get assigned different numbers. + + >>> from bdb import Breakpoint + >>> Breakpoint.next = 1 + >>> Breakpoint.bplist = {} + >>> Breakpoint.bpbynumber = [None] + + Now test the breakpoint commands. NORMALIZE_WHITESPACE is needed because + the breakpoint list outputs a tab for the "stop only" and "ignore next" + lines, which we don't want to put in here. + + >>> with PdbTestInput([ # doctest: +NORMALIZE_WHITESPACE + ... 'break 3', + ... 'disable 1', + ... 'ignore 1 10', + ... 'condition 1 1 < 2', + ... 'break 4', + ... 'break 4', + ... 'break', + ... 'clear 3', + ... 'break', + ... 'condition 1', + ... 'enable 1', + ... 'clear 1', + ... 'commands 2', + ... 'print 42', + ... 'end', + ... 'continue', # will stop at breakpoint 2 (line 4) + ... 'clear', # clear all! + ... 'y', + ... 'tbreak 5', + ... 'continue', # will stop at temporary breakpoint + ... 'break', # make sure breakpoint is gone + ... 'continue', + ... ]): + ... test_function() + > (3)test_function() + -> print(1) + (Pdb) break 3 + Breakpoint 1 at :3 + (Pdb) disable 1 + (Pdb) ignore 1 10 + Will ignore next 10 crossings of breakpoint 1. + (Pdb) condition 1 1 < 2 + (Pdb) break 4 + Breakpoint 2 at :4 + (Pdb) break 4 + Breakpoint 3 at :4 + (Pdb) break + Num Type Disp Enb Where + 1 breakpoint keep no at :3 + stop only if 1 < 2 + ignore next 10 hits + 2 breakpoint keep yes at :4 + 3 breakpoint keep yes at :4 + (Pdb) clear 3 + Deleted breakpoint 3 + (Pdb) break + Num Type Disp Enb Where + 1 breakpoint keep no at :3 + stop only if 1 < 2 + ignore next 10 hits + 2 breakpoint keep yes at :4 + (Pdb) condition 1 + Breakpoint 1 is now unconditional. + (Pdb) enable 1 + (Pdb) clear 1 + Deleted breakpoint 1 + (Pdb) commands 2 + (com) print 42 + (com) end + (Pdb) continue + 1 + 42 + > (4)test_function() + -> print(2) + (Pdb) clear + Clear all breaks? y + (Pdb) tbreak 5 + Breakpoint 4 at :5 + (Pdb) continue + 2 + Deleted breakpoint 4 + > (5)test_function() + -> print(3) + (Pdb) break + (Pdb) continue + 3 + 4 + """ def test_pdb_skip_modules(): """This illustrates the simple case of module skipping. @@ -138,6 +239,14 @@ def test_pdb_continue_in_bottomframe(): ... print(3) ... print(4) + First, need to clear bdb state that might be left over from previous tests. + Otherwise, the new breakpoints might get assigned different numbers. + + >>> from bdb import Breakpoint + >>> Breakpoint.next = 1 + >>> Breakpoint.bplist = {} + >>> Breakpoint.bpbynumber = [None] + >>> with PdbTestInput([ ... 'next', ... 'break 7', @@ -168,6 +277,7 @@ def test_pdb_continue_in_bottomframe(): """ + def test_main(): from test import test_pdb support.run_doctest(test_pdb, verbosity=True) diff --git a/Misc/NEWS b/Misc/NEWS index d8924523d2c..1167fff329b 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -28,6 +28,8 @@ Core and Builtins Library ------- +- Issue #10561: In pdb, clear the breakpoints by the breakpoint number. + - Issue #10459: Update CJK character names to Unicode 5.1. - Issue #10092: Properly reset locale in calendar.Locale*Calendar classes.