From 75e1496d4bbea6ab61c9cb5dd1917609b45f70d7 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Fri, 17 Mar 2023 13:41:04 +0000 Subject: [PATCH 1/7] gh-102778: Add sys.last_exc, deprecate sys.last_type, sys.last_value, sys.last_traceback --- Doc/library/sys.rst | 25 +++++++++++-------- .../pycore_global_objects_fini_generated.h | 1 + Include/internal/pycore_global_strings.h | 1 + .../internal/pycore_runtime_init_generated.h | 1 + .../internal/pycore_unicodeobject_generated.h | 3 +++ Lib/code.py | 2 ++ Python/pylifecycle.c | 2 +- Python/pythonrun.c | 4 +++ Python/sysmodule.c | 6 +++-- 9 files changed, 31 insertions(+), 14 deletions(-) diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index a53d4908783e15..d06d77b5944647 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -1102,22 +1102,25 @@ always available. .. versionadded:: 3.5 +.. data:: last_exc + + This variable is not always defined; it is set to the exception instance + when an exception is not handled and the interpreter prints an error message + and a stack traceback. Its intended use is to allow an interactive user to + import a debugger module and engage in post-mortem debugging without having + to re-execute the command that caused the error. (Typical use is + ``import pdb; pdb.pm()`` to enter the post-mortem debugger; see :mod:`pdb` + module for more information.) + + .. versionadded:: 3.12 .. data:: last_type last_value last_traceback - These three variables are not always defined; they are set when an exception is - not handled and the interpreter prints an error message and a stack traceback. - Their intended use is to allow an interactive user to import a debugger module - and engage in post-mortem debugging without having to re-execute the command - that caused the error. (Typical use is ``import pdb; pdb.pm()`` to enter the - post-mortem debugger; see :mod:`pdb` module for - more information.) - - The meaning of the variables is the same as that of the return values from - :func:`exc_info` above. - + These three variables are deprecated, use ``sys.last_exc`` instead. + They hold the legacy representation of ``sys.last_exc``, as returned + from :func:`exc_info` above. .. data:: maxsize diff --git a/Include/internal/pycore_global_objects_fini_generated.h b/Include/internal/pycore_global_objects_fini_generated.h index 4b12ae523c3260..14dfd9ea5823ed 100644 --- a/Include/internal/pycore_global_objects_fini_generated.h +++ b/Include/internal/pycore_global_objects_fini_generated.h @@ -995,6 +995,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(kw2)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(lambda)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(last)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(last_exc)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(last_node)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(last_traceback)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(last_type)); diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h index 17fb9ffbbf9f11..6f430bb25eb8d3 100644 --- a/Include/internal/pycore_global_strings.h +++ b/Include/internal/pycore_global_strings.h @@ -481,6 +481,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(kw2) STRUCT_FOR_ID(lambda) STRUCT_FOR_ID(last) + STRUCT_FOR_ID(last_exc) STRUCT_FOR_ID(last_node) STRUCT_FOR_ID(last_traceback) STRUCT_FOR_ID(last_type) diff --git a/Include/internal/pycore_runtime_init_generated.h b/Include/internal/pycore_runtime_init_generated.h index b240be57369d9d..0452c4c61551de 100644 --- a/Include/internal/pycore_runtime_init_generated.h +++ b/Include/internal/pycore_runtime_init_generated.h @@ -987,6 +987,7 @@ extern "C" { INIT_ID(kw2), \ INIT_ID(lambda), \ INIT_ID(last), \ + INIT_ID(last_exc), \ INIT_ID(last_node), \ INIT_ID(last_traceback), \ INIT_ID(last_type), \ diff --git a/Include/internal/pycore_unicodeobject_generated.h b/Include/internal/pycore_unicodeobject_generated.h index fea9b6dbb1a75f..0a8865942e6d5b 100644 --- a/Include/internal/pycore_unicodeobject_generated.h +++ b/Include/internal/pycore_unicodeobject_generated.h @@ -1296,6 +1296,9 @@ _PyUnicode_InitStaticStrings(void) { string = &_Py_ID(last); assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); + string = &_Py_ID(last_exc); + assert(_PyUnicode_CheckConsistency(string, 1)); + PyUnicode_InternInPlace(&string); string = &_Py_ID(last_node); assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); diff --git a/Lib/code.py b/Lib/code.py index 76000f8c8b2c1e..cb34e5fe87cad6 100644 --- a/Lib/code.py +++ b/Lib/code.py @@ -106,6 +106,7 @@ def showsyntaxerror(self, filename=None): """ type, value, tb = sys.exc_info() + sys.last_exc = value sys.last_type = type sys.last_value = value sys.last_traceback = tb @@ -138,6 +139,7 @@ def showtraceback(self): """ sys.last_type, sys.last_value, last_tb = ei = sys.exc_info() sys.last_traceback = last_tb + sys.last_exc = ei[1] try: lines = traceback.format_exception(ei[0], ei[1], last_tb.tb_next) if sys.excepthook is sys.__excepthook__: diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index d0c65cc1f7fd44..7bf12271db2323 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1304,7 +1304,7 @@ finalize_modules_delete_special(PyThreadState *tstate, int verbose) { // List of names to clear in sys static const char * const sys_deletes[] = { - "path", "argv", "ps1", "ps2", + "path", "argv", "ps1", "ps2", "last_exc", "last_type", "last_value", "last_traceback", "__interactivehook__", // path_hooks and path_importer_cache are cleared diff --git a/Python/pythonrun.c b/Python/pythonrun.c index 07d119a67847c6..6ea185a1b75bc9 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -776,6 +776,10 @@ _PyErr_PrintEx(PyThreadState *tstate, int set_sys_last_vars) } if (set_sys_last_vars) { + if (_PySys_SetAttr(&_Py_ID(last_exc), exc) < 0) { + _PyErr_Clear(tstate); + } + /* Legacy version: */ if (_PySys_SetAttr(&_Py_ID(last_type), typ) < 0) { _PyErr_Clear(tstate); } diff --git a/Python/sysmodule.c b/Python/sysmodule.c index cc5b9a6d418bfa..126b7d422e0009 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -2670,11 +2670,13 @@ stderr -- standard error object; used for error messages\n\ By assigning other file objects (or objects that behave like files)\n\ to these, it is possible to redirect all of the interpreter's I/O.\n\ \n\ +last_exc - the last uncaught exception\n\ + Only available in an interactive session after a\n\ + traceback has been printed.\n\ last_type -- type of last uncaught exception\n\ last_value -- value of last uncaught exception\n\ last_traceback -- traceback of last uncaught exception\n\ - These three are only available in an interactive session after a\n\ - traceback has been printed.\n\ + These three are the (deprecated) legacy representation of last_exc.\n\ " ) /* concatenating string here */ From 56185a98e67e0a58fd5f64892deff2d9ef54389b Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Fri, 17 Mar 2023 13:49:04 +0000 Subject: [PATCH 2/7] add news --- Doc/whatsnew/3.12.rst | 9 +++++++++ .../2023-03-17-13-43-34.gh-issue-102778.ANDv8I.rst | 2 ++ 2 files changed, 11 insertions(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-03-17-13-43-34.gh-issue-102778.ANDv8I.rst diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index b55b9619fac226..5657bb71f0c2af 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -397,6 +397,12 @@ sys with contributions from Gregory P. Smith [Google] and Mark Shannon in :gh:`96123`.) +* Add ``sys.last_exc`` which holds the last unhandled exception that + was raised (for post-mortem debugging use cases). Deprecate the + three fields that have the same information in its legacy form: + ``sys.last_type``, ``sys.last_value`` and ``sys.last_traceback``. + (Contributed by Irit Katriel in :gh:`102778`.) + Optimizations ============= @@ -488,6 +494,9 @@ Deprecated contain the creation time, which is also available in the new ``st_birthtime`` field. (Contributed by Steve Dower in :gh:`99726`.) +* The ``sys.last_type``, ``sys.last_value`` and ``sys.last_traceback`` fields. + Use ``sys.last_exc`` instead. (Contributed by Irit Katriel in :gh:`102778`.) + Pending Removal in Python 3.13 ------------------------------ diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-17-13-43-34.gh-issue-102778.ANDv8I.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-17-13-43-34.gh-issue-102778.ANDv8I.rst new file mode 100644 index 00000000000000..2dec901b9d8fba --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-03-17-13-43-34.gh-issue-102778.ANDv8I.rst @@ -0,0 +1,2 @@ +Add ``sys.last_exc`` and deprecate ``sys.last_type``, ``sys.last_value`` and +``sys.last_traceback``, which have the same info in its legacy form. From 4b7c63104554bcc01acba67f815dbfcc92388e31 Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Fri, 17 Mar 2023 13:51:03 +0000 Subject: [PATCH 3/7] use directive Co-authored-by: Alex Waygood --- Doc/library/sys.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index d06d77b5944647..b3b9b5e74ac068 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -1118,7 +1118,7 @@ always available. last_value last_traceback - These three variables are deprecated, use ``sys.last_exc`` instead. + These three variables are deprecated; use :data:`sys.last_exc` instead. They hold the legacy representation of ``sys.last_exc``, as returned from :func:`exc_info` above. From e1cc312ff7306b743d2ac048607a7bd38e9186a1 Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Fri, 17 Mar 2023 17:53:14 +0000 Subject: [PATCH 4/7] Apply suggestions from code review Co-authored-by: Alex Waygood --- Doc/whatsnew/3.12.rst | 9 +++++---- .../2023-03-17-13-43-34.gh-issue-102778.ANDv8I.rst | 5 +++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 5657bb71f0c2af..8d2eaacf3d2c81 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -397,10 +397,10 @@ sys with contributions from Gregory P. Smith [Google] and Mark Shannon in :gh:`96123`.) -* Add ``sys.last_exc`` which holds the last unhandled exception that +* Add :data:`sys.last_exc` which holds the last unhandled exception that was raised (for post-mortem debugging use cases). Deprecate the three fields that have the same information in its legacy form: - ``sys.last_type``, ``sys.last_value`` and ``sys.last_traceback``. + :data:`sys.last_type`, :data:`sys.last_value` and :data:`sys.last_traceback`. (Contributed by Irit Katriel in :gh:`102778`.) @@ -494,8 +494,9 @@ Deprecated contain the creation time, which is also available in the new ``st_birthtime`` field. (Contributed by Steve Dower in :gh:`99726`.) -* The ``sys.last_type``, ``sys.last_value`` and ``sys.last_traceback`` fields. - Use ``sys.last_exc`` instead. (Contributed by Irit Katriel in :gh:`102778`.) +* The :data:`sys.last_type`, :data:`sys.last_value` and :data:`sys.last_traceback` + fields. Use :data:`sys.last_exc` instead. + (Contributed by Irit Katriel in :gh:`102778`.) Pending Removal in Python 3.13 ------------------------------ diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-17-13-43-34.gh-issue-102778.ANDv8I.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-17-13-43-34.gh-issue-102778.ANDv8I.rst index 2dec901b9d8fba..b5da227afa5a69 100644 --- a/Misc/NEWS.d/next/Core and Builtins/2023-03-17-13-43-34.gh-issue-102778.ANDv8I.rst +++ b/Misc/NEWS.d/next/Core and Builtins/2023-03-17-13-43-34.gh-issue-102778.ANDv8I.rst @@ -1,2 +1,3 @@ -Add ``sys.last_exc`` and deprecate ``sys.last_type``, ``sys.last_value`` and -``sys.last_traceback``, which have the same info in its legacy form. +Add :data:`sys.last_exc` and deprecate :data:`sys.last_type`, :data:`sys.last_value` +and :data:`sys.last_traceback`, +which hold the same information in its legacy form. From 008355f2b1c021a0375b7c310743b269136ac735 Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Fri, 17 Mar 2023 18:47:24 +0000 Subject: [PATCH 5/7] doc tweak --- Doc/whatsnew/3.12.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 8d2eaacf3d2c81..32fec962560ae1 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -495,7 +495,7 @@ Deprecated field. (Contributed by Steve Dower in :gh:`99726`.) * The :data:`sys.last_type`, :data:`sys.last_value` and :data:`sys.last_traceback` - fields. Use :data:`sys.last_exc` instead. + fields are deprecated. Use :data:`sys.last_exc` instead. (Contributed by Irit Katriel in :gh:`102778`.) Pending Removal in Python 3.13 From 242708ebbb1a896f5aaf5cc584276210b6ba7f2c Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Fri, 17 Mar 2023 20:45:15 +0000 Subject: [PATCH 6/7] update stdlib --- Lib/code.py | 2 +- Lib/dis.py | 5 ++++- Lib/idlelib/idle_test/test_stackviewer.py | 3 ++- Lib/idlelib/pyshell.py | 7 +++++-- Lib/idlelib/run.py | 2 ++ Lib/idlelib/stackviewer.py | 15 ++++++++++++--- Lib/pdb.py | 6 +++++- Lib/pydoc_data/topics.py | 4 ++-- Lib/test/test_dis.py | 10 +++++++++- Lib/test/test_ttk/test_extensions.py | 4 +++- Lib/tkinter/__init__.py | 1 + Lib/traceback.py | 16 ++++++++++------ 12 files changed, 56 insertions(+), 19 deletions(-) diff --git a/Lib/code.py b/Lib/code.py index cb34e5fe87cad6..2bd5fa3e795a61 100644 --- a/Lib/code.py +++ b/Lib/code.py @@ -120,7 +120,7 @@ def showsyntaxerror(self, filename=None): else: # Stuff in the right filename value = SyntaxError(msg, (filename, lineno, offset, line)) - sys.last_value = value + sys.last_exc = sys.last_value = value if sys.excepthook is sys.__excepthook__: lines = traceback.format_exception_only(type, value) self.write(''.join(lines)) diff --git a/Lib/dis.py b/Lib/dis.py index 9edde6ae8258da..c3d152b4de0469 100644 --- a/Lib/dis.py +++ b/Lib/dis.py @@ -118,7 +118,10 @@ def distb(tb=None, *, file=None, show_caches=False, adaptive=False): """Disassemble a traceback (default: last traceback).""" if tb is None: try: - tb = sys.last_traceback + if hasattr(sys, 'last_exc'): + tb = sys.last_exc.__traceback__ + else: + tb = sys.last_traceback except AttributeError: raise RuntimeError("no last traceback to disassemble") from None while tb.tb_next: tb = tb.tb_next diff --git a/Lib/idlelib/idle_test/test_stackviewer.py b/Lib/idlelib/idle_test/test_stackviewer.py index 98f53f9537bb25..f4626bb1702a30 100644 --- a/Lib/idlelib/idle_test/test_stackviewer.py +++ b/Lib/idlelib/idle_test/test_stackviewer.py @@ -19,6 +19,7 @@ def setUpClass(cls): except NameError: svs.last_type, svs.last_value, svs.last_traceback = ( sys.exc_info()) + svs.last_exc = svs.last_value requires('gui') cls.root = Tk() @@ -27,7 +28,7 @@ def setUpClass(cls): @classmethod def tearDownClass(cls): svs = stackviewer.sys - del svs.last_traceback, svs.last_type, svs.last_value + del svs.last_exc, svs.last_traceback, svs.last_type, svs.last_value cls.root.update_idletasks() ## for id in cls.root.tk.call('after', 'info'): diff --git a/Lib/idlelib/pyshell.py b/Lib/idlelib/pyshell.py index e68233a5a4131e..edc77ff26f62f7 100755 --- a/Lib/idlelib/pyshell.py +++ b/Lib/idlelib/pyshell.py @@ -1367,11 +1367,14 @@ def open_stack_viewer(self, event=None): if self.interp.rpcclt: return self.interp.remote_stack_viewer() try: - sys.last_traceback + if hasattr(sys, 'last_exc'): + sys.last_exc.__traceback__ + else: + sys.last_traceback except: messagebox.showerror("No stack trace", "There is no stack trace yet.\n" - "(sys.last_traceback is not defined)", + "(sys.last_exc and sys.last_traceback are not defined)", parent=self.text) return from idlelib.stackviewer import StackBrowser diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py index 577c49eb67b20d..6a7b50cf5cfb27 100644 --- a/Lib/idlelib/run.py +++ b/Lib/idlelib/run.py @@ -239,6 +239,7 @@ def print_exception(): efile = sys.stderr typ, val, tb = excinfo = sys.exc_info() sys.last_type, sys.last_value, sys.last_traceback = excinfo + sys.last_exc = val seen = set() def print_exc(typ, exc, tb): @@ -629,6 +630,7 @@ def stackviewer(self, flist_oid=None): flist = self.rpchandler.get_remote_proxy(flist_oid) while tb and tb.tb_frame.f_globals["__name__"] in ["rpc", "run"]: tb = tb.tb_next + sys.last_exc = val sys.last_type = typ sys.last_value = val item = stackviewer.StackTreeItem(flist, tb) diff --git a/Lib/idlelib/stackviewer.py b/Lib/idlelib/stackviewer.py index 94ffb4eff4dd26..855fc7a562991b 100644 --- a/Lib/idlelib/stackviewer.py +++ b/Lib/idlelib/stackviewer.py @@ -27,7 +27,10 @@ def __init__(self, flist=None, tb=None): def get_stack(self, tb): if tb is None: - tb = sys.last_traceback + if hasattr(sys, 'last_exc'): + tb = sys.last_exc.__traceback__ + else: + tb = sys.last_traceback stack = [] if tb and tb.tb_frame is None: tb = tb.tb_next @@ -37,8 +40,12 @@ def get_stack(self, tb): return stack def get_exception(self): - type = sys.last_type - value = sys.last_value + if hasattr(sys, 'last_exc'): + type = type(sys.last_exc) + value = sys.last_exc + else: + type = sys.last_type + value = sys.last_value if hasattr(type, "__name__"): type = type.__name__ s = str(type) @@ -136,6 +143,7 @@ def _stack_viewer(parent): # htest # except NameError: exc_type, exc_value, exc_tb = sys.exc_info() # inject stack trace to sys + sys.last_exc = exc_value sys.last_type = exc_type sys.last_value = exc_value sys.last_traceback = exc_tb @@ -143,6 +151,7 @@ def _stack_viewer(parent): # htest # StackBrowser(top, flist=flist, top=top, tb=exc_tb) # restore sys to original state + del sys.last_exc del sys.last_type del sys.last_value del sys.last_traceback diff --git a/Lib/pdb.py b/Lib/pdb.py index f11fc55536810f..3543f53282db15 100755 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -1739,7 +1739,11 @@ def post_mortem(t=None): def pm(): """Enter post-mortem debugging of the traceback found in sys.last_traceback.""" - post_mortem(sys.last_traceback) + if hasattr(sys, 'last_exc'): + tb = sys.last_exc.__traceback__ + else: + tb = sys.last_traceback + post_mortem(tb) # Main program for testing diff --git a/Lib/pydoc_data/topics.py b/Lib/pydoc_data/topics.py index 573065b4b714d9..ad1b6aca6b95bc 100644 --- a/Lib/pydoc_data/topics.py +++ b/Lib/pydoc_data/topics.py @@ -4799,7 +4799,7 @@ 'pdb.pm()\n' '\n' ' Enter post-mortem debugging of the traceback found in\n' - ' "sys.last_traceback".\n' + ' "sys.last_exc".\n' '\n' 'The "run*" functions and "set_trace()" are aliases for ' 'instantiating\n' @@ -13858,7 +13858,7 @@ 'if\n' ' the interpreter is interactive, it is also made available to ' 'the\n' - ' user as "sys.last_traceback".\n' + ' user as "sys.last_exc".\n' '\n' ' For explicitly created tracebacks, it is up to the creator ' 'of\n' diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index b77e3b06d0c1f1..fa1de1c7ded1b3 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -1026,6 +1026,10 @@ def test_disassemble_try_finally(self): self.do_disassembly_test(_tryfinallyconst, dis_tryfinallyconst) def test_dis_none(self): + try: + del sys.last_exc + except AttributeError: + pass try: del sys.last_traceback except AttributeError: @@ -1043,7 +1047,7 @@ def test_dis_traceback(self): 1/0 except Exception as e: tb = e.__traceback__ - sys.last_traceback = tb + sys.last_exc = e tb_dis = self.get_disassemble_as_string(tb.tb_frame.f_code, tb.tb_lasti) self.do_disassembly_test(None, tb_dis, True) @@ -1900,6 +1904,10 @@ def test_findlabels(self): class TestDisTraceback(DisTestBase): def setUp(self) -> None: + try: # We need to clean up existing tracebacks + del sys.last_exc + except AttributeError: + pass try: # We need to clean up existing tracebacks del sys.last_traceback except AttributeError: diff --git a/Lib/test/test_ttk/test_extensions.py b/Lib/test/test_ttk/test_extensions.py index 6135c49701f08e..d5e069716971fe 100644 --- a/Lib/test/test_ttk/test_extensions.py +++ b/Lib/test/test_ttk/test_extensions.py @@ -45,7 +45,9 @@ def test_widget_destroy(self): # value which causes the tracing callback to be called and then # it tries calling instance attributes not yet defined. ttk.LabeledScale(self.root, variable=myvar) - if hasattr(sys, 'last_type'): + if hasattr(sys, 'last_exc'): + self.assertNotEqual(type(sys.last_exc), tkinter.TclError) + elif hasattr(sys, 'last_type'): self.assertNotEqual(sys.last_type, tkinter.TclError) def test_initialization(self): diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py index 7565e0f7e46073..479daf0e5abfc3 100644 --- a/Lib/tkinter/__init__.py +++ b/Lib/tkinter/__init__.py @@ -2400,6 +2400,7 @@ def report_callback_exception(self, exc, val, tb): should when sys.stderr is None.""" import traceback print("Exception in Tkinter callback", file=sys.stderr) + sys.last_exc = val sys.last_type = exc sys.last_value = val sys.last_traceback = tb diff --git a/Lib/traceback.py b/Lib/traceback.py index c43c4720ae5a15..9e720ac9948fce 100644 --- a/Lib/traceback.py +++ b/Lib/traceback.py @@ -179,7 +179,7 @@ def _safe_string(value, what, func=str): # -- def print_exc(limit=None, file=None, chain=True): - """Shorthand for 'print_exception(*sys.exc_info(), limit, file)'.""" + """Shorthand for 'print_exception(*sys.exc_info(), limit, file, chain)'.""" print_exception(*sys.exc_info(), limit=limit, file=file, chain=chain) def format_exc(limit=None, chain=True): @@ -187,12 +187,16 @@ def format_exc(limit=None, chain=True): return "".join(format_exception(*sys.exc_info(), limit=limit, chain=chain)) def print_last(limit=None, file=None, chain=True): - """This is a shorthand for 'print_exception(sys.last_type, - sys.last_value, sys.last_traceback, limit, file)'.""" - if not hasattr(sys, "last_type"): + """This is a shorthand for 'print_exception(sys.last_exc, limit, file, chain)'.""" + if not hasattr(sys, "last_exc") and not hasattr(sys, "last_type"): raise ValueError("no last exception") - print_exception(sys.last_type, sys.last_value, sys.last_traceback, - limit, file, chain) + + if hasattr(sys, "last_exc"): + print_exception(sys.last_exc, limit, file, chain) + else: + print_exception(sys.last_type, sys.last_value, sys.last_traceback, + limit, file, chain) + # # Printing and Extracting Stacks. From 2ce2c268e5a510cf475e797f18532b15f94cd4e5 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Fri, 17 Mar 2023 21:43:27 +0000 Subject: [PATCH 7/7] variable name type --> typ --- Lib/idlelib/stackviewer.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Lib/idlelib/stackviewer.py b/Lib/idlelib/stackviewer.py index 855fc7a562991b..702fd32ca5d1bd 100644 --- a/Lib/idlelib/stackviewer.py +++ b/Lib/idlelib/stackviewer.py @@ -41,14 +41,14 @@ def get_stack(self, tb): def get_exception(self): if hasattr(sys, 'last_exc'): - type = type(sys.last_exc) + typ = type(sys.last_exc) value = sys.last_exc else: - type = sys.last_type + typ = sys.last_type value = sys.last_value - if hasattr(type, "__name__"): - type = type.__name__ - s = str(type) + if hasattr(typ, "__name__"): + typ = typ.__name__ + s = str(typ) if value is not None: s = s + ": " + str(value) return s