-
-
Notifications
You must be signed in to change notification settings - Fork 30.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
gh-119824: Print stack entry when user input is needed #119882
Conversation
Co-authored-by: Irit Katriel <[email protected]>
Hi @iritkatriel , do you think the comments are understandable now? We have another issue caused by this bug so it would be nice to fix it :) |
Lib/pdb.py
Outdated
2. a command to continue execution is encountered | ||
|
||
The return value is | ||
True - if the user input is expected after processing, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
True - if the user input is expected after processing, | |
True - if user input is expected after processing, |
What if instead of adding a fake instruction, you remember what the last executed instruction was, and use that to decide how to proceed? |
The problem is - we can't break out of the cmdloop. That's out of our control, unless I change the code of The purpose is pretty strightfoward - to print something between the input from Without that hook, we had to fake something to break out of the cmdloop and re-gain the control.
All the sentinel stuff is to achieve this print between draining the The only other option is to print the line before commands from |
Actually, I'm not sure if the alternate is possible. So let's go back a step and take a look at the original problem: Normally, we want to print the stack entry:
However, things got complicated, when If the
That just sets a breakpoint and run, why would pdb prints the stack entry? So, maybe if commands from
The user input is expected and we should print the stack in this case. So the key is to determine whether the user input is expected, and print the stack info if so. Well that may seem like an easy thing to do, but because all the Maybe we can be smart and simply check if a execution resume command ( Well there are two problems:
It's a simple bug, yes, but not all simple bugs have simple solutions. This one particularly, I really don't have any idea about how to make it simpler while keeping it correct (reasonable). If there's a hook in |
This is not what I proposed. I proposed that the decision be made on the basis of what WAS executed, not what WILL BE executed. Can cmd not return the last instruction it executed? |
I don't understand your approach. It's not about what commands were already executed, it's about how to break out of the command loop. Where do you suggest to put the code in? We need And BTW, no, cmd does not keep the last command executed. So here's the loop in cmd: while not stop:
if self.cmdqueue:
line = self.cmdqueue.pop(0)
else:
if self.use_rawinput:
try:
line = input(self.prompt)
except EOFError:
line = 'EOF'
else:
self.stdout.write(self.prompt)
self.stdout.flush()
line = self.stdin.readline()
if not len(line):
line = 'EOF'
else:
line = line.rstrip('\r\n')
line = self.precmd(line)
stop = self.onecmd(line)
stop = self.postcmd(stop, line) The purpose is to print something after |
In the same place you changed. Instead of checking whether the 'sentinel' is in the queue, check what the last instruction executed was. |
That won't work because the code will be stuck in |
If you're returning control just to print the stack, then you could instead add an instruction that prints the stack and doesn't return control. |
That's a possible solution, but that requires a new feature to fix the bug. This needs to be backported to 3.13 and 3.12 - do you think that's doable? We will add a new command to 3.12. Instead of a completely new command (that does a really simple thing), we could add an argument to The code won't be super clean either (maybe better than the current fix). In self.setup(frame, tb)
# if we have more commands to process, do not show the stack entry
if not self.cmdqueue:
self.print_stack_entry(self.stack[self.curindex])
self._cmdloop()
self.forget() will become something like self.setup(frame, tb)
# if we have more commands to process, show stack entry at the end
if not self.cmdqueue:
someflag = True
self.cmdqueue.append('w 1')
self._cmdloop()
# if cmdqueue is not drained, pop the command
# notice that someflag can't be ignored because self._cmdloop() can potentially
# fill self.cmdqueue with `;;`
if self.cmdqueue and someflag:
self.cmdqueue.pop(-1)
self.forget() |
If w will continue working as before without the new arg then I think that's fine. |
Sure we can try that approach. It will also involve some command appending and popping, but it won't use the sentinel command which might be hard to get. |
Okay I used the where approach. This makes the |
I removed the backport tags so I can do a manual backport for this fix. If we want to be even safer, we can only backport the There is a slight side effect - if the last command executed is the I think the safe way is to clear the last command if the command is The more important reason is that I plan to (in the future) replace the current print with |
Co-authored-by: Irit Katriel <[email protected]>
Fixed the comment too (I caught this once but then I was distracted and forgot about it). Do you want to merge it or do you want me to merge? |
You can merge. |
Thanks for the review. For the backport, do you want me to only remove the docs, or remove the |
…119882) Co-authored-by: Irit Katriel <[email protected]>
GH-120533 is a backport of this pull request to the 3.13 branch. |
) (#120533) Co-authored-by: Irit Katriel <[email protected]>
…needed (pythonGH-119882) (python#120533)" This reverts commit 1c41aa7.
…119882) Co-authored-by: Irit Katriel <[email protected]>
…119882) Co-authored-by: Irit Katriel <[email protected]>
…119882) Co-authored-by: Irit Katriel <[email protected]>
We currently determine whether to print the stack entry by checking if
self.cmdqueue
is empty. However, that's not the best user experience. The expected behavior is - if pdb expects user input, the stack entry should be printed, otherwise it should not.This patch does a small trick to achieve that without changing
cmd.Cmd
- it appends astep
command afterself.cmdqueue
if it's not empty and let it finish thecmdloop
. If thestep
command is executed (self.cmdqueue
is exhausted), then that means the originalself.cmdqueue
does not have a resuming command and extra user inputs are expected. Otherwise we can simply pop the artificialstep
out and skip the user input part.There will be a side effect for
step
command, but it will be overwritten by the resuming command from user input.(issuing a
step
command only sets some config, it will not relinquish control immediately)I considered this a bug fix because the current behavior is different than it was before (stack entry is not printed when
.pdbrc
exists), and this patch will revert that behavior. Thus the backport.pdb._post_mortem
behavior if.pdbrc
exists #119824