From 942ff16673c623ce2b9a86e84fab31cb99b62b65 Mon Sep 17 00:00:00 2001 From: Ken Date: Sat, 23 Jan 2021 19:23:25 +0800 Subject: [PATCH 1/5] Make IDLE respect sys.excepthook --- Lib/idlelib/run.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py index 1e84ecc6584ef1..1d0cf5c8a178b9 100644 --- a/Lib/idlelib/run.py +++ b/Lib/idlelib/run.py @@ -565,7 +565,10 @@ def runcode(self, code): self.usr_exc_info = sys.exc_info() if quitting: exit() - print_exception() + if sys.excepthook is sys.__excepthook__: + print_exception() + else: + sys.excepthook(*self.usr_exc_info) jit = self.rpchandler.console.getvar("<>") if jit: self.rpchandler.interp.open_remote_stack_viewer() From 4c891b5f33ef1866e43339369a7ab2abf3431812 Mon Sep 17 00:00:00 2001 From: Ken Date: Sat, 23 Jan 2021 23:58:01 +0800 Subject: [PATCH 2/5] Add blurb for IDLE fix --- .../NEWS.d/next/Library/2020-01-23-03-45-43.bpo-43008.lSZkGx.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Library/2020-01-23-03-45-43.bpo-43008.lSZkGx.rst diff --git a/Misc/NEWS.d/next/Library/2020-01-23-03-45-43.bpo-43008.lSZkGx.rst b/Misc/NEWS.d/next/Library/2020-01-23-03-45-43.bpo-43008.lSZkGx.rst new file mode 100644 index 00000000000000..225b72d5878bca --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-01-23-03-45-43.bpo-43008.lSZkGx.rst @@ -0,0 +1 @@ +Fix: IDLE now correctly invokes :func:`sys.excepthook` in normal, 2-process mode. From 237be53df18700daf30635cb6b65c33a26f550e2 Mon Sep 17 00:00:00 2001 From: Ken Date: Sun, 24 Jan 2021 00:01:51 +0800 Subject: [PATCH 3/5] Update IDLE Restart Shell docs to say... ..." and reset display and exception handling". --- Doc/library/idle.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/idle.rst b/Doc/library/idle.rst index a59a5d3a465703..e7eaabd8bfa25a 100644 --- a/Doc/library/idle.rst +++ b/Doc/library/idle.rst @@ -250,7 +250,7 @@ View Last Restart Scroll the shell window to the last Shell restart. Restart Shell - Restart the shell to clean the environment. + Restart the shell to clean the environment and reset display and exception handling. Previous History Cycle through earlier commands in history which match the current entry. From a11fa374e0f2818cf213d326901703f5fa8f107e Mon Sep 17 00:00:00 2001 From: Ken Date: Sun, 24 Jan 2021 00:06:57 +0800 Subject: [PATCH 4/5] IDLE: Handle sys.excepthook errors... ...when raising in 2-process mode, in a way that matches normal shell behavior. --- Lib/idlelib/run.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py index 1d0cf5c8a178b9..c7610bce4b7f4e 100644 --- a/Lib/idlelib/run.py +++ b/Lib/idlelib/run.py @@ -568,7 +568,13 @@ def runcode(self, code): if sys.excepthook is sys.__excepthook__: print_exception() else: - sys.excepthook(*self.usr_exc_info) + try: + sys.excepthook(*self.usr_exc_info) + except: + print_exception() + print("\nDuring handling of the above exception, another exception occurred:\n", file=sys.stderr) + self.usr_exc_info = sys.exc_info() + print_exception() jit = self.rpchandler.console.getvar("<>") if jit: self.rpchandler.interp.open_remote_stack_viewer() From 30a2974cfda43fa0bf7924440af83341bb913f21 Mon Sep 17 00:00:00 2001 From: Terry Jan Reedy Date: Tue, 26 Jan 2021 18:15:32 -0500 Subject: [PATCH 5/5] Revise and add tests. --- Lib/idlelib/NEWS.txt | 3 ++ Lib/idlelib/idle_test/test_run.py | 43 +++++++++++++++++-- Lib/idlelib/run.py | 24 ++++++----- .../2021-01-26-18-12-17.bpo-43008.mbQUc7.rst | 1 + .../2020-01-23-03-45-43.bpo-43008.lSZkGx.rst | 1 - 5 files changed, 56 insertions(+), 16 deletions(-) create mode 100644 Misc/NEWS.d/next/IDLE/2021-01-26-18-12-17.bpo-43008.mbQUc7.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-01-23-03-45-43.bpo-43008.lSZkGx.rst diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt index 26200981eb8d93..f1abb38eee2e54 100644 --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -3,6 +3,9 @@ Released on 2021-10-04? ====================================== +bpo-43008: Make IDLE invoke :func:`sys.excepthook` in normal, +2-process mode. + bpo-33065: Fix problem debugging user classes with __repr__ method. bpo-32631: Finish zzdummy example extension module: make menu entries diff --git a/Lib/idlelib/idle_test/test_run.py b/Lib/idlelib/idle_test/test_run.py index 37c0d4525e56cd..a31671ee0485fa 100644 --- a/Lib/idlelib/idle_test/test_run.py +++ b/Lib/idlelib/idle_test/test_run.py @@ -1,16 +1,18 @@ "Test run, coverage 49%." from idlelib import run +import io +import sys +from test.support import captured_output, captured_stderr import unittest from unittest import mock +import idlelib from idlelib.idle_test.mock_idle import Func -from test.support import captured_output, captured_stderr -import io -import sys +idlelib.testing = True # Use {} for executing test user code. -class RunTest(unittest.TestCase): +class PrintExceptionTest(unittest.TestCase): def test_print_exception_unhashable(self): class UnhashableException(Exception): @@ -351,5 +353,38 @@ def test_fatal_error(self): self.assertIn('IndexError', msg) eq(func.called, 2) + +class ExecRuncodeTest(unittest.TestCase): + + @classmethod + def setUpClass(cls): + cls.addClassCleanup(setattr,run,'print_exception',run.print_exception) + cls.prt = Func() # Need reference. + run.print_exception = cls.prt + mockrpc = mock.Mock() + mockrpc.console.getvar = Func(result=False) + cls.ex = run.Executive(mockrpc) + + @classmethod + def tearDownClass(cls): + assert sys.excepthook == sys.__excepthook__ + + def test_exceptions(self): + ex = self.ex + ex.runcode('1/0') + self.assertIs(ex.user_exc_info[0], ZeroDivisionError) + + self.addCleanup(setattr, sys, 'excepthook', sys.__excepthook__) + sys.excepthook = lambda t, e, tb: run.print_exception(t) + ex.runcode('1/0') + self.assertIs(self.prt.args[0], ZeroDivisionError) + + sys.excepthook = lambda: None + ex.runcode('1/0') + t, e, tb = ex.user_exc_info + self.assertIs(t, TypeError) + self.assertTrue(isinstance(e.__context__, ZeroDivisionError)) + + if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py index 6cc6e35b49d71e..07e9a2bf9ceeae 100644 --- a/Lib/idlelib/run.py +++ b/Lib/idlelib/run.py @@ -16,6 +16,7 @@ import threading import warnings +import idlelib # testing from idlelib import autocomplete # AutoComplete, fetch_encodings from idlelib import calltip # Calltip from idlelib import debugger_r # start_debugger @@ -542,14 +543,17 @@ class Executive: def __init__(self, rpchandler): self.rpchandler = rpchandler - self.locals = __main__.__dict__ - self.calltip = calltip.Calltip() - self.autocomplete = autocomplete.AutoComplete() + if idlelib.testing is False: + self.locals = __main__.__dict__ + self.calltip = calltip.Calltip() + self.autocomplete = autocomplete.AutoComplete() + else: + self.locals = {} def runcode(self, code): global interruptable try: - self.usr_exc_info = None + self.user_exc_info = None interruptable = True try: exec(code, self.locals) @@ -562,18 +566,16 @@ def runcode(self, code): print('SystemExit: ' + str(ob), file=sys.stderr) # Return to the interactive prompt. except: - self.usr_exc_info = sys.exc_info() + self.user_exc_info = sys.exc_info() # For testing, hook, viewer. if quitting: exit() if sys.excepthook is sys.__excepthook__: print_exception() else: try: - sys.excepthook(*self.usr_exc_info) + sys.excepthook(*self.user_exc_info) except: - print_exception() - print("\nDuring handling of the above exception, another exception occurred:\n", file=sys.stderr) - self.usr_exc_info = sys.exc_info() + self.user_exc_info = sys.exc_info() # For testing. print_exception() jit = self.rpchandler.console.getvar("<>") if jit: @@ -599,8 +601,8 @@ def get_the_completion_list(self, what, mode): return self.autocomplete.fetch_completions(what, mode) def stackviewer(self, flist_oid=None): - if self.usr_exc_info: - typ, val, tb = self.usr_exc_info + if self.user_exc_info: + typ, val, tb = self.user_exc_info else: return None flist = None diff --git a/Misc/NEWS.d/next/IDLE/2021-01-26-18-12-17.bpo-43008.mbQUc7.rst b/Misc/NEWS.d/next/IDLE/2021-01-26-18-12-17.bpo-43008.mbQUc7.rst new file mode 100644 index 00000000000000..3e0b80a909d728 --- /dev/null +++ b/Misc/NEWS.d/next/IDLE/2021-01-26-18-12-17.bpo-43008.mbQUc7.rst @@ -0,0 +1 @@ +Make IDLE invoke :func:`sys.excepthook` in normal, 2-process mode. diff --git a/Misc/NEWS.d/next/Library/2020-01-23-03-45-43.bpo-43008.lSZkGx.rst b/Misc/NEWS.d/next/Library/2020-01-23-03-45-43.bpo-43008.lSZkGx.rst deleted file mode 100644 index 225b72d5878bca..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-01-23-03-45-43.bpo-43008.lSZkGx.rst +++ /dev/null @@ -1 +0,0 @@ -Fix: IDLE now correctly invokes :func:`sys.excepthook` in normal, 2-process mode.