https://github.com/python/cpython/commit/7beb7e8d35a58d52f8b91c095993b41eac17150a
commit: 7beb7e8d35a58d52f8b91c095993b41eac17150a
branch: 3.13
author: Tian Gao <[email protected]>
committer: gaogaotiantian <[email protected]>
date: 2025-11-16T22:23:03Z
summary:
[3.13] gh-136057: Allow step and next to step over for loops (GH-136160)
(#141641)
(cherry picked from commit 8be3b2f479431f670f2e81e41b52e698c0806289)
files:
A Misc/NEWS.d/next/Library/2025-07-01-04-57-57.gh-issue-136057.4-t596.rst
M Lib/bdb.py
M Lib/test/test_pdb.py
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()
+ > <doctest test.test_pdb.test_pdb_issue_gh_136057[0]>(2)test_function()
+ -> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace()
+ (Pdb) next
+ > <doctest test.test_pdb.test_pdb_issue_gh_136057[0]>(3)test_function()
+ -> lst = [i for i in range(10)]
+ (Pdb) next
+ > <doctest test.test_pdb.test_pdb_issue_gh_136057[0]>(4)test_function()
+ -> for i in lst: pass
+ (Pdb) step
+ --Return--
+ > <doctest
test.test_pdb.test_pdb_issue_gh_136057[0]>(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.
_______________________________________________
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]