You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Support to jump between chained exception in Pdb #106670
I believe it would be useful to allow to move between chained exception in Pdb.
That is to say if you have
try:
function_that_raises()
except Exception as e:
raise ... from e # Pdb says this is the bottom frame.
Havin something like down go down the chained exception ? This was requested on IPython's ipdb, But I believe this could be brought to Pdb as well.
Picth
When moving up and down the stack in Pdb in chained exception, when hitting the bottom of the stack, it should be possible to look at the __cause__ or __context__ and jump to the top of it. And vice-versa when going up if we store the various TB we went through.
In post-mortem debugging this should allow to better understand the reason for an exception.
The general idea is great, yes giving the users the ability to take a look at chained exceptions is a good feature for pdb.
However, we probably need extra discussions for how this should be achieved.
How would the users use it? The current entry is too deep and no user would ever use pdb like that.
Is reusing up and down a good idea?
First of all, I think the current implementation is inverted. up in stack means "going backward in time" because it's going to the callers, which should be used to get the previous chained exception. That's how the current traceback of chained exception is displayed, and that's the ipdb issue suggested.
I'm having concerns for reusing up and down for this because it's not exactly the same thing. It's not completely irrelavent, but still.
If we decide to reuse up and down, we should probably give some hints to the users about it - it's kind of secluded now. If I were a debugger user, having a call stack with ALL the exceptions could be interesting - like the traceback. Of course we should have some indicators to seperate the exceptions.
However, this solution has its own problem, as the outermost exception could've had the full call stack - it's a bit weird to stepping up to the very top caller then to the previous exception.
The other solution could be having a set of new commands for chained exceptions to switch between them(is it an overkill?).
How would the users use it? The current entry is too deep and no user would ever use pdb like that.
I want to decouple implementation from actually exposing it, I think in the end, ``import pdb; pdb.pm()` should just make this work.
First of all, I think the current implementation is inverted. up in stack means "going backward in time" because it's going to the callers, which should be used to get the previous chained exception. That's how the current traceback of chained exception is displayed, and that's the ipdb issue suggested.
I disagree with this – I also find the normal chained traceback backward.
Aparte
Instead of DeepException During handling of the above exception, another exception occurred: MiddleException ... I would prefer MiddleException Was cause by DeeperException.
I guess it depends wether the reraise was on purpose, which I guess is more explicit with raise ... from ..., or wether an actual error append during the error handling
End Aparte, back to original
I don't think we can use up to go to __cause__/__context__.
Say you have
For me i_fail() is definitely a callee of out(), so moving from out() to i_fail() is going down. There is no notion of time in this.
And anyway say you are in the debugger at # here on line 5; up already brings you to out() on line 10, the only place you can go is therefore down... and you reach the top of i_fail() call.
I think that might be what you are trying to say with the following.
However, this solution has its own problem, as the outermost exception could've had the full call stack - it's a bit weird to stepping up to the very top caller then to the previous exception.
After playing a bit with it, I do find the current up/down pretty natural, if you think about it in term of intermediate try/except chained exception being absent. You just happen to stop on the except Exception as e: raise ... line. This is also highlighted by the fact that the original issue mentions Exception.add_note, so I believe we should really view this without the intermediate try/except.
The other solution could be having a set of new commands for chained exceptions to switch between them(is it an overkill?).
One thing that might settle this is exception groups, is we add commands to move between chained exception we can extend those to move between sub exception groups. I do not have async project where I use exception groups though so this is pure speculation.
Anyway, happy to go with the route cpython prefers.
Instead of DeepException During handling of the above exception, another exception occurred: MiddleException ... I would prefer MiddleException Was cause by DeeperException.
I guess it depends wether the reraise was on purpose, which I guess is more explicit with raise ... from ..., or wether an actual error append during the error handling
Unless you can convince core devs to change that in CPython, I'm afraid we should respect that order :)
For me i_fail() is definitely a callee of out(), so moving from out() to i_fail() is going down. There is no notion of time in this.
And anyway say you are in the debugger at # here on line 5; up already brings you to out() on line 10, the only place you can go is therefore down... and you reach the top of i_fail() call.
Only if your chained exception is raised in the same frame as your try ... except block. I guess your thoughts about the usages are more about a direct raise in the exception handling code, but what about:
defout():
try:
i_fail()
exceptExceptionase:
handle_exception(e)
defi_fail():
1/0defhandle_exception(e):
even_more_functions(e)
defeven_more_functions(e):
raiseValueError("Can't handle this") # This is the exception raisedout()
How could down make any sense here?
I'm not saying up is a good choice, but it's conforming to the current traceback (that you did not like).
That's why I ask the question up front - is up and down good candidates for such feature? What we really have is multiple exceptions that are linked together as they were raised when handling each other.
I think a better solution might be a separate command to list and track exceptions, for example, exception. Like breakpoints, exception can list out all the current exceptions in post_mortem mode (even on exception event in normal debugging). exception <exc_number> will switch the context to that exception. We probably will be able to handle exception groups this way.
We want this to work for pm and post_mortem eventually (probably in this PR), but I doubt if we can simply change the input type for post_mortem to Exception - that's a breaking change. So we probably need to keep the traceback path anyway. I'd like @iritkatriel's input here as she's been reviewing my pdb code and she's the expert in Exceptions.
From my point of view, we need to support both Exception and traceback for post_mortem - traceback itself is not enough to get all the exception chain information. The questions is whether we add another argument for post_mortem (which would keep the full backward compatibility but the two arguments are kind of mutually exclusive), or we make the current argument which takes an exception (which is better code, but either need to use the word "traceback" for potential exception, or break backward compatibility for those who use the keyword "traceback" to call the function).
I know you asked about interaction, but the way we handle the user interface can be the way we handle interaction - however it's not an exposed API so we have a bit more flexibility there.
We definitely still need the path for traceback for interaction as we need to keep the path for post_mortem, but I don't like the idea of taking a list of tracebacks, as we'll lose the data for the exceptions. I think we need to store the exception(or exceptions) in pdb so we can display it.
Activity
Allow Pdb to move between chained exception.
gaogaotiantian commentedon Jul 12, 2023
The general idea is great, yes giving the users the ability to take a look at chained exceptions is a good feature for pdb.
However, we probably need extra discussions for how this should be achieved.
upanddowna good idea?upin stack means "going backward in time" because it's going to the callers, which should be used to get the previous chained exception. That's how the current traceback of chained exception is displayed, and that's the ipdb issue suggested.upanddownfor this because it's not exactly the same thing. It's not completely irrelavent, but still.upanddown, we should probably give some hints to the users about it - it's kind of secluded now. If I were a debugger user, having a call stack with ALL the exceptions could be interesting - like the traceback. Of course we should have some indicators to seperate the exceptions.Carreau commentedon Jul 12, 2023
Thanks for the feedback,
I want to decouple implementation from actually exposing it, I think in the end, ``import pdb; pdb.pm()` should just make this work.
I disagree with this – I also find the normal chained traceback backward.
Aparte
Instead of DeepException
During handling of the above exception, another exception occurred:MiddleException ... I would prefer MiddleExceptionWas cause byDeeperException.I guess it depends wether the reraise was on purpose, which I guess is more explicit with
raise ... from ..., or wether an actual error append during the error handlingEnd Aparte, back to original
I don't think we can use up to go to
__cause__/__context__.Say you have
For me
i_fail()is definitely a callee ofout(), so moving fromout()toi_fail()is going down. There is no notion of time in this.And anyway say you are in the debugger at
# hereon line 5;upalready brings you toout()on line 10, the only place you can go is therefore down... and you reach the top ofi_fail()call.I think that might be what you are trying to say with the following.
After playing a bit with it, I do find the current up/down pretty natural, if you think about it in term of intermediate try/except chained exception being absent. You just happen to stop on the
except Exception as e: raise ...line. This is also highlighted by the fact that the original issue mentions Exception.add_note, so I believe we should really view this without the intermediate try/except.One thing that might settle this is exception groups, is we add commands to move between chained exception we can extend those to move between sub exception groups. I do not have async project where I use exception groups though so this is pure speculation.
Anyway, happy to go with the route cpython prefers.
gaogaotiantian commentedon Jul 12, 2023
Unless you can convince core devs to change that in CPython, I'm afraid we should respect that order :)
Only if your chained exception is raised in the same frame as your
try ... exceptblock. I guess your thoughts about the usages are more about a direct raise in the exception handling code, but what about:How could
downmake any sense here?I'm not saying
upis a good choice, but it's conforming to the current traceback (that you did not like).That's why I ask the question up front - is
upanddowngood candidates for such feature? What we really have is multiple exceptions that are linked together as they were raised when handling each other.I think a better solution might be a separate command to list and track exceptions, for example,
exception. Like breakpoints,exceptioncan list out all the current exceptions in post_mortem mode (even on exception event in normal debugging).exception <exc_number>will switch the context to that exception. We probably will be able to handle exception groups this way.Carreau commentedon Jul 13, 2023
I'll try to implement that as a do_exception command.
Do you still think we should have
interactiontake an exception, or should be instead accept a list of tracebacks?gaogaotiantian commentedon Jul 13, 2023
We want this to work for
pmandpost_mortemeventually (probably in this PR), but I doubt if we can simply change the input type forpost_mortemtoException- that's a breaking change. So we probably need to keep the traceback path anyway. I'd like @iritkatriel's input here as she's been reviewing my pdb code and she's the expert in Exceptions.From my point of view, we need to support both
Exceptionandtracebackforpost_mortem-tracebackitself is not enough to get all the exception chain information. The questions is whether we add another argument forpost_mortem(which would keep the full backward compatibility but the two arguments are kind of mutually exclusive), or we make the current argument which takes an exception (which is better code, but either need to use the word "traceback" for potential exception, or break backward compatibility for those who use the keyword "traceback" to call the function).I know you asked about
interaction, but the way we handle the user interface can be the way we handleinteraction- however it's not an exposed API so we have a bit more flexibility there.We definitely still need the path for
tracebackfor interaction as we need to keep the path forpost_mortem, but I don't like the idea of taking a list of tracebacks, as we'll lose the data for the exceptions. I think we need to store the exception(or exceptions) in pdb so we can display it.Allow Pdb to move between chained exception.
Carreau commentedon Jul 18, 2023
I rebased/pushed and updated the description of #106676
pdb.pm(), now uselast_valueif present by default.tracebackname for parameters, and check withisinstance(..., BaseException).do_exceptionsthat takes:"list": to enumerate the exception, and have a cursor to current exception.Allow Pdb to move between chained exception.
Allow Pdb to move between chained exception.
Allow Pdb to move between chained exception.
Merge remote-tracking branch 'github/pythongh-106670' into pythongh-1…
Allow Pdb to move between chained exception.
Merge branch 'main' into pythongh-106670
gh-106670: Allow Pdb to move between chained exceptions (#106676)
pythongh-106670: Better handle Exceptions with no stacks.
pythongh-106670: Fix Pdb handling of chained Exceptions with no stacks.
pythongh-106670: Fix Pdb handling of chained Exceptions with no stacks.
gh-106670: Fix Pdb handling of chained Exceptions with no stacks. (#1…
gh-106670: Set convenience variable for post mortem debugging (#110493)
pythongh-106670: Set convenience variable for post mortem debugging (p…
gh-106670: Fix a typo in doc of pdb's exceptions command (#132277)
pythongh-106670: Fix a typo in doc of pdb's exceptions command (pytho…
[3.13] gh-106670: Fix a typo in doc of pdb's exceptions command (GH-1…