summaryrefslogtreecommitdiffstats
path: root/Lib/idlelib/idle_test/test_run.py
diff options
context:
space:
mode:
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>2021-05-08 00:35:25 (GMT)
committerGitHub <noreply@github.com>2021-05-08 00:35:25 (GMT)
commit5a5237c6d08ed97458b0903d6836624168df0b51 (patch)
treef3af69678ae8173f7e4596d40f7350f75044e2a8 /Lib/idlelib/idle_test/test_run.py
parent13de28f17af02563cb8c6d0f6da3c178a4241ff3 (diff)
downloadcpython-5a5237c6d08ed97458b0903d6836624168df0b51.zip
cpython-5a5237c6d08ed97458b0903d6836624168df0b51.tar.gz
cpython-5a5237c6d08ed97458b0903d6836624168df0b51.tar.bz2
bpo-44026: Idle - display interpreter's 'did you mean' hints (GH-25912)
A C function accessible by the default exception handler, but not by python code, finds the existing name closest to the name causing a name or attribute error. For such errors, call the default handler after capturing stderr and retrieve its message line. Co-authored-by: Terry Jan Reedy <tjreedy@udel.edu> (cherry picked from commit 092f9ddb5e85665552c8207972cd393d492f764e) Co-authored-by: E-Paine <63801254+E-Paine@users.noreply.github.com>
Diffstat (limited to 'Lib/idlelib/idle_test/test_run.py')
-rw-r--r--Lib/idlelib/idle_test/test_run.py47
1 files changed, 43 insertions, 4 deletions
diff --git a/Lib/idlelib/idle_test/test_run.py b/Lib/idlelib/idle_test/test_run.py
index a31671e..ec4637c 100644
--- a/Lib/idlelib/idle_test/test_run.py
+++ b/Lib/idlelib/idle_test/test_run.py
@@ -1,4 +1,4 @@
-"Test run, coverage 49%."
+"Test run, coverage 54%."
from idlelib import run
import io
@@ -12,7 +12,7 @@ from idlelib.idle_test.mock_idle import Func
idlelib.testing = True # Use {} for executing test user code.
-class PrintExceptionTest(unittest.TestCase):
+class ExceptionTest(unittest.TestCase):
def test_print_exception_unhashable(self):
class UnhashableException(Exception):
@@ -28,8 +28,7 @@ class PrintExceptionTest(unittest.TestCase):
raise ex1
except UnhashableException:
with captured_stderr() as output:
- with mock.patch.object(run,
- 'cleanup_traceback') as ct:
+ with mock.patch.object(run, 'cleanup_traceback') as ct:
ct.side_effect = lambda t, e: t
run.print_exception()
@@ -38,6 +37,46 @@ class PrintExceptionTest(unittest.TestCase):
self.assertIn('UnhashableException: ex2', tb[3])
self.assertIn('UnhashableException: ex1', tb[10])
+ data = (('1/0', ZeroDivisionError, "division by zero\n"),
+ ('abc', NameError, "name 'abc' is not defined. "
+ "Did you mean: 'abs'?\n"),
+ ('int.reel', AttributeError,
+ "type object 'int' has no attribute 'reel'. "
+ "Did you mean: 'real'?\n"),
+ )
+
+ def test_get_message(self):
+ for code, exc, msg in self.data:
+ with self.subTest(code=code):
+ try:
+ eval(compile(code, '', 'eval'))
+ except exc:
+ typ, val, tb = sys.exc_info()
+ actual = run.get_message_lines(typ, val, tb)[0]
+ expect = f'{exc.__name__}: {msg}'
+ self.assertEqual(actual, expect)
+
+ @mock.patch.object(run, 'cleanup_traceback',
+ new_callable=lambda: (lambda t, e: None))
+ def test_get_multiple_message(self, mock):
+ d = self.data
+ data2 = ((d[0], d[1]), (d[1], d[2]), (d[2], d[0]))
+ subtests = 0
+ for (code1, exc1, msg1), (code2, exc2, msg2) in data2:
+ with self.subTest(codes=(code1,code2)):
+ try:
+ eval(compile(code1, '', 'eval'))
+ except exc1:
+ try:
+ eval(compile(code2, '', 'eval'))
+ except exc2:
+ with captured_stderr() as output:
+ run.print_exception()
+ actual = output.getvalue()
+ self.assertIn(msg1, actual)
+ self.assertIn(msg2, actual)
+ subtests += 1
+ self.assertEqual(subtests, len(data2)) # All subtests ran?
# StdioFile tests.