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

Co-authored-by: Terry Jan Reedy <tjreedy@udel.edu>
This commit is contained in:
Ken 2021-01-27 07:55:52 +08:00 committed by GitHub
parent 01faf4542a
commit 7a34380ad7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 65 additions and 15 deletions

View File

@ -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.

View File

@ -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

View File

@ -1,16 +1,18 @@
"Test run, coverage 49%."
from idlelib import run
import unittest
from unittest import mock
from idlelib.idle_test.mock_idle import Func
from test.support import captured_output, captured_stderr
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
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)

View File

@ -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("<<toggle-jit-stack-viewer>>")
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

View File

@ -0,0 +1 @@
Make IDLE invoke :func:`sys.excepthook` in normal, 2-process mode.