Add convenience variables like $foo to pdb, which would be global and temporary. There is a similar feature in gdb.
Pitch
Currently, if the user needs to store something temporarily, they need to use a real variable in the current frame, which could potentially interfere with their program (overwrite an existing variable, or messing up with checks in the future). Also, there is no easy way for the users to create a variable that's accessible when they explore every frame.
An easily distinguishable variable (that starts with $) which is global and temporary would solve this issue. Behind the curtain, we simply replace the variable with a secret variable in global dict and clear the dict when pdb gives control back to the program.
With this feature, we actually solves another issue - it's super non-intuitive to access to some key data in the debugger. For example, retval. There's an issue for this #86690. You can display the value use retval, but to actually get access to it, you need something undocumented and hacky - locals()['__return__']. You can only do that when you are in the frame that's returning (which kind of makes sense, but only the BOTTOM ONE frame can be at this state). Also, there's the f_locals disaster that we have not yet solved #102864.
Another example would be the current frame. You'd be surprised that it's super difficult to access the current frame object you are debugging, sys._getframe() and its variance won't give you what you want.
So, we introduce a couple of internal convenience variables
$_frame - the current frame being debugged
$_retval - the return value if the bottom function is returning (this is globally distinct)
$_exception - the (exc_type, exc_value) tuple if an exception is being raised
This could be easily extended in the future to store variables that users are interested in but don't have easy access to.
Exec_value currently means the exception itself, making exec_type == exec_value.class redundant. I would just make $_exception the exception. @iritkatriel do you agree?
I actually think making $_exception the exception itself is the way to go. However, locals()['__exception__'] stores the tuple, and that's why I went with the tuple. I totally agree to make it just the exception value.
If we can gradually deprecate the secret local variable, it might clean up the structure even more. aka replace locals()['__exception__'] and locals()['__return__'] with the convenience variable stored globally.
However, the behavior of retval would change(it can't be used in upper frames now).
But for now, I do believe convenience variable is a helpful improvement.
Exec_value currently means the exception itself, making exec_type == exec_value.class redundant. I would just make $_exception the exception. @iritkatriel do you agree?
@iritkatriel actually, locals()['__exception__'] is not used anywhere else and it's not documented. It's possible that some code out there is using the secret variable. Do we want to change what's stored in it, or just store a different(well partial) value in $_exception?
$_exception will only store the exception value now
$_exception will be non-persistent, meaning it will only exist when the program is raising the exception, not after(even during the exception handling). This is a design choice now, which basically links the $_exception variable to the exception event. If this is not desirable, we can check for exceptions every time we setup the debugger and set the value. (This should be possible right? @iritkatriel is the expert here). Also updated the docs/tests.
Activity
terryjreedy commented on Apr 23, 2023
Exec_value currently means the exception itself, making exec_type == exec_value.class redundant. I would just make $_exception the exception. @iritkatriel do you agree?
gaogaotiantian commented on Apr 23, 2023
I actually think making $_exception the exception itself is the way to go. However, locals()['__exception__'] stores the tuple, and that's why I went with the tuple. I totally agree to make it just the exception value.
If we can gradually deprecate the secret local variable, it might clean up the structure even more. aka replace locals()['__exception__'] and locals()['__return__'] with the convenience variable stored globally.
However, the behavior of retval would change(it can't be used in upper frames now).
But for now, I do believe convenience variable is a helpful improvement.
iritkatriel commented on Apr 23, 2023
Yes, the type is redundant.
gaogaotiantian commented on Apr 23, 2023
@iritkatriel actually, locals()['__exception__'] is not used anywhere else and it's not documented. It's possible that some code out there is using the secret variable. Do we want to change what's stored in it, or just store a different(well partial) value in $_exception?
iritkatriel commented on Apr 23, 2023
If you’re going to deprecate the local then I think there’s no point changing it.
gaogaotiantian commented on Apr 23, 2023
Okay I made some changes:
gh-103693: Add convenience variable feature to `pdb` (#103694)