Skip to content

Commit

Permalink
Better SyntaxError reporting
Browse files Browse the repository at this point in the history
  • Loading branch information
geowurster committed Nov 1, 2024
1 parent 2db3880 commit 44bb0b6
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 20 deletions.
32 changes: 17 additions & 15 deletions pyin.py
Original file line number Diff line number Diff line change
Expand Up @@ -524,13 +524,7 @@ def compiled_expression(self, mode):

"""Compile a Python expression using the builtin ``compile()``."""

try:
return builtins.compile(self.expression, '<string>', mode)
except SyntaxError as e:
raise SyntaxError(
f"expression {repr(self.expression)} contains a syntax error:"
f" {e.text}"
)
return builtins.compile(self.expression, '<string>', mode)


class OpEval(OpBaseExpression, directives=('%eval', '%stream', '%exec')):
Expand Down Expand Up @@ -1246,14 +1240,8 @@ def main(
# Probably possible to use 'OpEval(%exec)' here, but not immediately
# clear how to manifest the scope changes.
for statement in setup:
try:
code = builtins.compile(statement, '<string>', 'exec')
except SyntaxError as e:
raise SyntaxError(
f"setup statement contains a syntax error:"
f" {e.text.strip()}"
)
exec(code, scope, local_scope)
code_object = builtins.compile(statement, '<string>', 'exec')
exec(code_object, scope, local_scope)
scope.update(local_scope)

del local_scope
Expand Down Expand Up @@ -1339,6 +1327,20 @@ def _cli_entrypoint(rawargs=None):
try:
exit_code = main(**vars(args))

except SyntaxError as e:

exit_code = 1

# Reformat the exception information to provide clarity that this is
# something the user did wrong, and not something 'pyin' did wrong.
lines = [
f'ERROR: expression contains a syntax error: {e.msg}',
'',
f' {e.text}',
f' {" " * (e.offset - 1)}^',
]
print(os.linesep.join(lines), file=sys.stderr)

# User interrupted with '^C' most likely, but technically this is just
# a SIGINT. Somehow this shows up in the coverage report generated by
# '$ pytest --cov'. No idea how that works!!
Expand Down
6 changes: 3 additions & 3 deletions tests/test_operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ def test_simple_stream(directive, args, stream, expected):
assert list(pyin.eval(expressions, [])) == []


def test_Eval_syntax_error():
def test_eval_syntax_error():

"""Produce a helpful error when encountering :obj:`SyntaxError`.
Expand All @@ -163,8 +163,8 @@ def test_Eval_syntax_error():
with pytest.raises(SyntaxError) as e:
list(pyin.eval(expr, range(1)))

assert 'contains a syntax error' in str(e.value)
assert expr in str(e.value)
assert 'invalid syntax' in str(e.value)
assert expr == e.value.text


def test_OpCSVDict(csv_with_header):
Expand Down
4 changes: 2 additions & 2 deletions tests/test_pyin.py
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,6 @@ def test_setup_syntax_error(runner):
"""``SyntaxError`` in a setup statement."""

statement = '1 invalid syntax'
expected = f'ERROR: setup statement contains a syntax error: {statement}'

result = runner.invoke(_cli_entrypoint, [
'--gen', 'range(1)',
Expand All @@ -323,7 +322,8 @@ def test_setup_syntax_error(runner):

assert result.exit_code == 1
assert not result.output
assert result.err == expected + os.linesep
assert 'expression contains a syntax error: invalid syntax' in result.err
assert statement in result.err


@mock.patch.dict(os.environ, {'PYIN_FULL_TRACEBACK': ''})
Expand Down

0 comments on commit 44bb0b6

Please sign in to comment.