-
Notifications
You must be signed in to change notification settings - Fork 231
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
Make the Debugger a singleton and do not reset the stopframe to None during postmortem. #667
base: main
Are you sure you want to change the base?
Make the Debugger a singleton and do not reset the stopframe to None during postmortem. #667
Conversation
…during postmortem. This fixes inducer#607. Making the Debugger a singleton should be enough to fix inducer#607. HOWEVER, pytest def postmortem() calls .reset() which resets the stopframe. Somehow, this causes the debugger to stop somewhere inside internal debugger source code, instead of in the code the postmortem should be done. So, this also includes an override of the .reset() method and detects when the debugger is already running and does not reset the stopframe. See also inducer#67.
Reproduce issue. Install pytest and pudb.
def test_foo():
breakpoint()
raise Exception pytest --pdbcls pudb.debugger:Debugger --pdb --capture=no test.py NB. The stopframe issue (#52) can also be observed with pytest-pudb using pytest --pudb test.py |
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.
Thanks. Some comments below.
pudb/debugger.py
Outdated
import linecache | ||
linecache.checkcache() | ||
self.botframe = None | ||
if not self._pytest_postmortem: | ||
self.stopframe = None | ||
else: | ||
self._pytest_postmortem = False | ||
self.returnframe = None | ||
self.quitting = False | ||
self.stoplineno = 0 |
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.
Would it be possible to call into Bdb.reset
for some of this? We're already copy-pasting too much of Bdb's guts into pudb... (If not, add a comment why not.)
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.
When calling Bdb.reset the debugger stops around there. self.stopframe = None
is the offending line. Calling Bdb.reset is a no-go. It is the exact same problem for #67 where also code is copies from Bdb in here. The problem now is that pytest is calling .reset, so that is why the override is needed and to check for the pytest postmortem state. I can add a link to the source of pytest as well, but I believe the docstring of this method explain already enough.
Do you think there needs to be more information in the docstring of this method to explain why it needs to be overriden?
# Okay, now we have a debugger | ||
self._current_debugger.append(self) |
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.
Could we get rid of _current_debugger
in favor of the singleton mechanism?
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.
That is logic in place for _get_debugger
. This has to remain. That is all fine.
Trying to instantiate a debugger again (and thus previously hitting the ValueError) is what pytest is doing. Thus my code only works around that specific pytest problem. All logic around _get_debugger
is fine, but pytest is just not calling it.
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.
This has to remain.
Why? There are now essentially two copies of singleton-management code floating around. My question is aimed at reducing that to one.
@inducer Added more comments. |
|
||
Override from Bdb.reset() | ||
|
||
When pytest starts a postmortem analysis, but the debugger is already active, |
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.
active
What does "active" mean in this context? How is this circumstance detected?
# Otherwise calling _get_debugger should be called. | ||
# This flag keeps track of the pytest postmortem situation to disable | ||
# a problematic line in Bbd.reset() | ||
cls._pytest_postmortem = True |
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.
How can we be sure that this case is only hit by pytest, as the code suggests? Could the condition under which this triggers be made a bit more narrow?
# Okay, now we have a debugger | ||
self._current_debugger.append(self) |
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.
This has to remain.
Why? There are now essentially two copies of singleton-management code floating around. My question is aimed at reducing that to one.
Unsubscribing... @-mention or request review once it's ready for a look or needs attention. |
This fixes #607. Making the Debugger a singleton should be enough to fix #607. HOWEVER, pytest def postmortem() calls .reset() which resets the stopframe. Somehow, this causes the debugger to stop somewhere inside internal debugger source code, instead of in the code the postmortem should be done.
So, this also includes an override of the .reset() method and detects when the debugger is already running and does not reset the stopframe. See also #67.