[Python-checkins] bpo-43008: Make IDLE respect sys.excepthook (GH-24302)

terryjreedy webhook-mailer at python.org
Tue Jan 26 18:56:06 EST 2021


https://github.com/python/cpython/commit/7a34380ad788886f5ad50d4175ceb2d5715b8cff
commit: 7a34380ad788886f5ad50d4175ceb2d5715b8cff
branch: master
author: Ken <kenny2minecraft at gmail.com>
committer: terryjreedy <tjreedy at udel.edu>
date: 2021-01-26T18:55:52-05:00
summary:

bpo-43008: Make IDLE respect sys.excepthook (GH-24302)

Co-authored-by: Terry Jan Reedy <tjreedy at udel.edu>

files:
A Misc/NEWS.d/next/IDLE/2021-01-26-18-12-17.bpo-43008.mbQUc7.rst
M Doc/library/idle.rst
M Lib/idlelib/NEWS.txt
M Lib/idlelib/idle_test/test_run.py
M Lib/idlelib/run.py

diff --git a/Doc/library/idle.rst b/Doc/library/idle.rst
index a59a5d3a46570..e7eaabd8bfa25 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 26200981eb8d9..f1abb38eee2e5 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 37c0d4525e56c..a31671ee0485f 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 ec575c3d48363..07e9a2bf9ceea 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,10 +566,17 @@ 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()
-            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("<<toggle-jit-stack-viewer>>")
             if jit:
                 self.rpchandler.interp.open_remote_stack_viewer()
@@ -590,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 0000000000000..3e0b80a909d72
--- /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.



More information about the Python-checkins mailing list