8000 gh-124552 : Improve the accuracy of possible breakpoint check in bdb … · python/cpython@adfe765 · GitHub
[go: up one dir, main page]

Skip to content

Commit adfe765

Browse files
gh-124552 : Improve the accuracy of possible breakpoint check in bdb (#124553)
1 parent 2d8b6a4 commit adfe765

File tree

3 files changed

+62
-3
lines changed

3 files changed

+62
-3
lines changed

Lib/bdb.py

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import fnmatch
44
import sys
55
import os
6+
import weakref
67
from inspect import CO_GENERATOR, CO_COROUTINE, CO_ASYNC_GENERATOR
78

89
__all__ = ["BdbQuit", "Bdb", "Breakpoint"]
@@ -36,6 +37,7 @@ def __init__(self, skip=None):
3637
self.frame_returning = None
3738
self.trace_opcodes = False
3839
self.enterframe = None
40+
self.code_linenos = weakref.WeakKeyDictionary()
3941

4042
self._load_breaks()
4143

@@ -155,6 +157,9 @@ def dispatch_return(self, frame, arg):
155157
if self.stop_here(frame) or frame == self.returnframe:
156158
# Ignore return events in generator except when stepping.
157159
if self.stopframe and frame.f_code.co_flags & GENERATOR_AND_COROUTINE_FLAGS:
160+
# It's possible to trigger a StopIteration exception in
161+
# the caller so we must set the trace function in the caller
162+
self._set_caller_tracefunc(frame)
158163
return self.trace_dispatch
159164
try:
160165
self.frame_returning = frame
@@ -273,9 +278,25 @@ def do_clear(self, arg):
273278
raise NotImplementedError("subclass of bdb must implement do_clear()")
274279

275280
def break_anywhere(self, frame):
276-
"""Return True if there is any breakpoint for frame's filename.
281+
"""Return True if there is any breakpoint in that frame
277282
"""
278-
return self.canonic(frame.f_code.co_filename) in self.breaks
283+
filename = self.canonic(frame.f_code.co_filename)
284+
if filename not in self.breaks:
285+
return False
286+
for lineno in self.breaks[filename]:
287+
if self._lineno_in_frame(lineno, frame):
288+
return True
289+
return False
290+
291+
def _lineno_in_frame(self, lineno, frame):
292+
"""Return True if the line number is in the frame's code object.
293+
"""
294+
code = frame.f_code
295+
if lineno < code.co_firstlineno:
296+
return False
297+
if code not in self.code_linenos:
298+
self.code_linenos[code] = set(lineno for _, _, lineno in code.co_lines())
299+
return lineno in self.code_linenos[code]
279300

280301
# Derived classes should override the user_* methods
281302
# to gain control.
@@ -360,7 +381,7 @@ def set_next(self, frame):
360381
def set_return(self, frame):
361382
"""Stop when returning from the given frame."""
362383
if frame.f_code.co_flags & GENERATOR_AND_COROUTINE_FLAGS:
363-
self._set_stopinfo(frame, None, -1)
384+
self._set_stopinfo(frame, frame, -1)
364385
else:
365386
self._set_stopinfo(frame.f_back, frame)
366387

Lib/test/test_pdb.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,43 @@ def test_pdb_breakpoints_preserved_across_interactive_sessions():
518518
(Pdb) continue
519519
"""
520520

521+
def test_pdb_break_anywhere():
522+
"""Test break_anywhere() method of Pdb.
523+
524+
>>> def outer():
525+
... def inner():
526+
... import pdb
527+
... import sys
528+
... p = pdb.Pdb(nosigint=True, readrc=False)
529+
... p.set_trace()
530+
... frame = sys._getframe()
531+
... print(p.break_anywhere(frame)) # inner
532+
... print(p.break_anywhere(frame.f_back)) # outer
533+
... print(p.break_anywhere(frame.f_back.f_back)) # caller
534+
... inner()
535+
536+
>>> def caller():
537+
... outer()
538+
539+
>>> def test_function():
540+
... caller()
541+
542+
>>> reset_Breakpoint()
543+
>>> with PdbTestInput([ # doctest: +NORMALIZE_WHITESPACE
544+
... 'b 3',
545+
... 'c',
546+
... ]):
547+
... test_function()
548+
> <doctest test.test_pdb.test_pdb_break_anywhere[0]>(6)inner()
549+
-> p.set_trace()
550+
(Pdb) b 3
551+
Breakpoint 1 at <doctest test.test_pdb.test_pdb_break_anywhere[0]>:3
552+
(Pdb) c
553+
True
554+
False
555+
False
556+
"""
557+
521558
def test_pdb_pp_repr_exc():
522559
"""Test that do_p/do_pp do not swallow exceptions.
523560
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Improve the accuracy of :mod:`bdb`'s check for the possibility of breakpoint in a frame. This makes it possible to disable unnecessary events in functions.

0 commit comments

Comments
 (0)
0