8000 gh-102778: Add sys.last_exc, deprecate sys.last_type, sys.last_value,… · Fidget-Spinner/cpython@0d85488 · GitHub
[go: up one dir, main page]

Skip to content

Commit 0d85488

Browse files
iritkatrielFidget-Spinner
authored andcommitted
pythongh-102778: Add sys.last_exc, deprecate sys.last_type, sys.last_value,sys.last_traceback (python#102779)
1 parent b019008 commit 0d85488

File tree

18 files changed

+97
-36
lines changed

18 files changed

+97
-36
lines changed

Doc/library/sys.rst

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1102,22 +1102,25 @@ always available.
11021102

11031103
.. versionadded:: 3.5
11041104

1105+
.. data:: last_exc
1106+
1107+
This variable is not always defined; it is set to the exception instance
1108+
when an exception is not handled and the interpreter prints an error message
1109+
and a stack traceback. Its intended use is to allow an interactive user to
1110+
import a debugger module and engage in post-mortem debugging without having
1111+
to re-execute the command that caused the error. (Typical use is
1112+
``import pdb; pdb.pm()`` to enter the post-mortem debugger; see :mod:`pdb`
1113+
module for more information.)
1114+
1115+
.. versionadded:: 3.12
11051116

11061117
.. data:: last_type
11071118
last_value
11081119
last_traceback
11091120

1110-
These three variables are not always defined; they are set when an exception is
1111-
not handled and the interpreter prints an error message and a stack traceback.
1112-
Their intended use is to allow an interactive user to import a debugger module
1113-
and engage in post-mortem debugging without having to re-execute the command
1114-
that caused the error. (Typical use is ``import pdb; pdb.pm()`` to enter the
1115-
post-mortem debugger; see :mod:`pdb` module for
1116-
more information.)
1117-
1118-
The meaning of the variables is the same as that of the return values from
1119-
:func:`exc_info` above.
1120-
1121+
These three variables are deprecated; use :data:`sys.last_exc` instead.
1122+
They hold the legacy representation of ``sys.last_exc``, as returned
1123+
from :func:`exc_info` above.
11211124

11221125
.. data:: maxsize
11231126

Doc/whatsnew/3.12.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,12 @@ sys
397397
with contributions from Gregory P. Smith [Google] and Mark Shannon
398398
in :gh:`96123`.)
399399

400+
* Add :data:`sys.last_exc` which holds the last unhandled exception that
401+
was raised (for post-mortem debugging use cases). Deprecate the
402+
three fields that have the same information in its legacy form:
403+
:data:`sys.last_type`, :data:`sys.last_value` and :data:`sys.last_traceback`.
404+
(Contributed by Irit Katriel in :gh:`102778`.)
405+
400406

401407
Optimizations
402408
=============
@@ -488,6 +494,10 @@ Deprecated
488494
contain the creation time, which is also available in the new ``st_birthtime``
489495
field. (Contributed by Steve Dower in :gh:`99726`.)
490496

497+
* The :data:`sys.last_type`, :data:`sys.last_value` and :data:`sys.last_traceback`
498+
fields are deprecated. Use :data:`sys.last_exc` instead.
499+
(Contributed by Irit Katriel in :gh:`102778`.)
500+
491501
Pending Removal in Python 3.13
492502
------------------------------
493503

Lib/code.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ def showsyntaxerror(self, filename=None):
106106
107107
"""
108108
type, value, tb = sys.exc_info()
109+
sys.last_exc = value
109110
sys.last_type = type
110111
sys.last_value = value
111112
sys.last_traceback = tb
@@ -119,7 +120,7 @@ def showsyntaxerror(self, filename=None):
119120
else:
120121
# Stuff in the right filename
121122
value = SyntaxError(msg, (filename, lineno, offset, line))
122-
sys.last_value = value
123+
sys.last_exc = sys.last_value = value
123124
if sys.excepthook is sys.__excepthook__:
124125
lines = traceback.format_exception_only(type, value)
125126
self.write(''.join(lines))
@@ -138,6 +139,7 @@ def showtraceback(self):
138139
"""
139140
sys.last_type, sys.last_value, last_tb = ei = sys.exc_info()
140141
sys.last_traceback = last_tb
142+
sys.last_exc = ei[1]
141143
try:
142144
lines = traceback.format_exception(ei[0], ei[1], last_tb.tb_next)
143145
if sys.excepthook is sys.__excepthook__:

Lib/dis.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,10 @@ def distb(tb=None, *, file=None, show_caches=False, adaptive=False):
132132
"""Disassemble a traceback (default: last traceback)."""
133133
if tb is None:
134134
try:
135-
tb = sys.last_traceback
135+
if hasattr(sys, 'last_exc'):
136+
tb = sys.last_exc.__traceback__
137+
else:
138+
tb = sys.last_traceback
136139
except AttributeError:
137140
raise RuntimeError("no last traceback to disassemble") from None
138141
while tb.tb_next: tb = tb.tb_next

Lib/idlelib/idle_test/test_stackviewer.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ def setUpClass(cls):
1919
except NameError:
2020
svs.last_type, svs.last_value, svs.last_traceback = (
2121
sys.exc_info())
22+
svs.last_exc = svs.last_value
2223

2324
requires('gui')
2425
cls.root = Tk()
@@ -27,7 +28,7 @@ def setUpClass(cls):
2728
@classmethod
2829
def tearDownClass(cls):
2930
svs = stackviewer.sys
30-
del svs.last_traceback, svs.last_type, svs.last_value
31+
del svs.last_exc, svs.last_traceback, svs.last_type, svs.last_value
3132

3233
cls.root.update_idletasks()
3334
## for id in cls.root.tk.call('after', 'info'):

Lib/idlelib/pyshell.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1367,11 +1367,14 @@ def open_stack_viewer(self, event=None):
13671367
if self.interp.rpcclt:
13681368
return self.interp.remote_stack_viewer()
13691369
try:
1370-
sys.last_traceback
1370+
if hasattr(sys, 'last_exc'):
1371+
sys.last_exc.__traceback__
1372+
else:
1373+
sys.last_traceback
13711374
except:
13721375
messagebox.showerror("No stack trace",
13731376
"There is no stack trace yet.\n"
1374-
"(sys.last_traceback is not defined)",
1377+
"(sys.last_exc and sys.last_traceback are not defined)",
13751378
parent=self.text)
13761379
return
13771380
from idlelib.stackviewer import StackBrowser

Lib/idlelib/run.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,7 @@ def print_exception():
239239
efile = sys.stderr
240240
typ, val, tb = excinfo = sys.exc_info()
241241
sys.last_type, sys.last_value, sys.last_traceback = excinfo
242+
sys.last_exc = val
242243
seen = set()
243244

244245
def print_exc(typ, exc, tb):
@@ -629,6 +630,7 @@ def stackviewer(self, flist_oid=None):
629630
flist = self.rpchandler.get_remote_proxy(flist_oid)
630631
while tb and tb.tb_frame.f_globals["__name__"] in ["rpc", "run"]:
631632
tb = tb.tb_next
633+
sys.last_exc = val
632634
sys.last_type = typ
633635
sys.last_value = val
634636
item = stackviewer.StackTreeItem(flist, tb)

Lib/idlelib/stackviewer.py

Lines changed: 15 additions & 6 deletions
49
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,10 @@ def __init__(self, flist=None, tb=None):
2727

2828
def get_stack(self, tb):
2929
if tb is None:
30-
tb = sys.last_traceback
30+
if hasattr(sys, 'last_exc'):
31+
tb = sys.last_exc.__traceback__
32+
else:
33+
tb = sys.last_traceback
3134
stack = []
3235
if tb and tb.tb_frame is None:
3336
tb = tb.tb_next
@@ -37,11 +40,15 @@ def get_stack(self, tb):
3740
return stack
3841

3942
def get_exception(self):
40-
type = sys.last_type
41-
value = sys.last_value
42-
if hasattr(type, "__name__"):
43-
type = type.__name__
44-
s = str(type)
43+
if hasattr(sys, 'last_exc'):
44+
typ = type(sys.last_exc)
45+
value = sys.last_exc
46+
else:
47+
typ = sys.last_type
48+
value = sys.last_value
+
if hasattr(typ, "__name__"):
50+
typ = typ.__name__
51+
s = str(typ)
4552
if value is not None:
4653
s = s + ": " + str(value)
4754
return s
@@ -136,13 +143,15 @@ def _stack_viewer(parent): # htest #
136143
except NameError:
137144
exc_type, exc_value, exc_tb = sys.exc_info()
138145
# inject stack trace to sys
146+
sys.last_exc = exc_value
139147
sys.last_type = exc_type
140148
sys.last_value = exc_value
141149
sys.last_traceback = exc_tb
142150

143151
StackBrowser(top, flist=flist, top=top, tb=exc_tb)
144152

145153
# restore sys to original state
154+
del sys.last_exc
146155
del sys.last_type
147156
del sys.last_value
148157
del sys.last_traceback

Lib/pdb.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1739,7 +1739,11 @@ def post_mortem(t=None):
17391739

17401740
def pm():
17411741
"""Enter post-mortem debugging of the traceback found in sys.last_traceback."""
1742-
post_mortem(sys.last_traceback)
1742+
if hasattr(sys, 'last_exc'):
1743+
tb = sys.last_exc.__traceback__
1744+
else:
1745+
tb = sys.last_traceback
1746+
post_mortem(tb)
17431747

17441748

17451749
# Main program for testing

Lib/pydoc_data/topics.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4799,7 +4799,7 @@
47994799
'pdb.pm()\n'
48004800
'\n'
48014801
' Enter post-mortem debugging of the traceback found in\n'
4802-
' "sys.last_traceback".\n'
4802+
' "sys.last_exc".\n'
48034803
'\n'
48044804
'The "run*" functions and "set_trace()" are aliases for '
48054805
'instantiating\n'
@@ -13858,7 +13858,7 @@
1385813858
'if\n'
1385913859
' the interpreter is interactive, it is also made available to '
1386013860
'the\n'
13861-
' user as "sys.last_traceback".\n'
13861+
' user as "sys.last_exc".\n'
1386213862
'\n'
1386313863
' For explicitly created tracebacks, it is up to the creator '
1386413864
'of\n'

0 commit comments

Comments
 (0)
0