From 7a34380ad788886f5ad50d4175ceb2d5715b8cff Mon Sep 17 00:00:00 2001 From: Ken Date: Wed, 27 Jan 2021 07:55:52 +0800 Subject: bpo-43008: Make IDLE respect sys.excepthook (GH-24302) Co-authored-by: Terry Jan Reedy --- Doc/library/idle.rst | 2 +- Lib/idlelib/NEWS.txt | 3 ++ Lib/idlelib/idle_test/test_run.py | 43 ++++++++++++++++++++-- Lib/idlelib/run.py | 27 ++++++++++---- .../IDLE/2021-01-26-18-12-17.bpo-43008.mbQUc7.rst | 1 + 5 files changed, 63 insertions(+), 13 deletions(-) create mode 100644 Misc/NEWS.d/next/IDLE/2021-01-26-18-12-17.bpo-43008.mbQUc7.rst diff --git a/Doc/library/idle.rst b/Doc/library/idle.rst index a59a5d3..e7eaabd 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. diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt index 2620098..f1abb38 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 37c0d45..a31671e 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 @@ class HandleErrorTest(unittest.TestCase): 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 ec575c3..07e9a2b 100644 --- a/Lib/idlelib/run.py +++ b/Lib/idlelib/run.py @@ -16,6 +16,7 @@ import _thread as thread 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,10 +566,17 @@ class Executive: 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() - print_exception() + if sys.excepthook is sys.__excepthook__: + print_exception() + else: + try: + sys.excepthook(*self.user_exc_info) + except: + self.user_exc_info = sys.exc_info() # For testing. + print_exception() jit = self.rpchandler.console.getvar("<>") if jit: self.rpchandler.interp.open_remote_stack_viewer() @@ -590,8 +601,8 @@ class Executive: 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 0000000..3e0b80a --- /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. -- cgit v0.12