diff options
author | Tian Gao <gaogaotiantian@hotmail.com> | 2024-10-05 01:32:57 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-10-05 01:32:57 (GMT) |
commit | adfe7657a3f1ce5d8384694ed27a40376a18fa6c (patch) | |
tree | a9c6b04e17b69d2b0fd2c00a6dba74e55c1c0e99 /Lib/bdb.py | |
parent | 2d8b6a4e9d9a74e3c5270eec62716710ac197063 (diff) | |
download | cpython-adfe7657a3f1ce5d8384694ed27a40376a18fa6c.zip cpython-adfe7657a3f1ce5d8384694ed27a40376a18fa6c.tar.gz cpython-adfe7657a3f1ce5d8384694ed27a40376a18fa6c.tar.bz2 |
gh-124552 : Improve the accuracy of possible breakpoint check in bdb (#124553)
Diffstat (limited to 'Lib/bdb.py')
-rw-r--r-- | Lib/bdb.py | 27 |
1 files changed, 24 insertions, 3 deletions
@@ -3,6 +3,7 @@ import fnmatch import sys import os +import weakref from inspect import CO_GENERATOR, CO_COROUTINE, CO_ASYNC_GENERATOR __all__ = ["BdbQuit", "Bdb", "Breakpoint"] @@ -36,6 +37,7 @@ class Bdb: self.frame_returning = None self.trace_opcodes = False self.enterframe = None + self.code_linenos = weakref.WeakKeyDictionary() self._load_breaks() @@ -155,6 +157,9 @@ class Bdb: if self.stop_here(frame) or frame == self.returnframe: # Ignore return events in generator except when stepping. if self.stopframe and frame.f_code.co_flags & GENERATOR_AND_COROUTINE_FLAGS: + # It's possible to trigger a StopIteration exception in + # the caller so we must set the trace function in the caller + self._set_caller_tracefunc(frame) return self.trace_dispatch try: self.frame_returning = frame @@ -273,9 +278,25 @@ class Bdb: raise NotImplementedError("subclass of bdb must implement do_clear()") def break_anywhere(self, frame): - """Return True if there is any breakpoint for frame's filename. + """Return True if there is any breakpoint in that frame """ - return self.canonic(frame.f_code.co_filename) in self.breaks + filename = self.canonic(frame.f_code.co_filename) + if filename not in self.breaks: + return False + for lineno in self.breaks[filename]: + if self._lineno_in_frame(lineno, frame): + return True + return False + + def _lineno_in_frame(self, lineno, frame): + """Return True if the line number is in the frame's code object. + """ + code = frame.f_code + if lineno < code.co_firstlineno: + return False + if code not in self.code_linenos: + self.code_linenos[code] = set(lineno for _, _, lineno in code.co_lines()) + return lineno in self.code_linenos[code] # Derived classes should override the user_* methods # to gain control. @@ -360,7 +381,7 @@ class Bdb: def set_return(self, frame): """Stop when returning from the given frame.""" if frame.f_code.co_flags & GENERATOR_AND_COROUTINE_FLAGS: - self._set_stopinfo(frame, None, -1) + self._set_stopinfo(frame, frame, -1) else: self._set_stopinfo(frame.f_back, frame) |