Skip to content

Conversation

@gaogaotiantian
Copy link
Member

@gaogaotiantian gaogaotiantian commented Jul 1, 2025

Due to historical reasons, sys.settrace issues a line event for for loops even if the jump target is on the same line:

# 10 line events on this line
for _ in range(10): pass

We don't want to touch this behavior, because it's been like this for like forever.

However, it's not desirable to pdb. When the user does next or step command, they want to step over this line and reach the next line.

Our documentation also clearly states such behavior:

s(tep)
Execute the current line, stop at the first possible occasion (either in a function that is called or on the next line in the current function).

n(ext)
Continue execution until the next line in the current function is reached or it returns. (The difference between next and step is that step stops inside a called function, while next executes called functions at (nearly) full speed, only stopping at the next line in the current function.)

So I consider the current behavior as a bug, which we should fix.

A thought might be - why don't we check this in stop_here? The reason is because dispatch_exception also uses stop_here and we should trigger user_exception even if it's on the same line.

An extra check in dispatch_line is the cleanest way I can think of to make this happen - only line events should be dealt with. We don't need to worry about the extra reference to a frame because the eventual continue (or anything other than step or next) will clear this reference.

Let me know if anyone has a better idea of how to implement this.

Lib/bdb.py Outdated
if self.stop_here(frame) or self.break_here(frame):
# GH-136057
# For line events, besides whether we should stop at the frame, we
# also need to check if it's the same line as we issue the command.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is very clear: "it's the same line as we issue the command". I think you mean "the same frame and line at which the break command was issued by the user".

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not the break command, it's either next or step. But yes I'm open to all suggestions to make this clearer.

Lib/bdb.py Outdated
self.stoplineno = stoplineno
# startframe/startlineno is the frame/line number when the user does
# step or next. We don't want to stop at the same line for those commands.
self.startframe = startframe
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we could pick a more informative name, something like "command frame", because it's ambiguous here what exactly started at that frame.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah we can change it, but there's actually a caveat here - it's not really the command frame. You can do up to an upper frame and do next/step - the behavior is different. next will next to the line at the upper frame, so the frame we need is the "command frame". step however, will stop at the innermost frame, no matter which frame you are inspecting - that's just how step works.

So it's more like a "do not stop here again if it's a line event" frame/lineno. Do you think there's better name to describe it?

@gaogaotiantian
Copy link
Member Author

@iritkatriel do you think the current name and comments are better?

Lib/bdb.py Outdated
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
# we issue the previous next/step command.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we stop, it's not necessarily due to a next/step, right? Could it also be a breakpoint or until, etc?

So maybe the comment can say:

If we are stopping due to a next/step command, we don't want to stop on the same line on which
the command was issued.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I'm thinking. If we are currently at line 10, and the user does a until 10, should we stop at the current line? And if we stopped by a breakpoint, then we do continue, should we stop at the same line? Those are kind of undefined behaviors, unlike step and next which explicitly said that the debugger should stop at the "next" line.

@gaogaotiantian
Copy link
Member Author

Hi @iritkatriel , want to circle back to this. I made a small change to initialize the attributes - just merged a PR for pdb so I think might as well do it for at least the newly added attributes for bdb.


def test_pdb_issue_gh_136057():
"""See GH-136057
"step" and "next" commands should be able to get over list comprehensions
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't it be that next steps over the list comp but step executes every iteration?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not according to our documentation

Execute the current line, stop at the first possible occasion (either in a function that is called or on the next line in the current function).

I mean we can have different interpretation of the phrase "first possible occasion". Technically we can do this at bytecode level - but that's probably not we really want. I think we should stick to the explanation in the parenthesis.

@gaogaotiantian gaogaotiantian merged commit 8be3b2f into python:main Nov 16, 2025
46 checks passed
@miss-islington-app
Copy link

Thanks @gaogaotiantian for the PR 🌮🎉.. I'm working now to backport this PR to: 3.13, 3.14.
🐍🍒⛏🤖 I'm not a witch! I'm not a witch!

@gaogaotiantian gaogaotiantian deleted the pdb-next-for-loop branch November 16, 2025 21:57
miss-islington pushed a commit to miss-islington/cpython that referenced this pull request Nov 16, 2025
@miss-islington-app
Copy link

Sorry, @gaogaotiantian, I could not cleanly backport this to 3.13 due to a conflict.
Please backport using cherry_picker on command line.

cherry_picker 8be3b2f479431f670f2e81e41b52e698c0806289 3.13

@bedevere-app
Copy link

bedevere-app bot commented Nov 16, 2025

GH-141640 is a backport of this pull request to the 3.14 branch.

@bedevere-app bedevere-app bot removed the needs backport to 3.14 bugs and security fixes label Nov 16, 2025
@bedevere-app
Copy link

bedevere-app bot commented Nov 16, 2025

GH-141641 is a backport of this pull request to the 3.13 branch.

@bedevere-app bedevere-app bot removed the needs backport to 3.13 bugs and security fixes label Nov 16, 2025
gaogaotiantian added a commit that referenced this pull request Nov 16, 2025
…) (#141640)

gh-136057: Allow step and next to step over for loops (GH-136160)
(cherry picked from commit 8be3b2f)

Co-authored-by: Tian Gao <[email protected]>
gaogaotiantian added a commit that referenced this pull request Nov 16, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants