Skip to content

Commit e1e9bab

Browse files
authored
gh-102778: Add sys.last_exc, deprecate sys.last_type, sys.last_value,sys.last_traceback (#102779)
1 parent 039714d commit e1e9bab

File tree

22 files changed

+103
-36
lines changed

22 files changed

+103
-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

Include/internal/pycore_global_objects_fini_generated.h

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Include/internal/pycore_global_strings.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,7 @@ struct _Py_global_strings {
481481
STRUCT_FOR_ID(kw2)
482482
STRUCT_FOR_ID(lambda)
483483
STRUCT_FOR_ID(last)
484+
STRUCT_FOR_ID(last_exc)
484485
STRUCT_FOR_ID(last_node)
485486
STRUCT_FOR_ID(last_traceback)
486487
STRUCT_FOR_ID(last_type)

Include/internal/pycore_runtime_init_generated.h

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Include/internal/pycore_unicodeobject_generated.h

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

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
@@ -118,7 +118,10 @@ def distb(tb=None, *, file=None, show_caches=False, adaptive=False):
118118
"""Disassemble a traceback (default: last traceback)."""
119119
if tb is None:
120120
try:
121-
tb = sys.last_traceback
121+
if hasattr(sys, 'last_exc'):
122+
tb = sys.last_exc.__traceback__
123+
else:
124+
tb = sys.last_traceback
122125
except AttributeError:
123126
raise RuntimeError("no last traceback to disassemble") from None
124127
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

0 commit comments

Comments
 (0)