summaryrefslogtreecommitdiffstats
path: root/Lib/test/test_exceptions.py
diff options
context:
space:
mode:
authorPablo Galindo <Pablogsal@gmail.com>2021-04-23 13:27:05 (GMT)
committerGitHub <noreply@github.com>2021-04-23 13:27:05 (GMT)
commita77aac4fca9723b8fd52a832f3e9df13beb25113 (patch)
treea504aa9fed91cd31849cdda3ecb1dad439a93778 /Lib/test/test_exceptions.py
parent91b69b77cf5f78de6d35dea23098df34b6fd9e53 (diff)
downloadcpython-a77aac4fca9723b8fd52a832f3e9df13beb25113.zip
cpython-a77aac4fca9723b8fd52a832f3e9df13beb25113.tar.gz
cpython-a77aac4fca9723b8fd52a832f3e9df13beb25113.tar.bz2
bpo-43914: Highlight invalid ranges in SyntaxErrors (#25525)
To improve the user experience understanding what part of the error messages associated with SyntaxErrors is wrong, we can highlight the whole error range and not only place the caret at the first character. In this way: >>> foo(x, z for z in range(10), t, w) File "<stdin>", line 1 foo(x, z for z in range(10), t, w) ^ SyntaxError: Generator expression must be parenthesized becomes >>> foo(x, z for z in range(10), t, w) File "<stdin>", line 1 foo(x, z for z in range(10), t, w) ^^^^^^^^^^^^^^^^^^^^ SyntaxError: Generator expression must be parenthesized
Diffstat (limited to 'Lib/test/test_exceptions.py')
-rw-r--r--Lib/test/test_exceptions.py155
1 files changed, 143 insertions, 12 deletions
diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py
index e0e8191..b3c00b0 100644
--- a/Lib/test/test_exceptions.py
+++ b/Lib/test/test_exceptions.py
@@ -8,6 +8,7 @@ import unittest
import pickle
import weakref
import errno
+from textwrap import dedent
from test.support import (captured_stderr, check_impl_detail,
cpython_only, gc_collect,
@@ -255,13 +256,13 @@ class ExceptionTests(unittest.TestCase):
check('from __future__ import doesnt_exist', 1, 1)
check('from __future__ import braces', 1, 1)
check('x=1\nfrom __future__ import division', 2, 1)
- check('foo(1=2)', 1, 6)
+ check('foo(1=2)', 1, 5)
check('def f():\n x, y: int', 2, 3)
check('[*x for x in xs]', 1, 2)
check('foo(x for x in range(10), 100)', 1, 5)
check('for 1 in []: pass', 1, 5)
- check('(yield i) = 2', 1, 11)
- check('def f(*):\n pass', 1, 8)
+ check('(yield i) = 2', 1, 2)
+ check('def f(*):\n pass', 1, 7)
@cpython_only
def testSettingException(self):
@@ -395,25 +396,31 @@ class ExceptionTests(unittest.TestCase):
'filename' : 'filenameStr', 'filename2' : None}),
(SyntaxError, (), {'msg' : None, 'text' : None,
'filename' : None, 'lineno' : None, 'offset' : None,
- 'print_file_and_line' : None}),
+ 'end_offset': None, 'print_file_and_line' : None}),
(SyntaxError, ('msgStr',),
{'args' : ('msgStr',), 'text' : None,
'print_file_and_line' : None, 'msg' : 'msgStr',
- 'filename' : None, 'lineno' : None, 'offset' : None}),
+ 'filename' : None, 'lineno' : None, 'offset' : None,
+ 'end_offset': None}),
(SyntaxError, ('msgStr', ('filenameStr', 'linenoStr', 'offsetStr',
- 'textStr')),
+ 'textStr', 'endLinenoStr', 'endOffsetStr')),
{'offset' : 'offsetStr', 'text' : 'textStr',
'args' : ('msgStr', ('filenameStr', 'linenoStr',
- 'offsetStr', 'textStr')),
+ 'offsetStr', 'textStr',
+ 'endLinenoStr', 'endOffsetStr')),
'print_file_and_line' : None, 'msg' : 'msgStr',
- 'filename' : 'filenameStr', 'lineno' : 'linenoStr'}),
+ 'filename' : 'filenameStr', 'lineno' : 'linenoStr',
+ 'end_lineno': 'endLinenoStr', 'end_offset': 'endOffsetStr'}),
(SyntaxError, ('msgStr', 'filenameStr', 'linenoStr', 'offsetStr',
- 'textStr', 'print_file_and_lineStr'),
+ 'textStr', 'endLinenoStr', 'endOffsetStr',
+ 'print_file_and_lineStr'),
{'text' : None,
'args' : ('msgStr', 'filenameStr', 'linenoStr', 'offsetStr',
- 'textStr', 'print_file_and_lineStr'),
+ 'textStr', 'endLinenoStr', 'endOffsetStr',
+ 'print_file_and_lineStr'),
'print_file_and_line' : None, 'msg' : 'msgStr',
- 'filename' : None, 'lineno' : None, 'offset' : None}),
+ 'filename' : None, 'lineno' : None, 'offset' : None,
+ 'end_lineno': None, 'end_offset': None}),
(UnicodeError, (), {'args' : (),}),
(UnicodeEncodeError, ('ascii', 'a', 0, 1,
'ordinal not in range'),
@@ -459,7 +466,7 @@ class ExceptionTests(unittest.TestCase):
e = exc(*args)
except:
print("\nexc=%r, args=%r" % (exc, args), file=sys.stderr)
- raise
+ # raise
else:
# Verify module name
if not type(e).__name__.endswith('NaiveException'):
@@ -1827,6 +1834,130 @@ class ImportErrorTests(unittest.TestCase):
self.assertEqual(exc.name, orig.name)
self.assertEqual(exc.path, orig.path)
+class SyntaxErrorTests(unittest.TestCase):
+ def test_range_of_offsets(self):
+ cases = [
+ # Basic range from 2->7
+ (("bad.py", 1, 2, "abcdefg", 1, 7),
+ dedent(
+ """
+ File "bad.py", line 1
+ abcdefg
+ ^^^^^
+ SyntaxError: bad bad
+ """)),
+ # end_offset = start_offset + 1
+ (("bad.py", 1, 2, "abcdefg", 1, 3),
+ dedent(
+ """
+ File "bad.py", line 1
+ abcdefg
+ ^
+ SyntaxError: bad bad
+ """)),
+ # Negative end offset
+ (("bad.py", 1, 2, "abcdefg", 1, -2),
+ dedent(
+ """
+ File "bad.py", line 1
+ abcdefg
+ ^
+ SyntaxError: bad bad
+ """)),
+ # end offset before starting offset
+ (("bad.py", 1, 4, "abcdefg", 1, 2),
+ dedent(
+ """
+ File "bad.py", line 1
+ abcdefg
+ ^
+ SyntaxError: bad bad
+ """)),
+ # Both offsets negative
+ (("bad.py", 1, -4, "abcdefg", 1, -2),
+ dedent(
+ """
+ File "bad.py", line 1
+ abcdefg
+ SyntaxError: bad bad
+ """)),
+ # Both offsets negative and the end more negative
+ (("bad.py", 1, -4, "abcdefg", 1, -5),
+ dedent(
+ """
+ File "bad.py", line 1
+ abcdefg
+ SyntaxError: bad bad
+ """)),
+ # Both offsets 0
+ (("bad.py", 1, 0, "abcdefg", 1, 0),
+ dedent(
+ """
+ File "bad.py", line 1
+ abcdefg
+ SyntaxError: bad bad
+ """)),
+ # Start offset 0 and end offset not 0
+ (("bad.py", 1, 0, "abcdefg", 1, 5),
+ dedent(
+ """
+ File "bad.py", line 1
+ abcdefg
+ SyntaxError: bad bad
+ """)),
+ # End offset pass the source lenght
+ (("bad.py", 1, 2, "abcdefg", 1, 100),
+ dedent(
+ """
+ File "bad.py", line 1
+ abcdefg
+ ^^^^^^
+ SyntaxError: bad bad
+ """)),
+ ]
+ for args, expected in cases:
+ with self.subTest(args=args):
+ try:
+ raise SyntaxError("bad bad", args)
+ except SyntaxError as exc:
+ with support.captured_stderr() as err:
+ sys.__excepthook__(*sys.exc_info())
+ the_exception = exc
+
+ def test_attributes_new_constructor(self):
+ args = ("bad.py", 1, 2, "abcdefg", 1, 100)
+ the_exception = SyntaxError("bad bad", args)
+ filename, lineno, offset, error, end_lineno, end_offset = args
+ self.assertEqual(filename, the_exception.filename)
+ self.assertEqual(lineno, the_exception.lineno)
+ self.assertEqual(end_lineno, the_exception.end_lineno)
+ self.assertEqual(offset, the_exception.offset)
+ self.assertEqual(end_offset, the_exception.end_offset)
+ self.assertEqual(error, the_exception.text)
+ self.assertEqual("bad bad", the_exception.msg)
+
+ def test_attributes_old_constructor(self):
+ args = ("bad.py", 1, 2, "abcdefg")
+ the_exception = SyntaxError("bad bad", args)
+ filename, lineno, offset, error = args
+ self.assertEqual(filename, the_exception.filename)
+ self.assertEqual(lineno, the_exception.lineno)
+ self.assertEqual(None, the_exception.end_lineno)
+ self.assertEqual(offset, the_exception.offset)
+ self.assertEqual(None, the_exception.end_offset)
+ self.assertEqual(error, the_exception.text)
+ self.assertEqual("bad bad", the_exception.msg)
+
+ def test_incorrect_constructor(self):
+ args = ("bad.py", 1, 2)
+ self.assertRaises(TypeError, SyntaxError, "bad bad", args)
+
+ args = ("bad.py", 1, 2, 4, 5, 6, 7)
+ self.assertRaises(TypeError, SyntaxError, "bad bad", args)
+
+ args = ("bad.py", 1, 2, "abcdefg", 1)
+ self.assertRaises(TypeError, SyntaxError, "bad bad", args)
+
class PEP626Tests(unittest.TestCase):