mirror of https://github.com/python/cpython
[3.13] gh-58933: Make pdb return to caller frame correctly when f_trace is not set (GH-118979) (#119007)
gh-58933: Make pdb return to caller frame correctly when f_trace is not set (GH-118979)
(cherry picked from commit f526314194
)
Co-authored-by: Tian Gao <gaogaotiantian@hotmail.com>
This commit is contained in:
parent
44995aab49
commit
09d4c072eb
12
Lib/bdb.py
12
Lib/bdb.py
|
@ -165,6 +165,11 @@ class Bdb:
|
||||||
# The user issued a 'next' or 'until' command.
|
# The user issued a 'next' or 'until' command.
|
||||||
if self.stopframe is frame and self.stoplineno != -1:
|
if self.stopframe is frame and self.stoplineno != -1:
|
||||||
self._set_stopinfo(None, None)
|
self._set_stopinfo(None, None)
|
||||||
|
# The previous frame might not have f_trace set, unless we are
|
||||||
|
# issuing a command that does not expect to stop, we should set
|
||||||
|
# f_trace
|
||||||
|
if self.stoplineno != -1:
|
||||||
|
self._set_caller_tracefunc(frame)
|
||||||
return self.trace_dispatch
|
return self.trace_dispatch
|
||||||
|
|
||||||
def dispatch_exception(self, frame, arg):
|
def dispatch_exception(self, frame, arg):
|
||||||
|
@ -320,13 +325,12 @@ class Bdb:
|
||||||
self.stoplineno = stoplineno
|
self.stoplineno = stoplineno
|
||||||
self._set_trace_opcodes(opcode)
|
self._set_trace_opcodes(opcode)
|
||||||
|
|
||||||
def _set_caller_tracefunc(self):
|
def _set_caller_tracefunc(self, current_frame):
|
||||||
# Issue #13183: pdb skips frames after hitting a breakpoint and running
|
# Issue #13183: pdb skips frames after hitting a breakpoint and running
|
||||||
# step commands.
|
# step commands.
|
||||||
# Restore the trace function in the caller (that may not have been set
|
# Restore the trace function in the caller (that may not have been set
|
||||||
# for performance reasons) when returning from the current frame.
|
# for performance reasons) when returning from the current frame.
|
||||||
if self.frame_returning:
|
caller_frame = current_frame.f_back
|
||||||
caller_frame = self.frame_returning.f_back
|
|
||||||
if caller_frame and not caller_frame.f_trace:
|
if caller_frame and not caller_frame.f_trace:
|
||||||
caller_frame.f_trace = self.trace_dispatch
|
caller_frame.f_trace = self.trace_dispatch
|
||||||
|
|
||||||
|
@ -343,12 +347,10 @@ class Bdb:
|
||||||
|
|
||||||
def set_step(self):
|
def set_step(self):
|
||||||
"""Stop after one line of code."""
|
"""Stop after one line of code."""
|
||||||
self._set_caller_tracefunc()
|
|
||||||
self._set_stopinfo(None, None)
|
self._set_stopinfo(None, None)
|
||||||
|
|
||||||
def set_stepinstr(self):
|
def set_stepinstr(self):
|
||||||
"""Stop before the next instruction."""
|
"""Stop before the next instruction."""
|
||||||
self._set_caller_tracefunc()
|
|
||||||
self._set_stopinfo(None, None, opcode=True)
|
self._set_stopinfo(None, None, opcode=True)
|
||||||
|
|
||||||
def set_next(self, frame):
|
def set_next(self, frame):
|
||||||
|
|
|
@ -1453,6 +1453,58 @@ def test_post_mortem():
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def test_pdb_return_to_different_file():
|
||||||
|
"""When pdb returns to a different file, it should not skip if f_trace is
|
||||||
|
not already set
|
||||||
|
|
||||||
|
>>> import pprint
|
||||||
|
|
||||||
|
>>> class A:
|
||||||
|
... def __repr__(self):
|
||||||
|
... return 'A'
|
||||||
|
|
||||||
|
>>> def test_function():
|
||||||
|
... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace()
|
||||||
|
... pprint.pprint(A())
|
||||||
|
|
||||||
|
>>> reset_Breakpoint()
|
||||||
|
>>> with PdbTestInput([ # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE
|
||||||
|
... 'b A.__repr__',
|
||||||
|
... 'continue',
|
||||||
|
... 'return',
|
||||||
|
... 'next',
|
||||||
|
... 'return',
|
||||||
|
... 'return',
|
||||||
|
... 'continue',
|
||||||
|
... ]):
|
||||||
|
... test_function()
|
||||||
|
> <doctest test.test_pdb.test_pdb_return_to_different_file[2]>(2)test_function()
|
||||||
|
-> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace()
|
||||||
|
(Pdb) b A.__repr__
|
||||||
|
Breakpoint 1 at <doctest test.test_pdb.test_pdb_return_to_different_file[1]>:3
|
||||||
|
(Pdb) continue
|
||||||
|
> <doctest test.test_pdb.test_pdb_return_to_different_file[1]>(3)__repr__()
|
||||||
|
-> return 'A'
|
||||||
|
(Pdb) return
|
||||||
|
--Return--
|
||||||
|
> <doctest test.test_pdb.test_pdb_return_to_different_file[1]>(3)__repr__()->'A'
|
||||||
|
-> return 'A'
|
||||||
|
(Pdb) next
|
||||||
|
> ...pprint.py..._safe_repr()
|
||||||
|
-> return rep,...
|
||||||
|
(Pdb) return
|
||||||
|
--Return--
|
||||||
|
> ...pprint.py..._safe_repr()->('A'...)
|
||||||
|
-> return rep,...
|
||||||
|
(Pdb) return
|
||||||
|
--Return--
|
||||||
|
> ...pprint.py...format()->('A'...)
|
||||||
|
-> return...
|
||||||
|
(Pdb) continue
|
||||||
|
A
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
def test_pdb_skip_modules():
|
def test_pdb_skip_modules():
|
||||||
"""This illustrates the simple case of module skipping.
|
"""This illustrates the simple case of module skipping.
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Make :mod:`pdb` return to caller frame correctly when ``f_trace`` of the caller frame is not set
|
Loading…
Reference in New Issue