Skip to content

Commit 690b935

Browse files
gh-121450: Make inline breakpoints use the most recent pdb instance (#121451)
1 parent 6557af6 commit 690b935

File tree

5 files changed

+70
-1
lines changed

5 files changed

+70
-1
lines changed

Doc/whatsnew/3.14.rst

+10
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,16 @@ pathlib
114114
another.
115115
(Contributed by Barney Gale in :gh:`73991`.)
116116

117+
pdb
118+
---
119+
120+
* Hard-coded breakpoints (:func:`breakpoint` and :func:`pdb.set_trace()`) now
121+
reuse the most recent :class:`~pdb.Pdb` instance that calls
122+
:meth:`~pdb.Pdb.set_trace()`, instead of creating a new one each time.
123+
As a result, all the instance specific data like :pdbcmd:`display` and
124+
:pdbcmd:`commands` are preserved across hard-coded breakpoints.
125+
(Contributed by Tian Gao in :gh:`121450`.)
126+
117127
symtable
118128
--------
119129

Lib/bdb.py

+1
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,7 @@ def set_trace(self, frame=None):
369369
370370
If frame is not specified, debugging starts from caller's frame.
371371
"""
372+
sys.settrace(None)
372373
if frame is None:
373374
frame = sys._getframe().f_back
374375
self.reset()

Lib/pdb.py

+12-1
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,8 @@ class Pdb(bdb.Bdb, cmd.Cmd):
306306

307307
_file_mtime_table = {}
308308

309+
_last_pdb_instance = None
310+
309311
def __init__(self, completekey='tab', stdin=None, stdout=None, skip=None,
310312
nosigint=False, readrc=True):
311313
bdb.Bdb.__init__(self, skip=skip)
@@ -359,6 +361,12 @@ def __init__(self, completekey='tab', stdin=None, stdout=None, skip=None,
359361
self._chained_exceptions = tuple()
360362
self._chained_exception_index = 0
361363

364+
def set_trace(self, frame=None):
365+
Pdb._last_pdb_instance = self
366+
if frame is None:
367+
frame = sys._getframe().f_back
368+
super().set_trace(frame)
369+
362370
def sigint_handler(self, signum, frame):
363371
if self.allow_kbdint:
364372
raise KeyboardInterrupt
@@ -2350,7 +2358,10 @@ def set_trace(*, header=None):
23502358
an assertion fails). If given, *header* is printed to the console
23512359
just before debugging begins.
23522360
"""
2353-
pdb = Pdb()
2361+
if Pdb._last_pdb_instance is not None:
2362+
pdb = Pdb._last_pdb_instance
2363+
else:
2364+
pdb = Pdb()
23542365
if header is not None:
23552366
pdb.message(header)
23562367
pdb.set_trace(sys._getframe().f_back)

Lib/test/test_pdb.py

+43
Original file line numberDiff line numberDiff line change
@@ -2448,6 +2448,49 @@ def test_pdb_show_attribute_and_item():
24482448
(Pdb) c
24492449
"""
24502450

2451+
# doctest will modify pdb.set_trace during the test, so we need to backup
2452+
# the original function to use it in the test
2453+
original_pdb_settrace = pdb.set_trace
2454+
2455+
def test_pdb_with_inline_breakpoint():
2456+
"""Hard-coded breakpoint() calls should invoke the same debugger instance
2457+
2458+
>>> def test_function():
2459+
... x = 1
2460+
... import pdb; pdb.Pdb().set_trace()
2461+
... original_pdb_settrace()
2462+
... x = 2
2463+
2464+
>>> with PdbTestInput(['display x',
2465+
... 'n',
2466+
... 'n',
2467+
... 'n',
2468+
... 'n',
2469+
... 'undisplay',
2470+
... 'c']):
2471+
... test_function()
2472+
> <doctest test.test_pdb.test_pdb_with_inline_breakpoint[0]>(3)test_function()
2473+
-> import pdb; pdb.Pdb().set_trace()
2474+
(Pdb) display x
2475+
display x: 1
2476+
(Pdb) n
2477+
> <doctest test.test_pdb.test_pdb_with_inline_breakpoint[0]>(4)test_function()
2478+
-> original_pdb_settrace()
2479+
(Pdb) n
2480+
> <doctest test.test_pdb.test_pdb_with_inline_breakpoint[0]>(4)test_function()
2481+
-> original_pdb_settrace()
2482+
(Pdb) n
2483+
> <doctest test.test_pdb.test_pdb_with_inline_breakpoint[0]>(5)test_function()
2484+
-> x = 2
2485+
(Pdb) n
2486+
--Return--
2487+
> <doctest test.test_pdb.test_pdb_with_inline_breakpoint[0]>(5)test_function()->None
2488+
-> x = 2
2489+
display x: 2 [old: 1]
2490+
(Pdb) undisplay
2491+
(Pdb) c
2492+
"""
2493+
24512494
def test_pdb_issue_20766():
24522495
"""Test for reference leaks when the SIGINT handler is set.
24532496
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Hard-coded breakpoints (:func:`breakpoint` and :func:`pdb.set_trace()`) now
2+
reuse the most recent ``Pdb`` instance that calls ``Pdb.set_trace()``,
3+
instead of creating a new one each time. As a result, all the instance specific
4+
data like ``display`` and ``commands`` are preserved across Hard-coded breakpoints.

0 commit comments

Comments
 (0)