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.
224 lines
8.1 KiB
224 lines
8.1 KiB
4 months ago
|
import pytest
|
||
|
|
||
|
from jinja2.environment import Environment
|
||
|
from jinja2.exceptions import TemplateNotFound
|
||
|
from jinja2.exceptions import TemplatesNotFound
|
||
|
from jinja2.exceptions import TemplateSyntaxError
|
||
|
from jinja2.exceptions import UndefinedError
|
||
|
from jinja2.loaders import DictLoader
|
||
|
|
||
|
|
||
|
@pytest.fixture
|
||
|
def test_env():
|
||
|
env = Environment(
|
||
|
loader=DictLoader(
|
||
|
dict(
|
||
|
module="{% macro test() %}[{{ foo }}|{{ bar }}]{% endmacro %}",
|
||
|
header="[{{ foo }}|{{ 23 }}]",
|
||
|
o_printer="({{ o }})",
|
||
|
)
|
||
|
)
|
||
|
)
|
||
|
env.globals["bar"] = 23
|
||
|
return env
|
||
|
|
||
|
|
||
|
class TestImports:
|
||
|
def test_context_imports(self, test_env):
|
||
|
t = test_env.from_string('{% import "module" as m %}{{ m.test() }}')
|
||
|
assert t.render(foo=42) == "[|23]"
|
||
|
t = test_env.from_string(
|
||
|
'{% import "module" as m without context %}{{ m.test() }}'
|
||
|
)
|
||
|
assert t.render(foo=42) == "[|23]"
|
||
|
t = test_env.from_string(
|
||
|
'{% import "module" as m with context %}{{ m.test() }}'
|
||
|
)
|
||
|
assert t.render(foo=42) == "[42|23]"
|
||
|
t = test_env.from_string('{% from "module" import test %}{{ test() }}')
|
||
|
assert t.render(foo=42) == "[|23]"
|
||
|
t = test_env.from_string(
|
||
|
'{% from "module" import test without context %}{{ test() }}'
|
||
|
)
|
||
|
assert t.render(foo=42) == "[|23]"
|
||
|
t = test_env.from_string(
|
||
|
'{% from "module" import test with context %}{{ test() }}'
|
||
|
)
|
||
|
assert t.render(foo=42) == "[42|23]"
|
||
|
|
||
|
def test_import_needs_name(self, test_env):
|
||
|
test_env.from_string('{% from "foo" import bar %}')
|
||
|
test_env.from_string('{% from "foo" import bar, baz %}')
|
||
|
|
||
|
with pytest.raises(TemplateSyntaxError):
|
||
|
test_env.from_string('{% from "foo" import %}')
|
||
|
|
||
|
def test_no_trailing_comma(self, test_env):
|
||
|
with pytest.raises(TemplateSyntaxError):
|
||
|
test_env.from_string('{% from "foo" import bar, %}')
|
||
|
|
||
|
with pytest.raises(TemplateSyntaxError):
|
||
|
test_env.from_string('{% from "foo" import bar,, %}')
|
||
|
|
||
|
with pytest.raises(TemplateSyntaxError):
|
||
|
test_env.from_string('{% from "foo" import, %}')
|
||
|
|
||
|
def test_trailing_comma_with_context(self, test_env):
|
||
|
test_env.from_string('{% from "foo" import bar, baz with context %}')
|
||
|
test_env.from_string('{% from "foo" import bar, baz, with context %}')
|
||
|
test_env.from_string('{% from "foo" import bar, with context %}')
|
||
|
test_env.from_string('{% from "foo" import bar, with, context %}')
|
||
|
test_env.from_string('{% from "foo" import bar, with with context %}')
|
||
|
|
||
|
with pytest.raises(TemplateSyntaxError):
|
||
|
test_env.from_string('{% from "foo" import bar,, with context %}')
|
||
|
|
||
|
with pytest.raises(TemplateSyntaxError):
|
||
|
test_env.from_string('{% from "foo" import bar with context, %}')
|
||
|
|
||
|
def test_exports(self, test_env):
|
||
|
m = test_env.from_string(
|
||
|
"""
|
||
|
{% macro toplevel() %}...{% endmacro %}
|
||
|
{% macro __private() %}...{% endmacro %}
|
||
|
{% set variable = 42 %}
|
||
|
{% for item in [1] %}
|
||
|
{% macro notthere() %}{% endmacro %}
|
||
|
{% endfor %}
|
||
|
"""
|
||
|
).module
|
||
|
assert m.toplevel() == "..."
|
||
|
assert not hasattr(m, "__missing")
|
||
|
assert m.variable == 42
|
||
|
assert not hasattr(m, "notthere")
|
||
|
|
||
|
def test_not_exported(self, test_env):
|
||
|
t = test_env.from_string("{% from 'module' import nothing %}{{ nothing() }}")
|
||
|
|
||
|
with pytest.raises(UndefinedError, match="does not export the requested name"):
|
||
|
t.render()
|
||
|
|
||
|
def test_import_with_globals(self, test_env):
|
||
|
env = Environment(
|
||
|
loader=DictLoader(
|
||
|
{
|
||
|
"macros": "{% macro test() %}foo: {{ foo }}{% endmacro %}",
|
||
|
"test": "{% import 'macros' as m %}{{ m.test() }}",
|
||
|
"test1": "{% import 'macros' as m %}{{ m.test() }}",
|
||
|
}
|
||
|
)
|
||
|
)
|
||
|
tmpl = env.get_template("test", globals={"foo": "bar"})
|
||
|
assert tmpl.render() == "foo: bar"
|
||
|
|
||
|
tmpl = env.get_template("test1")
|
||
|
assert tmpl.render() == "foo: "
|
||
|
|
||
|
def test_import_with_globals_override(self, test_env):
|
||
|
env = Environment(
|
||
|
loader=DictLoader(
|
||
|
{
|
||
|
"macros": "{% set foo = '42' %}{% macro test() %}"
|
||
|
"foo: {{ foo }}{% endmacro %}",
|
||
|
"test": "{% from 'macros' import test %}{{ test() }}",
|
||
|
}
|
||
|
)
|
||
|
)
|
||
|
tmpl = env.get_template("test", globals={"foo": "bar"})
|
||
|
assert tmpl.render() == "foo: 42"
|
||
|
|
||
|
def test_from_import_with_globals(self, test_env):
|
||
|
env = Environment(
|
||
|
loader=DictLoader(
|
||
|
{
|
||
|
"macros": "{% macro testing() %}foo: {{ foo }}{% endmacro %}",
|
||
|
"test": "{% from 'macros' import testing %}{{ testing() }}",
|
||
|
}
|
||
|
)
|
||
|
)
|
||
|
tmpl = env.get_template("test", globals={"foo": "bar"})
|
||
|
assert tmpl.render() == "foo: bar"
|
||
|
|
||
|
|
||
|
class TestIncludes:
|
||
|
def test_context_include(self, test_env):
|
||
|
t = test_env.from_string('{% include "header" %}')
|
||
|
assert t.render(foo=42) == "[42|23]"
|
||
|
t = test_env.from_string('{% include "header" with context %}')
|
||
|
assert t.render(foo=42) == "[42|23]"
|
||
|
t = test_env.from_string('{% include "header" without context %}')
|
||
|
assert t.render(foo=42) == "[|23]"
|
||
|
|
||
|
def test_choice_includes(self, test_env):
|
||
|
t = test_env.from_string('{% include ["missing", "header"] %}')
|
||
|
assert t.render(foo=42) == "[42|23]"
|
||
|
|
||
|
t = test_env.from_string('{% include ["missing", "missing2"] ignore missing %}')
|
||
|
assert t.render(foo=42) == ""
|
||
|
|
||
|
t = test_env.from_string('{% include ["missing", "missing2"] %}')
|
||
|
pytest.raises(TemplateNotFound, t.render)
|
||
|
with pytest.raises(TemplatesNotFound) as e:
|
||
|
t.render()
|
||
|
|
||
|
assert e.value.templates == ["missing", "missing2"]
|
||
|
assert e.value.name == "missing2"
|
||
|
|
||
|
def test_includes(t, **ctx):
|
||
|
ctx["foo"] = 42
|
||
|
assert t.render(ctx) == "[42|23]"
|
||
|
|
||
|
t = test_env.from_string('{% include ["missing", "header"] %}')
|
||
|
test_includes(t)
|
||
|
t = test_env.from_string("{% include x %}")
|
||
|
test_includes(t, x=["missing", "header"])
|
||
|
t = test_env.from_string('{% include [x, "header"] %}')
|
||
|
test_includes(t, x="missing")
|
||
|
t = test_env.from_string("{% include x %}")
|
||
|
test_includes(t, x="header")
|
||
|
t = test_env.from_string("{% include [x] %}")
|
||
|
test_includes(t, x="header")
|
||
|
|
||
|
def test_include_ignoring_missing(self, test_env):
|
||
|
t = test_env.from_string('{% include "missing" %}')
|
||
|
pytest.raises(TemplateNotFound, t.render)
|
||
|
for extra in "", "with context", "without context":
|
||
|
t = test_env.from_string(
|
||
|
'{% include "missing" ignore missing ' + extra + " %}"
|
||
|
)
|
||
|
assert t.render() == ""
|
||
|
|
||
|
def test_context_include_with_overrides(self, test_env):
|
||
|
env = Environment(
|
||
|
loader=DictLoader(
|
||
|
dict(
|
||
|
main="{% for item in [1, 2, 3] %}{% include 'item' %}{% endfor %}",
|
||
|
item="{{ item }}",
|
||
|
)
|
||
|
)
|
||
|
)
|
||
|
assert env.get_template("main").render() == "123"
|
||
|
|
||
|
def test_unoptimized_scopes(self, test_env):
|
||
|
t = test_env.from_string(
|
||
|
"""
|
||
|
{% macro outer(o) %}
|
||
|
{% macro inner() %}
|
||
|
{% include "o_printer" %}
|
||
|
{% endmacro %}
|
||
|
{{ inner() }}
|
||
|
{% endmacro %}
|
||
|
{{ outer("FOO") }}
|
||
|
"""
|
||
|
)
|
||
|
assert t.render().strip() == "(FOO)"
|
||
|
|
||
|
def test_import_from_with_context(self):
|
||
|
env = Environment(
|
||
|
loader=DictLoader({"a": "{% macro x() %}{{ foobar }}{% endmacro %}"})
|
||
|
)
|
||
|
t = env.from_string(
|
||
|
"{% set foobar = 42 %}{% from 'a' import x with context %}{{ x() }}"
|
||
|
)
|
||
|
assert t.render() == "42"
|