Skip to content

Commit

Permalink
gh-105724: Add location information to assert errors (GH-105935)
Browse files Browse the repository at this point in the history
  • Loading branch information
sobolevn authored Aug 16, 2023
1 parent fd9d70a commit bdd8ddf
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 6 deletions.
10 changes: 5 additions & 5 deletions Lib/test/test_compile.py
Original file line number Diff line number Diff line change
Expand Up @@ -1315,18 +1315,18 @@ def test_multiline_assert(self):
snippet = textwrap.dedent("""\
assert (a > 0 and
bb > 0 and
ccc == 4), "error msg"
ccc == 1000000), "error msg"
""")
compiled_code, _ = self.check_positions_against_ast(snippet)
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":
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',
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',
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):
snippet = textwrap.dedent("""\
Expand Down
117 changes: 117 additions & 0 deletions Lib/test/test_exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -1931,6 +1931,123 @@ def test_copy_pickle(self):
self.assertEqual(exc.name, orig.name)
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):
def test_range_of_offsets(self):
cases = [
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Improve ``assert`` error messages by providing exact error range.
2 changes: 1 addition & 1 deletion Python/compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -3952,7 +3952,7 @@ compiler_assert(struct compiler *c, stmt_ty s)
VISIT(c, expr, s->v.Assert.msg);
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);
return SUCCESS;
Expand Down

0 comments on commit bdd8ddf

Please sign in to comment.