Skip to content

Commit 8be3b2f

Browse files
gh-136057: Allow step and next to step over for loops (#136160)
1 parent be699d6 commit 8be3b2f

File tree

3 files changed

+50
-4
lines changed

3 files changed

+50
-4
lines changed

Lib/bdb.py

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,8 @@ def __init__(self, skip=None, backend='settrace'):
199199
self.frame_returning = None
200200
self.trace_opcodes = False
201201
self.enterframe = None
202+
self.cmdframe = None
203+
self.cmdlineno = None
202204
self.code_linenos = weakref.WeakKeyDictionary()
203205
self.backend = backend
204206
if backend == 'monitoring':
@@ -297,7 +299,12 @@ def dispatch_line(self, frame):
297299
self.user_line(). Raise BdbQuit if self.quitting is set.
298300
Return self.trace_dispatch to continue tracing in this scope.
299301
"""
300-
if self.stop_here(frame) or self.break_here(frame):
302+
# GH-136057
303+
# For line events, we don't want to stop at the same line where
304+
# the latest next/step command was issued.
305+
if (self.stop_here(frame) or self.break_here(frame)) and not (
306+
self.cmdframe == frame and self.cmdlineno == frame.f_lineno
307+
):
301308
self.user_line(frame)
302309
self.restart_events()
303310
if self.quitting: raise BdbQuit
@@ -526,7 +533,8 @@ def _set_trace_opcodes(self, trace_opcodes):
526533
if self.monitoring_tracer:
527534
self.monitoring_tracer.update_local_events()
528535

529-
def _set_stopinfo(self, stopframe, returnframe, stoplineno=0, opcode=False):
536+
def _set_stopinfo(self, stopframe, returnframe, stoplineno=0, opcode=False,
537+
cmdframe=None, cmdlineno=None):
530538
"""Set the attributes for stopping.
531539
532540
If stoplineno is greater than or equal to 0, then stop at line
@@ -539,6 +547,10 @@ def _set_stopinfo(self, stopframe, returnframe, stoplineno=0, opcode=False):
539547
# stoplineno >= 0 means: stop at line >= the stoplineno
540548
# stoplineno -1 means: don't stop at all
541549
self.stoplineno = stoplineno
550+
# cmdframe/cmdlineno is the frame/line number when the user issued
551+
# step/next commands.
552+
self.cmdframe = cmdframe
553+
self.cmdlineno = cmdlineno
542554
self._set_trace_opcodes(opcode)
543555

544556
def _set_caller_tracefunc(self, current_frame):
@@ -564,15 +576,17 @@ def set_until(self, frame, lineno=None):
564576

565577
def set_step(self):
566578
"""Stop after one line of code."""
567-
self._set_stopinfo(None, None)
579+
# set_step() could be called from signal handler so enterframe might be None
580+
self._set_stopinfo(None, None, cmdframe=self.enterframe,
581+
cmdlineno=getattr(self.enterframe, 'f_lineno', None))
568582

569583
def set_stepinstr(self):
570584
"""Stop before the next instruction."""
571585
self._set_stopinfo(None, None, opcode=True)
572586

573587
def set_next(self, frame):
574588
"""Stop on the next line in or below the given frame."""
575-
self._set_stopinfo(frame, None)
589+
self._set_stopinfo(frame, None, cmdframe=frame, cmdlineno=frame.f_lineno)
576590

577591
def set_return(self, frame):
578592
"""Stop when returning from the given frame."""

Lib/test/test_pdb.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3232,6 +3232,37 @@ def test_pdb_issue_gh_127321():
32323232
"""
32333233

32343234

3235+
def test_pdb_issue_gh_136057():
3236+
"""See GH-136057
3237+
"step" and "next" commands should be able to get over list comprehensions
3238+
>>> def test_function():
3239+
... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace()
3240+
... lst = [i for i in range(10)]
3241+
... for i in lst: pass
3242+
3243+
>>> with PdbTestInput([ # doctest: +NORMALIZE_WHITESPACE
3244+
... 'next',
3245+
... 'next',
3246+
... 'step',
3247+
... 'continue',
3248+
... ]):
3249+
... test_function()
3250+
> <doctest test.test_pdb.test_pdb_issue_gh_136057[0]>(2)test_function()
3251+
-> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace()
3252+
(Pdb) next
3253+
> <doctest test.test_pdb.test_pdb_issue_gh_136057[0]>(3)test_function()
3254+
-> lst = [i for i in range(10)]
3255+
(Pdb) next
3256+
> <doctest test.test_pdb.test_pdb_issue_gh_136057[0]>(4)test_function()
3257+
-> for i in lst: pass
3258+
(Pdb) step
3259+
--Return--
3260+
> <doctest test.test_pdb.test_pdb_issue_gh_136057[0]>(4)test_function()->None
3261+
-> for i in lst: pass
3262+
(Pdb) continue
3263+
"""
3264+
3265+
32353266
def test_pdb_issue_gh_80731():
32363267
"""See GH-80731
32373268
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
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.

0 commit comments

Comments
 (0)