mirror of
https://github.com/python/cpython.git
synced 2025-07-24 11:44:31 +00:00
gh-105724: Add location information to assert
errors (GH-105935)
This commit is contained in:
parent
fd9d70a94d
commit
bdd8ddfda1
4 changed files with 124 additions and 6 deletions
|
@ -1315,18 +1315,18 @@ class TestSourcePositions(unittest.TestCase):
|
||||||
snippet = textwrap.dedent("""\
|
snippet = textwrap.dedent("""\
|
||||||
assert (a > 0 and
|
assert (a > 0 and
|
||||||
bb > 0 and
|
bb > 0 and
|
||||||
ccc == 4), "error msg"
|
ccc == 1000000), "error msg"
|
||||||
""")
|
""")
|
||||||
compiled_code, _ = self.check_positions_against_ast(snippet)
|
compiled_code, _ = self.check_positions_against_ast(snippet)
|
||||||
self.assertOpcodeSourcePositionIs(compiled_code, 'LOAD_ASSERTION_ERROR',
|
self.assertOpcodeSourcePositionIs(compiled_code, 'LOAD_ASSERTION_ERROR',
|
||||||
line=1, end_line=3, column=0, end_column=30, occurrence=1)
|
line=1, end_line=3, column=0, end_column=36, occurrence=1)
|
||||||
# The "error msg":
|
# The "error msg":
|
||||||
self.assertOpcodeSourcePositionIs(compiled_code, 'LOAD_CONST',
|
self.assertOpcodeSourcePositionIs(compiled_code, 'LOAD_CONST',
|
||||||
line=3, end_line=3, column=19, end_column=30, occurrence=4)
|
line=3, end_line=3, column=25, end_column=36, occurrence=4)
|
||||||
self.assertOpcodeSourcePositionIs(compiled_code, 'CALL',
|
self.assertOpcodeSourcePositionIs(compiled_code, 'CALL',
|
||||||
line=1, end_line=3, column=0, end_column=30, occurrence=1)
|
line=1, end_line=3, column=0, end_column=36, occurrence=1)
|
||||||
self.assertOpcodeSourcePositionIs(compiled_code, 'RAISE_VARARGS',
|
self.assertOpcodeSourcePositionIs(compiled_code, 'RAISE_VARARGS',
|
||||||
line=1, end_line=3, column=0, end_column=30, occurrence=1)
|
line=1, end_line=3, column=8, end_column=22, occurrence=1)
|
||||||
|
|
||||||
def test_multiline_generator_expression(self):
|
def test_multiline_generator_expression(self):
|
||||||
snippet = textwrap.dedent("""\
|
snippet = textwrap.dedent("""\
|
||||||
|
|
|
@ -1931,6 +1931,123 @@ class ImportErrorTests(unittest.TestCase):
|
||||||
self.assertEqual(exc.name, orig.name)
|
self.assertEqual(exc.name, orig.name)
|
||||||
self.assertEqual(exc.path, orig.path)
|
self.assertEqual(exc.path, orig.path)
|
||||||
|
|
||||||
|
|
||||||
|
class AssertionErrorTests(unittest.TestCase):
|
||||||
|
def tearDown(self):
|
||||||
|
unlink(TESTFN)
|
||||||
|
|
||||||
|
def write_source(self, source):
|
||||||
|
with open(TESTFN, 'w') as testfile:
|
||||||
|
testfile.write(dedent(source))
|
||||||
|
_rc, _out, err = script_helper.assert_python_failure('-Wd', '-X', 'utf8', TESTFN)
|
||||||
|
return err.decode('utf-8').splitlines()
|
||||||
|
|
||||||
|
def test_assertion_error_location(self):
|
||||||
|
cases = [
|
||||||
|
('assert None',
|
||||||
|
[
|
||||||
|
' assert None',
|
||||||
|
' ^^^^',
|
||||||
|
'AssertionError',
|
||||||
|
],
|
||||||
|
),
|
||||||
|
('assert 0',
|
||||||
|
[
|
||||||
|
' assert 0',
|
||||||
|
' ^',
|
||||||
|
'AssertionError',
|
||||||
|
],
|
||||||
|
),
|
||||||
|
('assert 1 > 2',
|
||||||
|
[
|
||||||
|
' assert 1 > 2',
|
||||||
|
' ^^^^^',
|
||||||
|
'AssertionError',
|
||||||
|
],
|
||||||
|
),
|
||||||
|
('assert 1 > 2 and 3 > 2',
|
||||||
|
[
|
||||||
|
' assert 1 > 2 and 3 > 2',
|
||||||
|
' ^^^^^^^^^^^^^^^',
|
||||||
|
'AssertionError',
|
||||||
|
],
|
||||||
|
),
|
||||||
|
('assert 1 > 2, "message"',
|
||||||
|
[
|
||||||
|
' assert 1 > 2, "message"',
|
||||||
|
' ^^^^^',
|
||||||
|
'AssertionError: message',
|
||||||
|
],
|
||||||
|
),
|
||||||
|
|
||||||
|
# Multiline:
|
||||||
|
("""
|
||||||
|
assert (
|
||||||
|
1 > 2)
|
||||||
|
""",
|
||||||
|
[
|
||||||
|
' 1 > 2)',
|
||||||
|
' ^^^^^',
|
||||||
|
'AssertionError',
|
||||||
|
],
|
||||||
|
),
|
||||||
|
("""
|
||||||
|
assert (
|
||||||
|
1 > 2), "Message"
|
||||||
|
""",
|
||||||
|
[
|
||||||
|
' 1 > 2), "Message"',
|
||||||
|
' ^^^^^',
|
||||||
|
'AssertionError: Message',
|
||||||
|
],
|
||||||
|
),
|
||||||
|
("""
|
||||||
|
assert (
|
||||||
|
1 > 2), \\
|
||||||
|
"Message"
|
||||||
|
""",
|
||||||
|
[
|
||||||
|
' 1 > 2), \\',
|
||||||
|
' ^^^^^',
|
||||||
|
'AssertionError: Message',
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
||||||
|
for source, expected in cases:
|
||||||
|
with self.subTest(source):
|
||||||
|
result = self.write_source(source)
|
||||||
|
self.assertEqual(result[-3:], expected)
|
||||||
|
|
||||||
|
def test_multiline_not_highlighted(self):
|
||||||
|
cases = [
|
||||||
|
("""
|
||||||
|
assert (
|
||||||
|
1 > 2
|
||||||
|
)
|
||||||
|
""",
|
||||||
|
[
|
||||||
|
' 1 > 2',
|
||||||
|
'AssertionError',
|
||||||
|
],
|
||||||
|
),
|
||||||
|
("""
|
||||||
|
assert (
|
||||||
|
1 < 2 and
|
||||||
|
3 > 4
|
||||||
|
)
|
||||||
|
""",
|
||||||
|
[
|
||||||
|
' 1 < 2 and',
|
||||||
|
'AssertionError',
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
||||||
|
for source, expected in cases:
|
||||||
|
with self.subTest(source):
|
||||||
|
result = self.write_source(source)
|
||||||
|
self.assertEqual(result[-2:], expected)
|
||||||
|
|
||||||
|
|
||||||
class SyntaxErrorTests(unittest.TestCase):
|
class SyntaxErrorTests(unittest.TestCase):
|
||||||
def test_range_of_offsets(self):
|
def test_range_of_offsets(self):
|
||||||
cases = [
|
cases = [
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Improve ``assert`` error messages by providing exact error range.
|
|
@ -3952,7 +3952,7 @@ compiler_assert(struct compiler *c, stmt_ty s)
|
||||||
VISIT(c, expr, s->v.Assert.msg);
|
VISIT(c, expr, s->v.Assert.msg);
|
||||||
ADDOP_I(c, LOC(s), CALL, 0);
|
ADDOP_I(c, LOC(s), CALL, 0);
|
||||||
}
|
}
|
||||||
ADDOP_I(c, LOC(s), RAISE_VARARGS, 1);
|
ADDOP_I(c, LOC(s->v.Assert.test), RAISE_VARARGS, 1);
|
||||||
|
|
||||||
USE_LABEL(c, end);
|
USE_LABEL(c, end);
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue