You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
115 lines
3.6 KiB
115 lines
3.6 KiB
import pickle
|
|
import re
|
|
from traceback import format_exception
|
|
|
|
import pytest
|
|
|
|
from jinja2 import ChoiceLoader
|
|
from jinja2 import DictLoader
|
|
from jinja2 import Environment
|
|
from jinja2 import TemplateSyntaxError
|
|
|
|
|
|
@pytest.fixture
|
|
def fs_env(filesystem_loader):
|
|
"""returns a new environment."""
|
|
return Environment(loader=filesystem_loader)
|
|
|
|
|
|
class TestDebug:
|
|
def assert_traceback_matches(self, callback, expected_tb):
|
|
with pytest.raises(Exception) as exc_info:
|
|
callback()
|
|
|
|
tb = format_exception(exc_info.type, exc_info.value, exc_info.tb)
|
|
m = re.search(expected_tb.strip(), "".join(tb))
|
|
assert (
|
|
m is not None
|
|
), "Traceback did not match:\n\n{''.join(tb)}\nexpected:\n{expected_tb}"
|
|
|
|
def test_runtime_error(self, fs_env):
|
|
def test():
|
|
tmpl.render(fail=lambda: 1 / 0)
|
|
|
|
tmpl = fs_env.get_template("broken.html")
|
|
self.assert_traceback_matches(
|
|
test,
|
|
r"""
|
|
File ".*?broken.html", line 2, in (top-level template code|<module>)
|
|
\{\{ fail\(\) \}\}
|
|
File ".*debug?.pyc?", line \d+, in <lambda>
|
|
tmpl\.render\(fail=lambda: 1 / 0\)
|
|
ZeroDivisionError: (int(eger)? )?division (or modulo )?by zero
|
|
""",
|
|
)
|
|
|
|
def test_syntax_error(self, fs_env):
|
|
# The trailing .*? is for PyPy 2 and 3, which don't seem to
|
|
# clear the exception's original traceback, leaving the syntax
|
|
# error in the middle of other compiler frames.
|
|
self.assert_traceback_matches(
|
|
lambda: fs_env.get_template("syntaxerror.html"),
|
|
"""(?sm)
|
|
File ".*?syntaxerror.html", line 4, in (template|<module>)
|
|
\\{% endif %\\}.*?
|
|
(jinja2\\.exceptions\\.)?TemplateSyntaxError: Encountered unknown tag 'endif'. Jinja \
|
|
was looking for the following tags: 'endfor' or 'else'. The innermost block that needs \
|
|
to be closed is 'for'.
|
|
""",
|
|
)
|
|
|
|
def test_regular_syntax_error(self, fs_env):
|
|
def test():
|
|
raise TemplateSyntaxError("wtf", 42)
|
|
|
|
self.assert_traceback_matches(
|
|
test,
|
|
r"""
|
|
File ".*debug.pyc?", line \d+, in test
|
|
raise TemplateSyntaxError\("wtf", 42\)
|
|
(jinja2\.exceptions\.)?TemplateSyntaxError: wtf
|
|
line 42""",
|
|
)
|
|
|
|
def test_pickleable_syntax_error(self, fs_env):
|
|
original = TemplateSyntaxError("bad template", 42, "test", "test.txt")
|
|
unpickled = pickle.loads(pickle.dumps(original))
|
|
assert str(original) == str(unpickled)
|
|
assert original.name == unpickled.name
|
|
|
|
def test_include_syntax_error_source(self, filesystem_loader):
|
|
e = Environment(
|
|
loader=ChoiceLoader(
|
|
[
|
|
filesystem_loader,
|
|
DictLoader({"inc": "a\n{% include 'syntaxerror.html' %}\nb"}),
|
|
]
|
|
)
|
|
)
|
|
t = e.get_template("inc")
|
|
|
|
with pytest.raises(TemplateSyntaxError) as exc_info:
|
|
t.render()
|
|
|
|
assert exc_info.value.source is not None
|
|
|
|
def test_local_extraction(self):
|
|
from jinja2.debug import get_template_locals
|
|
from jinja2.runtime import missing
|
|
|
|
locals = get_template_locals(
|
|
{
|
|
"l_0_foo": 42,
|
|
"l_1_foo": 23,
|
|
"l_2_foo": 13,
|
|
"l_0_bar": 99,
|
|
"l_1_bar": missing,
|
|
"l_0_baz": missing,
|
|
}
|
|
)
|
|
assert locals == {"foo": 13, "bar": 99}
|
|
|
|
def test_get_corresponding_lineno_traceback(self, fs_env):
|
|
tmpl = fs_env.get_template("test.html")
|
|
assert tmpl.get_corresponding_lineno(1) == 1
|