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.
285 lines
8.5 KiB
285 lines
8.5 KiB
import pytest
|
|
|
|
from jinja2 import DictLoader
|
|
from jinja2 import Environment
|
|
from jinja2 import TemplateRuntimeError
|
|
|
|
LAYOUTTEMPLATE = """\
|
|
|{% block block1 %}block 1 from layout{% endblock %}
|
|
|{% block block2 %}block 2 from layout{% endblock %}
|
|
|{% block block3 %}
|
|
{% block block4 %}nested block 4 from layout{% endblock %}
|
|
{% endblock %}|"""
|
|
|
|
LEVEL1TEMPLATE = """\
|
|
{% extends "layout" %}
|
|
{% block block1 %}block 1 from level1{% endblock %}"""
|
|
|
|
LEVEL2TEMPLATE = """\
|
|
{% extends "level1" %}
|
|
{% block block2 %}{% block block5 %}nested block 5 from level2{%
|
|
endblock %}{% endblock %}"""
|
|
|
|
LEVEL3TEMPLATE = """\
|
|
{% extends "level2" %}
|
|
{% block block5 %}block 5 from level3{% endblock %}
|
|
{% block block4 %}block 4 from level3{% endblock %}
|
|
"""
|
|
|
|
LEVEL4TEMPLATE = """\
|
|
{% extends "level3" %}
|
|
{% block block3 %}block 3 from level4{% endblock %}
|
|
"""
|
|
|
|
WORKINGTEMPLATE = """\
|
|
{% extends "layout" %}
|
|
{% block block1 %}
|
|
{% if false %}
|
|
{% block block2 %}
|
|
this should workd
|
|
{% endblock %}
|
|
{% endif %}
|
|
{% endblock %}
|
|
"""
|
|
|
|
DOUBLEEXTENDS = """\
|
|
{% extends "layout" %}
|
|
{% extends "layout" %}
|
|
{% block block1 %}
|
|
{% if false %}
|
|
{% block block2 %}
|
|
this should workd
|
|
{% endblock %}
|
|
{% endif %}
|
|
{% endblock %}
|
|
"""
|
|
|
|
|
|
@pytest.fixture
|
|
def env():
|
|
return Environment(
|
|
loader=DictLoader(
|
|
{
|
|
"layout": LAYOUTTEMPLATE,
|
|
"level1": LEVEL1TEMPLATE,
|
|
"level2": LEVEL2TEMPLATE,
|
|
"level3": LEVEL3TEMPLATE,
|
|
"level4": LEVEL4TEMPLATE,
|
|
"working": WORKINGTEMPLATE,
|
|
"doublee": DOUBLEEXTENDS,
|
|
}
|
|
),
|
|
trim_blocks=True,
|
|
)
|
|
|
|
|
|
class TestInheritance:
|
|
def test_layout(self, env):
|
|
tmpl = env.get_template("layout")
|
|
assert tmpl.render() == (
|
|
"|block 1 from layout|block 2 from layout|nested block 4 from layout|"
|
|
)
|
|
|
|
def test_level1(self, env):
|
|
tmpl = env.get_template("level1")
|
|
assert tmpl.render() == (
|
|
"|block 1 from level1|block 2 from layout|nested block 4 from layout|"
|
|
)
|
|
|
|
def test_level2(self, env):
|
|
tmpl = env.get_template("level2")
|
|
assert tmpl.render() == (
|
|
"|block 1 from level1|nested block 5 from "
|
|
"level2|nested block 4 from layout|"
|
|
)
|
|
|
|
def test_level3(self, env):
|
|
tmpl = env.get_template("level3")
|
|
assert tmpl.render() == (
|
|
"|block 1 from level1|block 5 from level3|block 4 from level3|"
|
|
)
|
|
|
|
def test_level4(self, env):
|
|
tmpl = env.get_template("level4")
|
|
assert tmpl.render() == (
|
|
"|block 1 from level1|block 5 from level3|block 3 from level4|"
|
|
)
|
|
|
|
def test_super(self, env):
|
|
env = Environment(
|
|
loader=DictLoader(
|
|
{
|
|
"a": "{% block intro %}INTRO{% endblock %}|"
|
|
"BEFORE|{% block data %}INNER{% endblock %}|AFTER",
|
|
"b": '{% extends "a" %}{% block data %}({{ '
|
|
"super() }}){% endblock %}",
|
|
"c": '{% extends "b" %}{% block intro %}--{{ '
|
|
"super() }}--{% endblock %}\n{% block data "
|
|
"%}[{{ super() }}]{% endblock %}",
|
|
}
|
|
)
|
|
)
|
|
tmpl = env.get_template("c")
|
|
assert tmpl.render() == "--INTRO--|BEFORE|[(INNER)]|AFTER"
|
|
|
|
def test_working(self, env):
|
|
env.get_template("working")
|
|
|
|
def test_reuse_blocks(self, env):
|
|
tmpl = env.from_string(
|
|
"{{ self.foo() }}|{% block foo %}42{% endblock %}|{{ self.foo() }}"
|
|
)
|
|
assert tmpl.render() == "42|42|42"
|
|
|
|
def test_preserve_blocks(self, env):
|
|
env = Environment(
|
|
loader=DictLoader(
|
|
{
|
|
"a": "{% if false %}{% block x %}A{% endblock %}"
|
|
"{% endif %}{{ self.x() }}",
|
|
"b": '{% extends "a" %}{% block x %}B{{ super() }}{% endblock %}',
|
|
}
|
|
)
|
|
)
|
|
tmpl = env.get_template("b")
|
|
assert tmpl.render() == "BA"
|
|
|
|
def test_dynamic_inheritance(self, env):
|
|
env = Environment(
|
|
loader=DictLoader(
|
|
{
|
|
"master1": "MASTER1{% block x %}{% endblock %}",
|
|
"master2": "MASTER2{% block x %}{% endblock %}",
|
|
"child": "{% extends master %}{% block x %}CHILD{% endblock %}",
|
|
}
|
|
)
|
|
)
|
|
tmpl = env.get_template("child")
|
|
for m in range(1, 3):
|
|
assert tmpl.render(master=f"master{m}") == f"MASTER{m}CHILD"
|
|
|
|
def test_multi_inheritance(self, env):
|
|
env = Environment(
|
|
loader=DictLoader(
|
|
{
|
|
"master1": "MASTER1{% block x %}{% endblock %}",
|
|
"master2": "MASTER2{% block x %}{% endblock %}",
|
|
"child": """{% if master %}{% extends master %}{% else %}{% extends
|
|
'master1' %}{% endif %}{% block x %}CHILD{% endblock %}""",
|
|
}
|
|
)
|
|
)
|
|
tmpl = env.get_template("child")
|
|
assert tmpl.render(master="master2") == "MASTER2CHILD"
|
|
assert tmpl.render(master="master1") == "MASTER1CHILD"
|
|
assert tmpl.render() == "MASTER1CHILD"
|
|
|
|
def test_scoped_block(self, env):
|
|
env = Environment(
|
|
loader=DictLoader(
|
|
{
|
|
"master.html": "{% for item in seq %}[{% block item scoped %}"
|
|
"{% endblock %}]{% endfor %}"
|
|
}
|
|
)
|
|
)
|
|
t = env.from_string(
|
|
"{% extends 'master.html' %}{% block item %}{{ item }}{% endblock %}"
|
|
)
|
|
assert t.render(seq=list(range(5))) == "[0][1][2][3][4]"
|
|
|
|
def test_super_in_scoped_block(self, env):
|
|
env = Environment(
|
|
loader=DictLoader(
|
|
{
|
|
"master.html": "{% for item in seq %}[{% block item scoped %}"
|
|
"{{ item }}{% endblock %}]{% endfor %}"
|
|
}
|
|
)
|
|
)
|
|
t = env.from_string(
|
|
'{% extends "master.html" %}{% block item %}'
|
|
"{{ super() }}|{{ item * 2 }}{% endblock %}"
|
|
)
|
|
assert t.render(seq=list(range(5))) == "[0|0][1|2][2|4][3|6][4|8]"
|
|
|
|
def test_scoped_block_after_inheritance(self, env):
|
|
env = Environment(
|
|
loader=DictLoader(
|
|
{
|
|
"layout.html": """
|
|
{% block useless %}{% endblock %}
|
|
""",
|
|
"index.html": """
|
|
{%- extends 'layout.html' %}
|
|
{% from 'helpers.html' import foo with context %}
|
|
{% block useless %}
|
|
{% for x in [1, 2, 3] %}
|
|
{% block testing scoped %}
|
|
{{ foo(x) }}
|
|
{% endblock %}
|
|
{% endfor %}
|
|
{% endblock %}
|
|
""",
|
|
"helpers.html": """
|
|
{% macro foo(x) %}{{ the_foo + x }}{% endmacro %}
|
|
""",
|
|
}
|
|
)
|
|
)
|
|
rv = env.get_template("index.html").render(the_foo=42).split()
|
|
assert rv == ["43", "44", "45"]
|
|
|
|
|
|
class TestBugFix:
|
|
def test_fixed_macro_scoping_bug(self, env):
|
|
assert (
|
|
Environment(
|
|
loader=DictLoader(
|
|
{
|
|
"test.html": """\
|
|
{% extends 'details.html' %}
|
|
|
|
{% macro my_macro() %}
|
|
my_macro
|
|
{% endmacro %}
|
|
|
|
{% block inner_box %}
|
|
{{ my_macro() }}
|
|
{% endblock %}
|
|
""",
|
|
"details.html": """\
|
|
{% extends 'standard.html' %}
|
|
|
|
{% macro my_macro() %}
|
|
my_macro
|
|
{% endmacro %}
|
|
|
|
{% block content %}
|
|
{% block outer_box %}
|
|
outer_box
|
|
{% block inner_box %}
|
|
inner_box
|
|
{% endblock %}
|
|
{% endblock %}
|
|
{% endblock %}
|
|
""",
|
|
"standard.html": """
|
|
{% block content %} {% endblock %}
|
|
""",
|
|
}
|
|
)
|
|
)
|
|
.get_template("test.html")
|
|
.render()
|
|
.split()
|
|
== ["outer_box", "my_macro"]
|
|
)
|
|
|
|
def test_double_extends(self, env):
|
|
"""Ensures that a template with more than 1 {% extends ... %} usage
|
|
raises a ``TemplateError``.
|
|
"""
|
|
with pytest.raises(TemplateRuntimeError, match="extended multiple times"):
|
|
env.get_template("doublee").render()
|