From 2a845fa2d178b0f2fd5b3fb83ac8abdfb4c99d07 Mon Sep 17 00:00:00 2001 From: Tian Gao Date: Sun, 16 Nov 2025 13:57:07 -0800 Subject: [PATCH] [3.13] gh-136057: Allow step and next to step over for loops (GH-136160) (cherry picked from commit 8be3b2f479431f670f2e81e41b52e698c0806289) Co-authored-by: Tian Gao --- Lib/bdb.py | 22 ++++++++++--- Lib/test/test_pdb.py | 31 +++++++++++++++++++ ...-07-01-04-57-57.gh-issue-136057.4-t596.rst | 1 + 3 files changed, 50 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2025-07-01-04-57-57.gh-issue-136057.4-t596.rst diff --git a/Lib/bdb.py b/Lib/bdb.py index 0a3b6dfbfc6025..f256b56daaa01e 100644 --- a/Lib/bdb.py +++ b/Lib/bdb.py @@ -37,6 +37,8 @@ def __init__(self, skip=None): self.frame_returning = None self.trace_opcodes = False self.enterframe = None + self.cmdframe = None + self.cmdlineno = None self._load_breaks() @@ -124,7 +126,12 @@ def dispatch_line(self, frame): self.user_line(). Raise BdbQuit if self.quitting is set. Return self.trace_dispatch to continue tracing in this scope. """ - if self.stop_here(frame) or self.break_here(frame): + # GH-136057 + # For line events, we don't want to stop at the same line where + # the latest next/step command was issued. + if (self.stop_here(frame) or self.break_here(frame)) and not ( + self.cmdframe == frame and self.cmdlineno == frame.f_lineno + ): self.user_line(frame) if self.quitting: raise BdbQuit return self.trace_dispatch @@ -316,7 +323,8 @@ def _set_trace_opcodes(self, trace_opcodes): break frame = frame.f_back - def _set_stopinfo(self, stopframe, returnframe, stoplineno=0, opcode=False): + def _set_stopinfo(self, stopframe, returnframe, stoplineno=0, opcode=False, + cmdframe=None, cmdlineno=None): """Set the attributes for stopping. If stoplineno is greater than or equal to 0, then stop at line @@ -329,6 +337,10 @@ def _set_stopinfo(self, stopframe, returnframe, stoplineno=0, opcode=False): # stoplineno >= 0 means: stop at line >= the stoplineno # stoplineno -1 means: don't stop at all self.stoplineno = stoplineno + # cmdframe/cmdlineno is the frame/line number when the user issued + # step/next commands. + self.cmdframe = cmdframe + self.cmdlineno = cmdlineno self._set_trace_opcodes(opcode) def _set_caller_tracefunc(self, current_frame): @@ -354,7 +366,9 @@ def set_until(self, frame, lineno=None): def set_step(self): """Stop after one line of code.""" - self._set_stopinfo(None, None) + # set_step() could be called from signal handler so enterframe might be None + self._set_stopinfo(None, None, cmdframe=self.enterframe, + cmdlineno=getattr(self.enterframe, 'f_lineno', None)) def set_stepinstr(self): """Stop before the next instruction.""" @@ -362,7 +376,7 @@ def set_stepinstr(self): def set_next(self, frame): """Stop on the next line in or below the given frame.""" - self._set_stopinfo(frame, None) + self._set_stopinfo(frame, None, cmdframe=frame, cmdlineno=frame.f_lineno) def set_return(self, frame): """Stop when returning from the given frame.""" diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index 8c341c6ee8e11a..92a0180ecc9a06 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -2736,6 +2736,37 @@ def test_pdb_issue_gh_127321(): """ +def test_pdb_issue_gh_136057(): + """See GH-136057 + "step" and "next" commands should be able to get over list comprehensions + >>> def test_function(): + ... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + ... lst = [i for i in range(10)] + ... for i in lst: pass + + >>> with PdbTestInput([ # doctest: +NORMALIZE_WHITESPACE + ... 'next', + ... 'next', + ... 'step', + ... 'continue', + ... ]): + ... test_function() + > (2)test_function() + -> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + (Pdb) next + > (3)test_function() + -> lst = [i for i in range(10)] + (Pdb) next + > (4)test_function() + -> for i in lst: pass + (Pdb) step + --Return-- + > (4)test_function()->None + -> for i in lst: pass + (Pdb) continue + """ + + def test_pdb_issue_gh_80731(): """See GH-80731 diff --git a/Misc/NEWS.d/next/Library/2025-07-01-04-57-57.gh-issue-136057.4-t596.rst b/Misc/NEWS.d/next/Library/2025-07-01-04-57-57.gh-issue-136057.4-t596.rst new file mode 100644 index 00000000000000..e237a0e98cc486 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-07-01-04-57-57.gh-issue-136057.4-t596.rst @@ -0,0 +1 @@ +Fixed the bug in :mod:`pdb` and :mod:`bdb` where ``next`` and ``step`` can't go over the line if a loop exists in the line.