-
-
Notifications
You must be signed in to change notification settings - Fork 31.9k
Support to jump between chained exception in Pdb #106670
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
Comments
This lets Pdb receive and exception, instead of a traceback, and when this is the case and the exception are chained, up/down allow to move between the chained exceptions when reaching the tot/bottom. That is to say if you have something like def out(): try: middle() # B except Exception as e: raise ValueError("foo(): bar failed") # A def middle(): try: return inner(0) # D except Exception as e: raise ValueError("Middle fail") # C def inner(x): 1 / x # E Only A is reachable after calling `out()` and doing post mortem debug. With this all A-E points are reachable with up/down. I do not change the default behavior of ``pdb.pm()``, but I think that arguably the default should be to pass `sys.last_value` so that chained exception navigation is enabled. Closes pythongh-106670
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.
|
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 End Aparte, back to original I don't think we can use up to go to
For me And anyway say you are in the debugger at 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
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. |
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 def out():
try:
i_fail()
except Exception as e:
handle_exception(e)
def i_fail():
1 / 0
def handle_exception(e):
even_more_functions(e)
def even_more_functions(e):
raise ValueError("Can't handle this") # This is the exception raised
out() How could I'm not saying That's why I ask the question up front - is I think a better solution might be a separate command to list and track exceptions, for example, |
I'll try to implement that as a do_exception command. Do you still think we should have |
We want this to work for From my point of view, we need to support both I know you asked about We definitely still need the path for |
This lets Pdb receive and exception, instead of a traceback, and when this is the case and the exception are chained, `exceptions` allow to list and move between the chained exceptions when reaching the tot/bottom. That is to say if you have something like def out(): try: middle() # B except Exception as e: raise ValueError("foo(): bar failed") # A def middle(): try: return inner(0) # D except Exception as e: raise ValueError("Middle fail") # C def inner(x): 1 / x # E Only A is reachable after calling `out()` and doing post mortem debug. With this all A-E points are reachable with a combination of up/down, and ``exception <number>``. I also change the default behavior of ``pdb.pm()``, to receive `sys.last_value` so that chained exception navigation is enabled. Closes pythongh-106670
I rebased/pushed and updated the description of #106676
|
This lets Pdb receive and exception, instead of a traceback, and when this is the case and the exception are chained, `exceptions` allow to list and move between the chained exceptions when reaching the tot/bottom. That is to say if you have something like def out(): try: middle() # B except Exception as e: raise ValueError("foo(): bar failed") # A def middle(): try: return inner(0) # D except Exception as e: raise ValueError("Middle fail") # C def inner(x): 1 / x # E Only A is reachable after calling `out()` and doing post mortem debug. With this all A-E points are reachable with a combination of up/down, and ``exception <number>``. I also change the default behavior of ``pdb.pm()``, to receive `sys.last_value` so that chained exception navigation is enabled. Closes pythongh-106670
This lets Pdb receive an exception, instead of a traceback, and when this is the case and the exception are chained, `exceptions` allow to list and move between the chained exceptions. That is to say if you have something like def out(): try: middle() # B except Exception as e: raise ValueError("foo(): bar failed") # A def middle(): try: return inner(0) # D except Exception as e: raise ValueError("Middle fail") from e # C def inner(x): 1 / x # E Only A is reachable after calling `out()` and doing post mortem debug. With this all A-E points are reachable with a combination of up/down, and ``exception <number>``. Note that while above each exception have a unique `__cause__`/`__context__`, when both are present and different, each one is separately listed (see later commits) This also change the default behavior of ``pdb.pm()``, to receive `sys.last_exc` so that chained exception navigation is enabled. Closes pythongh-106670
This lets Pdb receive an exception, instead of a traceback, and when this is the case and the exception are chained, `exceptions` allow to list and move between the chained exceptions. That is to say if you have something like def out(): try: middle() # B except Exception as e: raise ValueError("foo(): bar failed") # A def middle(): try: return inner(0) # D except Exception as e: raise ValueError("Middle fail") from e # C def inner(x): 1 / x # E Only A is reachable after calling `out()` and doing post mortem debug. With this all A-E points are reachable with a combination of up/down, and ``exception <number>``. This also change the default behavior of ``pdb.pm()``, to receive `sys.last_exc` so that chained exception navigation is enabled. Closes pythongh-106670
This lets Pdb receive an exception, instead of a traceback, and when this is the case and the exception are chained, the new `exceptions` command allows to both list (no arguments) and move between the chained exceptions. That is to say if you have something like def out(): try: middle() # B except Exception as e: raise ValueError("foo(): bar failed") # A def middle(): try: return inner(0) # D except Exception as e: raise ValueError("Middle fail") from e # C def inner(x): 1 / x # E Only A was reachable after calling `out()` and doing post mortem debug. With this all A-E points are reachable with a combination of up/down, and ``exception <number>``. This also change the default behavior of ``pdb.pm()``, as well as `python -m pdb <script.py>` to receive `sys.last_exc` so that chained exception navigation is enabled. We do follow the logic of the ``traceback`` module and handle the ``_context__`` and ``__cause__`` in the same way. That is to say, we try ``__cause__`` first, and if not present chain with ``__context__``. In the same vein, if we encounter an exception that has ``__suppress_context__`` (like when ``raise ... from None``), we do stop walking the chain. Some implementation notes: - We do handle cycle in exceptions - cleanup of references to tracebacks are not cleared in ``forget()``, as ``setup()`` and ``forget()`` are both for setting a single exception. - We do not handle sub-exceptions of exception groups. Closes pythongh-106670
The introduction of chained exception in pythongh-106676 would lead to File .../Lib/pdb.py", line 298, in setup self.curframe = self.stack[self.curindex][0] ~~~~~~~~~~^^^^^^^^^^^^^^^ IndexError: list index out of range This fixes that by filtering exceptions that that do not have a stack. Update tests to not use stack-less exceptions when testing another feature, and add an explicit test on how we handle stackless exceptions.
The introduction of chained exception in pythongh-106676 would lead to File .../Lib/pdb.py", line 298, in setup self.curframe = self.stack[self.curindex][0] ~~~~~~~~~~^^^^^^^^^^^^^^^ IndexError: list index out of range This fixes that by filtering exceptions that that do not have a stack. Update tests to not use stack-less exceptions when testing another feature, and add an explicit test on how we handle stackless exceptions.
The introduction of chained exception in pythongh-106676 would sometime lead to File .../Lib/pdb.py", line 298, in setup self.curframe = self.stack[self.curindex][0] ~~~~~~~~~~^^^^^^^^^^^^^^^ IndexError: list index out of range This fixes that by filtering exceptions that that do not have a stack/traceback. Update tests to not use stack-less exceptions when testing another feature, and add an explicit test on how we handle stackless exceptions.
…nGH-132277) (cherry picked from commit efd8aca) Co-authored-by: Tian Gao <[email protected]>
Feature or enhancement
I believe it would be useful to allow to move between chained exception in Pdb.
That is to say if you have
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.
Previous discussion
See,
https://discuss.python.org/t/interested-in-support-to-jump-between-chained-exception-in-pdb/29470/3
Linked PRs
The text was updated successfully, but these errors were encountered: