summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTian Gao <gaogaotiantian@hotmail.com>2024-07-11 02:54:27 (GMT)
committerGitHub <noreply@github.com>2024-07-11 02:54:27 (GMT)
commit690b9355e00d1ea52020fde3feb4c043a2b214e2 (patch)
treee83456c4be7bfc1d33ba5fc2f92ea951cbf3e9ef
parent6557af669899f18f8d123f8e1b6c3380d502c519 (diff)
downloadcpython-690b9355e00d1ea52020fde3feb4c043a2b214e2.zip
cpython-690b9355e00d1ea52020fde3feb4c043a2b214e2.tar.gz
cpython-690b9355e00d1ea52020fde3feb4c043a2b214e2.tar.bz2
gh-121450: Make inline breakpoints use the most recent pdb instance (#121451)
-rw-r--r--Doc/whatsnew/3.14.rst10
-rw-r--r--Lib/bdb.py1
-rw-r--r--Lib/pdb.py13
-rw-r--r--Lib/test/test_pdb.py43
-rw-r--r--Misc/NEWS.d/next/Library/2024-07-06-23-39-38.gh-issue-121450.vGqb3c.rst4
5 files changed, 70 insertions, 1 deletions
diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst
index d02c10e..da9b45c 100644
--- a/Doc/whatsnew/3.14.rst
+++ b/Doc/whatsnew/3.14.rst
@@ -114,6 +114,16 @@ pathlib
another.
(Contributed by Barney Gale in :gh:`73991`.)
+pdb
+---
+
+* Hard-coded breakpoints (:func:`breakpoint` and :func:`pdb.set_trace()`) now
+ reuse the most recent :class:`~pdb.Pdb` instance that calls
+ :meth:`~pdb.Pdb.set_trace()`, instead of creating a new one each time.
+ As a result, all the instance specific data like :pdbcmd:`display` and
+ :pdbcmd:`commands` are preserved across hard-coded breakpoints.
+ (Contributed by Tian Gao in :gh:`121450`.)
+
symtable
--------
diff --git a/Lib/bdb.py b/Lib/bdb.py
index aa62105..d754301 100644
--- a/Lib/bdb.py
+++ b/Lib/bdb.py
@@ -369,6 +369,7 @@ class Bdb:
If frame is not specified, debugging starts from caller's frame.
"""
+ sys.settrace(None)
if frame is None:
frame = sys._getframe().f_back
self.reset()
diff --git a/Lib/pdb.py b/Lib/pdb.py
index 85a3aa2..7ff9731 100644
--- a/Lib/pdb.py
+++ b/Lib/pdb.py
@@ -306,6 +306,8 @@ class Pdb(bdb.Bdb, cmd.Cmd):
_file_mtime_table = {}
+ _last_pdb_instance = None
+
def __init__(self, completekey='tab', stdin=None, stdout=None, skip=None,
nosigint=False, readrc=True):
bdb.Bdb.__init__(self, skip=skip)
@@ -359,6 +361,12 @@ class Pdb(bdb.Bdb, cmd.Cmd):
self._chained_exceptions = tuple()
self._chained_exception_index = 0
+ def set_trace(self, frame=None):
+ Pdb._last_pdb_instance = self
+ if frame is None:
+ frame = sys._getframe().f_back
+ super().set_trace(frame)
+
def sigint_handler(self, signum, frame):
if self.allow_kbdint:
raise KeyboardInterrupt
@@ -2350,7 +2358,10 @@ def set_trace(*, header=None):
an assertion fails). If given, *header* is printed to the console
just before debugging begins.
"""
- pdb = Pdb()
+ if Pdb._last_pdb_instance is not None:
+ pdb = Pdb._last_pdb_instance
+ else:
+ pdb = Pdb()
if header is not None:
pdb.message(header)
pdb.set_trace(sys._getframe().f_back)
diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py
index 5c74455..343e15a 100644
--- a/Lib/test/test_pdb.py
+++ b/Lib/test/test_pdb.py
@@ -2448,6 +2448,49 @@ def test_pdb_show_attribute_and_item():
(Pdb) c
"""
+# doctest will modify pdb.set_trace during the test, so we need to backup
+# the original function to use it in the test
+original_pdb_settrace = pdb.set_trace
+
+def test_pdb_with_inline_breakpoint():
+ """Hard-coded breakpoint() calls should invoke the same debugger instance
+
+ >>> def test_function():
+ ... x = 1
+ ... import pdb; pdb.Pdb().set_trace()
+ ... original_pdb_settrace()
+ ... x = 2
+
+ >>> with PdbTestInput(['display x',
+ ... 'n',
+ ... 'n',
+ ... 'n',
+ ... 'n',
+ ... 'undisplay',
+ ... 'c']):
+ ... test_function()
+ > <doctest test.test_pdb.test_pdb_with_inline_breakpoint[0]>(3)test_function()
+ -> import pdb; pdb.Pdb().set_trace()
+ (Pdb) display x
+ display x: 1
+ (Pdb) n
+ > <doctest test.test_pdb.test_pdb_with_inline_breakpoint[0]>(4)test_function()
+ -> original_pdb_settrace()
+ (Pdb) n
+ > <doctest test.test_pdb.test_pdb_with_inline_breakpoint[0]>(4)test_function()
+ -> original_pdb_settrace()
+ (Pdb) n
+ > <doctest test.test_pdb.test_pdb_with_inline_breakpoint[0]>(5)test_function()
+ -> x = 2
+ (Pdb) n
+ --Return--
+ > <doctest test.test_pdb.test_pdb_with_inline_breakpoint[0]>(5)test_function()->None
+ -> x = 2
+ display x: 2 [old: 1]
+ (Pdb) undisplay
+ (Pdb) c
+ """
+
def test_pdb_issue_20766():
"""Test for reference leaks when the SIGINT handler is set.
diff --git a/Misc/NEWS.d/next/Library/2024-07-06-23-39-38.gh-issue-121450.vGqb3c.rst b/Misc/NEWS.d/next/Library/2024-07-06-23-39-38.gh-issue-121450.vGqb3c.rst
new file mode 100644
index 0000000..4a65fb7
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2024-07-06-23-39-38.gh-issue-121450.vGqb3c.rst
@@ -0,0 +1,4 @@
+Hard-coded breakpoints (:func:`breakpoint` and :func:`pdb.set_trace()`) now
+reuse the most recent ``Pdb`` instance that calls ``Pdb.set_trace()``,
+instead of creating a new one each time. As a result, all the instance specific
+data like ``display`` and ``commands`` are preserved across Hard-coded breakpoints.