diff options
author | Miss Islington (bot) <31488909+miss-islington@users.noreply.github.com> | 2021-05-08 00:35:25 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-05-08 00:35:25 (GMT) |
commit | 5a5237c6d08ed97458b0903d6836624168df0b51 (patch) | |
tree | f3af69678ae8173f7e4596d40f7350f75044e2a8 /Lib/idlelib/idle_test/test_run.py | |
parent | 13de28f17af02563cb8c6d0f6da3c178a4241ff3 (diff) | |
download | cpython-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.py | 47 |
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. |