Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitdef928d

Browse files
committed
Allow Pdb to move between chained exception.
This lets Pdb receive and exception, instead of a traceback, and whenthis is the case and the exception are chained, up/down allow to movebetween 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 # EOnly 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 thatarguably the default should be to pass `sys.last_value` so that chainedexception navigation is enabled.Closesgh-106670
1 parentbe1b968 commitdef928d

File tree

3 files changed

+113
-2
lines changed

3 files changed

+113
-2
lines changed

‎Lib/pdb.py

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,7 @@ def namespace(self):
206206
line_prefix='\n-> '# Probably a better default
207207

208208
classPdb(bdb.Bdb,cmd.Cmd):
209+
_chained_exceptions= []
209210

210211
_previous_sigint_handler=None
211212

@@ -416,6 +417,15 @@ def preloop(self):
416417

417418
definteraction(self,frame,traceback):
418419
# Restore the previous signal handler at the Pdb prompt.
420+
421+
ifisinstance(traceback,BaseException):
422+
traceback,exception=traceback.__traceback__,traceback
423+
self._chained_exceptions= [exception]
424+
else:
425+
self._chained_exceptions= []
426+
427+
# list of exceptions in chain exception, we always start with the current one.
428+
419429
ifPdb._previous_sigint_handler:
420430
try:
421431
signal.signal(signal.SIGINT,Pdb._previous_sigint_handler)
@@ -1080,6 +1090,15 @@ def do_up(self, arg):
10801090
stack trace (to an older frame).
10811091
"""
10821092
ifself.curindex==0:
1093+
iflen(self._chained_exceptions)>1:
1094+
self.message("Oldest frame, moving to last frame upper exception")
1095+
self._chained_exceptions.pop()
1096+
self.setup(None,self._chained_exceptions[-1].__traceback__)
1097+
self.curindex=len(self.stack)
1098+
arg="0"
1099+
else:
1100+
self.error("Oldest frame")
1101+
return
10831102
self.error('Oldest frame')
10841103
return
10851104
try:
@@ -1101,8 +1120,17 @@ def do_down(self, arg):
11011120
stack trace (to a newer frame).
11021121
"""
11031122
ifself.curindex+1==len(self.stack):
1104-
self.error('Newest frame')
1105-
return
1123+
ifself._chained_exceptionsandself._chained_exceptions[-1].__context__:
1124+
new_ex=self._chained_exceptions[-1].__context__
1125+
1126+
self.message("Newest frame, moving into __context__ traceback.")
1127+
self._chained_exceptions.append(new_ex)
1128+
self.setup(None,new_ex.__traceback__)
1129+
self.curindex=-1
1130+
arg="1"
1131+
else:
1132+
self.error("Newest frame")
1133+
return
11061134
try:
11071135
count=int(argor1)
11081136
exceptValueError:
@@ -1895,6 +1923,10 @@ def post_mortem(t=None):
18951923
If no traceback is given, it uses the one of the exception that is
18961924
currently being handled (an exception must be being handled if the
18971925
default is to be used).
1926+
1927+
If t is an Exception and is a chained exception (i.e it has a __context__),
1928+
pdb will be able to move to the sub-exception when reaching the bottom
1929+
frame.
18981930
"""
18991931
# handling the default
19001932
iftisNone:

‎Lib/test/test_pdb.py

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -826,6 +826,77 @@ def test_convenience_variables():
826826
(Pdb) continue
827827
"""
828828

829+
830+
deftest_post_mortem_chained():
831+
"""Test post mortem traceback debugging of chained exception
832+
833+
>>> def test_function_2():
834+
... try:
835+
... 1/0
836+
... finally:
837+
... print('Exception!')
838+
839+
>>> def test_function_reraise():
840+
... try:
841+
... test_function_2()
842+
... except ZeroDivisionError as e:
843+
... raise ZeroDivisionError('reraised') from e
844+
845+
>>> def test_function():
846+
... import pdb;
847+
... instance = pdb.Pdb(nosigint=True, readrc=False)
848+
... try:
849+
... test_function_reraise()
850+
... except Exception as e:
851+
... # same as pdb.post_mortem(e), but with custom pdb instance.
852+
... instance.reset()
853+
... instance.interaction(None, e)
854+
855+
>>> with PdbTestInput([ # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE
856+
... 'up',
857+
... 'up',
858+
... 'down',
859+
... 'down',
860+
... 'down',
861+
... 'down',
862+
... 'up',
863+
... 'up',
864+
... 'exit',
865+
... ]):
866+
... try:
867+
... test_function()
868+
... except ZeroDivisionError:
869+
... print('Correctly reraised.')
870+
Exception!
871+
> <doctest test.test_pdb.test_post_mortem_chained[1]>(5)test_function_reraise()
872+
-> raise ZeroDivisionError('reraised') from e
873+
(Pdb) up
874+
> <doctest test.test_pdb.test_post_mortem_chained[2]>(5)test_function()
875+
-> test_function_reraise()
876+
(Pdb) up
877+
*** Oldest frame
878+
(Pdb) down
879+
> <doctest test.test_pdb.test_post_mortem_chained[1]>(5)test_function_reraise()
880+
-> raise ZeroDivisionError('reraised') from e
881+
(Pdb) down
882+
Newest frame, moving into __context__ traceback.
883+
> <doctest test.test_pdb.test_post_mortem_chained[1]>(3)test_function_reraise()
884+
-> test_function_2()
885+
(Pdb) down
886+
> <doctest test.test_pdb.test_post_mortem_chained[0]>(3)test_function_2()
887+
-> 1/0
888+
(Pdb) down
889+
*** Newest frame
890+
(Pdb) up
891+
> <doctest test.test_pdb.test_post_mortem_chained[1]>(3)test_function_reraise()
892+
-> test_function_2()
893+
(Pdb) up
894+
Oldest frame, moving to last frame upper exception
895+
*** Oldest frame
896+
(Pdb) exit
897+
"""
898+
899+
829900
deftest_post_mortem():
830901
"""Test post mortem traceback debugging.
831902
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
Allow Pdb to move between chained exceptions on post_mortem debugging.
2+
3+
If Pdb.post_mortem() is called with a chained exception, it will now allow
4+
the user to move between the chained exceptions using ``up`` and ``down``
5+
commands.
6+
7+
When reaching the bottom of the stacktrace, Pdb will move the first frame of
8+
the next exception. And vice-versa, when reaching the top of the stacktrace.

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp