Skip to content

Commit

Permalink
pythongh-121450: Make inline breakpoints use the most recent pdb inst…
Browse files Browse the repository at this point in the history
…ance (python#121451)
  • Loading branch information
gaogaotiantian authored Jul 11, 2024
1 parent 6557af6 commit 690b935
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 1 deletion.
10 changes: 10 additions & 0 deletions Doc/whatsnew/3.14.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
--------

Expand Down
1 change: 1 addition & 0 deletions Lib/bdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,7 @@ def set_trace(self, frame=None):
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()
Expand Down
13 changes: 12 additions & 1 deletion Lib/pdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -359,6 +361,12 @@ def __init__(self, completekey='tab', stdin=None, stdout=None, skip=None,
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
Expand Down Expand Up @@ -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)
Expand Down
43 changes: 43 additions & 0 deletions Lib/test/test_pdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
Original file line number Diff line number Diff line change
@@ -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.

0 comments on commit 690b935

Please sign in to comment.