(core) Put user code in linecache so that source lines show in tracebacks

Summary: See title. This should improve the user experience, but more importantly it's something I've wanted several times when developing (including just now) so I've been meaning to do this.

Test Plan: Expanded existing unit tests

Reviewers: dsagal, paulfitz

Reviewed By: dsagal

Differential Revision: https://phab.getgrist.com/D2910
This commit is contained in:
Alex Hall 2021-07-12 22:14:23 +02:00
parent 869b2f00ec
commit 8524b4f791
2 changed files with 29 additions and 4 deletions

View File

@ -15,6 +15,7 @@ The schema for grist data is:
"formula": <opt_string>,
}
"""
import linecache
import re
import imp
from collections import OrderedDict
@ -194,6 +195,17 @@ def _is_special_table(table_id):
def exec_module_text(module_text):
# pylint: disable=exec-used
mod = imp.new_module("usercode")
exec(module_text, mod.__dict__)
filename = "usercode"
mod = imp.new_module(filename)
# Ensure that source lines show in tracebacks
linecache.cache[filename] = (
len(module_text),
None,
[line + '\n' for line in module_text.splitlines()],
filename,
)
code_obj = compile(module_text, filename, "exec")
exec(code_obj, mod.__dict__)
return mod

View File

@ -66,7 +66,14 @@ else:
r"TypeError: SQRT\(\) takes 1 positional argument but 2 were given")
self.assertFormulaError(self.engine.get_formula_error('Math', 'built_in_formula', 3),
TypeError, "'int' object is not iterable")
TypeError, "'int' object is not iterable",
textwrap.dedent(
r"""
File "usercode", line \d+, in built_in_formula
return max\(5\)
TypeError: 'int' object is not iterable
"""
))
self.assertFormulaError(self.engine.get_formula_error('Math', 'syntax_err', 3),
SyntaxError, "invalid syntax on line 5 col 9")
@ -76,7 +83,13 @@ else:
self.assertFormulaError(self.engine.get_formula_error('Math', 'other_err', 3),
TypeError, "'int' object is not iterable",
r"line \d+, in other_err")
textwrap.dedent(
r"""
File "usercode", line \d+, in other_err
if sum\(3, 5\) > 6:
TypeError: 'int' object is not iterable
"""
))
self.assertFormulaError(self.engine.get_formula_error('Math', 'custom_err', 3),
Exception, "hello")