summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTian Gao <gaogaotiantian@hotmail.com>2024-10-05 01:32:57 (GMT)
committerGitHub <noreply@github.com>2024-10-05 01:32:57 (GMT)
commitadfe7657a3f1ce5d8384694ed27a40376a18fa6c (patch)
treea9c6b04e17b69d2b0fd2c00a6dba74e55c1c0e99
parent2d8b6a4e9d9a74e3c5270eec62716710ac197063 (diff)
downloadcpython-adfe7657a3f1ce5d8384694ed27a40376a18fa6c.zip
cpython-adfe7657a3f1ce5d8384694ed27a40376a18fa6c.tar.gz
cpython-adfe7657a3f1ce5d8384694ed27a40376a18fa6c.tar.bz2
gh-124552 : Improve the accuracy of possible breakpoint check in bdb (#124553)
-rw-r--r--Lib/bdb.py27
-rw-r--r--Lib/test/test_pdb.py37
-rw-r--r--Misc/NEWS.d/next/Library/2024-09-25-22-06-52.gh-issue-124552.1nQKNM.rst1
3 files changed, 62 insertions, 3 deletions
diff --git a/Lib/bdb.py b/Lib/bdb.py
index d754301..666f971 100644
--- a/Lib/bdb.py
+++ b/Lib/bdb.py
@@ -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)
diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py
index 4c64a80..46eb002 100644
--- a/Lib/test/test_pdb.py
+++ b/Lib/test/test_pdb.py
@@ -518,6 +518,43 @@ def test_pdb_breakpoints_preserved_across_interactive_sessions():
(Pdb) continue
"""
+def test_pdb_break_anywhere():
+ """Test break_anywhere() method of Pdb.
+
+ >>> def outer():
+ ... def inner():
+ ... import pdb
+ ... import sys
+ ... p = pdb.Pdb(nosigint=True, readrc=False)
+ ... p.set_trace()
+ ... frame = sys._getframe()
+ ... print(p.break_anywhere(frame)) # inner
+ ... print(p.break_anywhere(frame.f_back)) # outer
+ ... print(p.break_anywhere(frame.f_back.f_back)) # caller
+ ... inner()
+
+ >>> def caller():
+ ... outer()
+
+ >>> def test_function():
+ ... caller()
+
+ >>> reset_Breakpoint()
+ >>> with PdbTestInput([ # doctest: +NORMALIZE_WHITESPACE
+ ... 'b 3',
+ ... 'c',
+ ... ]):
+ ... test_function()
+ > <doctest test.test_pdb.test_pdb_break_anywhere[0]>(6)inner()
+ -> p.set_trace()
+ (Pdb) b 3
+ Breakpoint 1 at <doctest test.test_pdb.test_pdb_break_anywhere[0]>:3
+ (Pdb) c
+ True
+ False
+ False
+ """
+
def test_pdb_pp_repr_exc():
"""Test that do_p/do_pp do not swallow exceptions.
diff --git a/Misc/NEWS.d/next/Library/2024-09-25-22-06-52.gh-issue-124552.1nQKNM.rst b/Misc/NEWS.d/next/Library/2024-09-25-22-06-52.gh-issue-124552.1nQKNM.rst
new file mode 100644
index 0000000..39dde4c
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2024-09-25-22-06-52.gh-issue-124552.1nQKNM.rst
@@ -0,0 +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.