https://github.com/python/cpython/commit/fcdd20ef83e099a227eba5692fffcec1c8b9031b
commit: fcdd20ef83e099a227eba5692fffcec1c8b9031b
branch: 3.12
author: Tian Gao <[email protected]>
committer: iritkatriel <[email protected]>
date: 2024-05-13T20:21:15+01:00
summary:

[3.12] gh-58933: Make pdb return to caller frame correctly when f_trace is not 
set (GH-118979) (#119008)

* [3.12] gh-58933: Make pdb return to caller frame correctly when f_trace is 
not set (GH-118979)
(cherry picked from commit f526314194f7fd15931025f8a4439c1765666e42)

Co-authored-by: Tian Gao <[email protected]>

files:
A Misc/NEWS.d/next/Library/2024-05-12-21-38-42.gh-issue-58933.0kgU2l.rst
M Lib/bdb.py
M Lib/test/test_pdb.py

diff --git a/Lib/bdb.py b/Lib/bdb.py
index 0f3eec653baaad..564d6c5e5324ed 100644
--- a/Lib/bdb.py
+++ b/Lib/bdb.py
@@ -157,6 +157,11 @@ def dispatch_return(self, frame, arg):
             # The user issued a 'next' or 'until' command.
             if self.stopframe is frame and self.stoplineno != -1:
                 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
 
     def dispatch_exception(self, frame, arg):
@@ -286,6 +291,15 @@ def _set_stopinfo(self, stopframe, returnframe, 
stoplineno=0):
         # stoplineno -1 means: don't stop at all
         self.stoplineno = stoplineno
 
+    def _set_caller_tracefunc(self, current_frame):
+        # Issue #13183: pdb skips frames after hitting a breakpoint and running
+        # step commands.
+        # Restore the trace function in the caller (that may not have been set
+        # for performance reasons) when returning from the current frame.
+        caller_frame = current_frame.f_back
+        if caller_frame and not caller_frame.f_trace:
+            caller_frame.f_trace = self.trace_dispatch
+
     # Derived classes and clients can call the following methods
     # to affect the stepping state.
 
@@ -299,14 +313,6 @@ def set_until(self, frame, lineno=None):
 
     def set_step(self):
         """Stop after one line of code."""
-        # Issue #13183: pdb skips frames after hitting a breakpoint and running
-        # step commands.
-        # Restore the trace function in the caller (that may not have been set
-        # for performance reasons) when returning from the current frame.
-        if self.frame_returning:
-            caller_frame = self.frame_returning.f_back
-            if caller_frame and not caller_frame.f_trace:
-                caller_frame.f_trace = self.trace_dispatch
         self._set_stopinfo(None, None)
 
     def set_next(self, frame):
diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py
index 5bdc5f22d0b798..24324a37804ca0 100644
--- a/Lib/test/test_pdb.py
+++ b/Lib/test/test_pdb.py
@@ -904,6 +904,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]>(3)test_function()
+    -> pprint.pprint(A())
+    (Pdb) b A.__repr__
+    Breakpoint 1 at <doctest 
test.test_pdb.test_pdb_return_to_different_file[1]>:2
+    (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():
     """This illustrates the simple case of module skipping.
 
diff --git 
a/Misc/NEWS.d/next/Library/2024-05-12-21-38-42.gh-issue-58933.0kgU2l.rst 
b/Misc/NEWS.d/next/Library/2024-05-12-21-38-42.gh-issue-58933.0kgU2l.rst
new file mode 100644
index 00000000000000..fa70b954e1e9ee
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2024-05-12-21-38-42.gh-issue-58933.0kgU2l.rst
@@ -0,0 +1 @@
+Make :mod:`pdb` return to caller frame correctly when ``f_trace`` of the 
caller frame is not set

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]

Reply via email to