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

Commit5f3433f

Browse files
authored
gh-106670: Fix Pdb handling of chained Exceptions with no stacks. (#108865)
1 parent44892b1 commit5f3433f

File tree

2 files changed

+108
-30
lines changed

2 files changed

+108
-30
lines changed

‎Lib/pdb.py

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -494,6 +494,8 @@ def interaction(self, frame, tb_or_exc):
494494
Pdb._previous_sigint_handler=None
495495

496496
_chained_exceptions,tb=self._get_tb_and_exceptions(tb_or_exc)
497+
ifisinstance(tb_or_exc,BaseException):
498+
asserttbisnotNone,"main exception must have a traceback"
497499
withself._hold_exceptions(_chained_exceptions):
498500
ifself.setup(frame,tb):
499501
# no interaction desired at this time (happens if .pdbrc contains
@@ -1169,14 +1171,23 @@ def do_exceptions(self, arg):
11691171
rep=repr(exc)
11701172
iflen(rep)>80:
11711173
rep=rep[:77]+"..."
1172-
self.message(f"{prompt}{ix:>3}{rep}")
1174+
indicator= (
1175+
" -"
1176+
ifself._chained_exceptions[ix].__traceback__isNone
1177+
elsef"{ix:>3}"
1178+
)
1179+
self.message(f"{prompt}{indicator}{rep}")
11731180
else:
11741181
try:
11751182
number=int(arg)
11761183
exceptValueError:
11771184
self.error("Argument must be an integer")
11781185
return
11791186
if0<=number<len(self._chained_exceptions):
1187+
ifself._chained_exceptions[number].__traceback__isNone:
1188+
self.error("This exception does not have a traceback, cannot jump to it")
1189+
return
1190+
11801191
self._chained_exception_index=number
11811192
self.setup(None,self._chained_exceptions[number].__traceback__)
11821193
self.print_stack_entry(self.stack[self.curindex])
@@ -2010,19 +2021,27 @@ def post_mortem(t=None):
20102021
If `t` is an exception object, the `exceptions` command makes it possible to
20112022
list and inspect its chained exceptions (if any).
20122023
"""
2024+
return_post_mortem(t,Pdb())
2025+
2026+
2027+
def_post_mortem(t,pdb_instance):
2028+
"""
2029+
Private version of post_mortem, which allow to pass a pdb instance
2030+
for testing purposes.
2031+
"""
20132032
# handling the default
20142033
iftisNone:
20152034
exc=sys.exception()
20162035
ifexcisnotNone:
20172036
t=exc.__traceback__
20182037

2019-
iftisNone:
2038+
iftisNoneor (isinstance(t,BaseException)andt.__traceback__isNone):
20202039
raiseValueError("A valid traceback must be passed if no "
20212040
"exception is being handled")
20222041

2023-
p=Pdb()
2024-
p.reset()
2025-
p.interaction(None,t)
2042+
pdb_instance.reset()
2043+
pdb_instance.interaction(None,t)
2044+
20262045

20272046
defpm():
20282047
"""Enter post-mortem debugging of the traceback found in sys.last_exc."""

‎Lib/test/test_pdb.py

Lines changed: 84 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -848,9 +848,7 @@ def test_post_mortem_chained():
848848
... try:
849849
... test_function_reraise()
850850
... except Exception as e:
851-
... # same as pdb.post_mortem(e), but with custom pdb instance.
852-
... instance.reset()
853-
... instance.interaction(None, e)
851+
... pdb._post_mortem(e, instance)
854852
855853
>>> with PdbTestInput([ # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE
856854
... 'exceptions',
@@ -907,24 +905,30 @@ def test_post_mortem_chained():
907905
deftest_post_mortem_cause_no_context():
908906
"""Test post mortem traceback debugging of chained exception
909907
908+
>>> def make_exc_with_stack(type_, *content, from_=None):
909+
... try:
910+
... raise type_(*content) from from_
911+
... except Exception as out:
912+
... return out
913+
...
914+
910915
>>> def main():
911916
... try:
912917
... raise ValueError('Context Not Shown')
913918
... except Exception as e1:
914-
... raise ValueError("With Cause") fromTypeError('The Cause')
919+
... raise ValueError("With Cause") frommake_exc_with_stack(TypeError,'The Cause')
915920
916921
>>> def test_function():
917922
... import pdb;
918923
... instance = pdb.Pdb(nosigint=True, readrc=False)
919924
... try:
920925
... main()
921926
... except Exception as e:
922-
... # same as pdb.post_mortem(e), but with custom pdb instance.
923-
... instance.reset()
924-
... instance.interaction(None, e)
927+
... pdb._post_mortem(e, instance)
925928
926929
>>> with PdbTestInput([ # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE
927930
... 'exceptions',
931+
... 'exceptions 0',
928932
... 'exceptions 1',
929933
... 'up',
930934
... 'down',
@@ -934,20 +938,23 @@ def test_post_mortem_cause_no_context():
934938
... test_function()
935939
... except ValueError:
936940
... print('Ok.')
937-
> <doctest test.test_pdb.test_post_mortem_cause_no_context[0]>(5)main()
938-
-> raise ValueError("With Cause") fromTypeError('The Cause')
941+
> <doctest test.test_pdb.test_post_mortem_cause_no_context[1]>(5)main()
942+
-> raise ValueError("With Cause") frommake_exc_with_stack(TypeError,'The Cause')
939943
(Pdb) exceptions
940-
0 TypeError('The Cause')
941-
> 1 ValueError('With Cause')
944+
0 TypeError('The Cause')
945+
> 1 ValueError('With Cause')
946+
(Pdb) exceptions 0
947+
> <doctest test.test_pdb.test_post_mortem_cause_no_context[0]>(3)make_exc_with_stack()
948+
-> raise type_(*content) from from_
942949
(Pdb) exceptions 1
943-
> <doctest test.test_pdb.test_post_mortem_cause_no_context[0]>(5)main()
944-
-> raise ValueError("With Cause") fromTypeError('The Cause')
950+
> <doctest test.test_pdb.test_post_mortem_cause_no_context[1]>(5)main()
951+
-> raise ValueError("With Cause") frommake_exc_with_stack(TypeError,'The Cause')
945952
(Pdb) up
946-
> <doctest test.test_pdb.test_post_mortem_cause_no_context[1]>(5)test_function()
953+
> <doctest test.test_pdb.test_post_mortem_cause_no_context[2]>(5)test_function()
947954
-> main()
948955
(Pdb) down
949-
> <doctest test.test_pdb.test_post_mortem_cause_no_context[0]>(5)main()
950-
-> raise ValueError("With Cause") fromTypeError('The Cause')
956+
> <doctest test.test_pdb.test_post_mortem_cause_no_context[1]>(5)main()
957+
-> raise ValueError("With Cause") frommake_exc_with_stack(TypeError,'The Cause')
951958
(Pdb) exit"""
952959

953960

@@ -971,9 +978,7 @@ def test_post_mortem_context_of_the_cause():
971978
... try:
972979
... main()
973980
... except Exception as e:
974-
... # same as pdb.post_mortem(e), but with custom pdb instance.
975-
... instance.reset()
976-
... instance.interaction(None, e)
981+
... pdb._post_mortem(e, instance)
977982
978983
>>> with PdbTestInput([ # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE
979984
... 'exceptions',
@@ -1046,9 +1051,7 @@ def test_post_mortem_from_none():
10461051
... try:
10471052
... main()
10481053
... except Exception as e:
1049-
... # same as pdb.post_mortem(e), but with custom pdb instance.
1050-
... instance.reset()
1051-
... instance.interaction(None, e)
1054+
... pdb._post_mortem(e, instance)
10521055
10531056
>>> with PdbTestInput([ # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE
10541057
... 'exceptions',
@@ -1066,6 +1069,64 @@ def test_post_mortem_from_none():
10661069
"""
10671070

10681071

1072+
deftest_post_mortem_from_no_stack():
1073+
"""Test post mortem traceback debugging of chained exception
1074+
1075+
especially when one exception has no stack.
1076+
1077+
>>> def main():
1078+
... raise Exception() from Exception()
1079+
1080+
1081+
>>> def test_function():
1082+
... import pdb;
1083+
... instance = pdb.Pdb(nosigint=True, readrc=False)
1084+
... try:
1085+
... main()
1086+
... except Exception as e:
1087+
... pdb._post_mortem(e, instance)
1088+
1089+
>>> with PdbTestInput( # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE
1090+
... ["exceptions",
1091+
... "exceptions 0",
1092+
... "exit"],
1093+
... ):
1094+
... try:
1095+
... test_function()
1096+
... except ValueError:
1097+
... print('Correctly reraised.')
1098+
> <doctest test.test_pdb.test_post_mortem_from_no_stack[0]>(2)main()
1099+
-> raise Exception() from Exception()
1100+
(Pdb) exceptions
1101+
- Exception()
1102+
> 1 Exception()
1103+
(Pdb) exceptions 0
1104+
*** This exception does not have a traceback, cannot jump to it
1105+
(Pdb) exit
1106+
"""
1107+
1108+
1109+
deftest_post_mortem_single_no_stack():
1110+
"""Test post mortem called when origin exception has no stack
1111+
1112+
1113+
>>> def test_function():
1114+
... import pdb;
1115+
... instance = pdb.Pdb(nosigint=True, readrc=False)
1116+
... import sys
1117+
... sys.last_exc = Exception()
1118+
... pdb._post_mortem(sys.last_exc, instance)
1119+
1120+
>>> with PdbTestInput( # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE
1121+
... []
1122+
... ):
1123+
... try:
1124+
... test_function()
1125+
... except ValueError as e:
1126+
... print(e)
1127+
A valid traceback must be passed if no exception is being handled
1128+
"""
1129+
10691130
deftest_post_mortem_complex():
10701131
"""Test post mortem traceback debugging of chained exception
10711132
@@ -1130,9 +1191,7 @@ def test_post_mortem_complex():
11301191
... try:
11311192
... main()
11321193
... except Exception as e:
1133-
... # same as pdb.post_mortem(e), but with custom pdb instance.
1134-
... instance.reset()
1135-
... instance.interaction(None, e)
1194+
... pdb._post_mortem(e, instance)
11361195
11371196
>>> with PdbTestInput( # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE
11381197
... ["exceptions",

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp