summaryrefslogtreecommitdiff
path: root/test/test_def.py
diff options
context:
space:
mode:
Diffstat (limited to 'test/test_def.py')
-rw-r--r--test/test_def.py755
1 files changed, 755 insertions, 0 deletions
diff --git a/test/test_def.py b/test/test_def.py
new file mode 100644
index 0000000..fd96433
--- /dev/null
+++ b/test/test_def.py
@@ -0,0 +1,755 @@
+from mako import lookup
+from mako.template import Template
+from mako.testing.assertions import assert_raises
+from mako.testing.assertions import eq_
+from mako.testing.fixtures import TemplateTest
+from mako.testing.helpers import flatten_result
+from mako.testing.helpers import result_lines
+
+
+class DefTest(TemplateTest):
+ def test_def_noargs(self):
+ template = Template(
+ """
+
+ ${mycomp()}
+
+ <%def name="mycomp()">
+ hello mycomp ${variable}
+ </%def>
+
+ """
+ )
+ eq_(template.render(variable="hi").strip(), """hello mycomp hi""")
+
+ def test_def_blankargs(self):
+ template = Template(
+ """
+ <%def name="mycomp()">
+ hello mycomp ${variable}
+ </%def>
+
+ ${mycomp()}"""
+ )
+ eq_(template.render(variable="hi").strip(), "hello mycomp hi")
+
+ def test_def_args(self):
+ template = Template(
+ """
+ <%def name="mycomp(a, b)">
+ hello mycomp ${variable}, ${a}, ${b}
+ </%def>
+
+ ${mycomp(5, 6)}"""
+ )
+ eq_(
+ template.render(variable="hi", a=5, b=6).strip(),
+ """hello mycomp hi, 5, 6""",
+ )
+
+ def test_def_py3k_args(self):
+ template = Template(
+ """
+ <%def name="kwonly(one, two, *three, four, five=5, **six)">
+ look at all these args: ${one} ${two} ${three[0]} """
+ """${four} ${five} ${six['seven']}
+ </%def>
+
+ ${kwonly('one', 'two', 'three', four='four', seven='seven')}"""
+ )
+ eq_(
+ template.render(one=1, two=2, three=(3,), six=6).strip(),
+ """look at all these args: one two three four 5 seven""",
+ )
+
+ def test_inter_def(self):
+ """test defs calling each other"""
+ template = Template(
+ """
+ ${b()}
+
+ <%def name="a()">\
+ im a
+ </%def>
+
+ <%def name="b()">
+ im b
+ and heres a: ${a()}
+ </%def>
+
+ <%def name="c()">
+ im c
+ </%def>
+"""
+ )
+ # check that "a" is declared in "b", but not in "c"
+ assert "a" not in template.module.render_c.__code__.co_varnames
+ assert "a" in template.module.render_b.__code__.co_varnames
+
+ # then test output
+ eq_(flatten_result(template.render()), "im b and heres a: im a")
+
+ def test_toplevel(self):
+ """test calling a def from the top level"""
+
+ template = Template(
+ """
+
+ this is the body
+
+ <%def name="a()">
+ this is a
+ </%def>
+
+ <%def name="b(x, y)">
+ this is b, ${x} ${y}
+ </%def>
+
+ """
+ )
+
+ self._do_test(
+ template.get_def("a"), "this is a", filters=flatten_result
+ )
+ self._do_test(
+ template.get_def("b"),
+ "this is b, 10 15",
+ template_args={"x": 10, "y": 15},
+ filters=flatten_result,
+ )
+ self._do_test(
+ template.get_def("body"),
+ "this is the body",
+ filters=flatten_result,
+ )
+
+ # test that args outside of the dict can be used
+ self._do_test(
+ template.get_def("a"),
+ "this is a",
+ filters=flatten_result,
+ template_args={"q": 5, "zq": "test"},
+ )
+
+ def test_def_operations(self):
+ """test get/list/has def"""
+
+ template = Template(
+ """
+
+ this is the body
+
+ <%def name="a()">
+ this is a
+ </%def>
+
+ <%def name="b(x, y)">
+ this is b, ${x} ${y}
+ </%def>
+
+ """
+ )
+
+ assert template.get_def("a")
+ assert template.get_def("b")
+ assert_raises(AttributeError, template.get_def, ("c"))
+
+ assert template.has_def("a")
+ assert template.has_def("b")
+ assert not template.has_def("c")
+
+ defs = template.list_defs()
+ assert "a" in defs
+ assert "b" in defs
+ assert "body" in defs
+ assert "c" not in defs
+
+
+class ScopeTest(TemplateTest):
+ """test scoping rules. The key is, enclosing
+ scope always takes precedence over contextual scope."""
+
+ def test_scope_one(self):
+ self._do_memory_test(
+ """
+ <%def name="a()">
+ this is a, and y is ${y}
+ </%def>
+
+ ${a()}
+
+ <%
+ y = 7
+ %>
+
+ ${a()}
+
+""",
+ "this is a, and y is None this is a, and y is 7",
+ filters=flatten_result,
+ template_args={"y": None},
+ )
+
+ def test_scope_two(self):
+ t = Template(
+ """
+ y is ${y}
+
+ <%
+ y = 7
+ %>
+
+ y is ${y}
+"""
+ )
+ try:
+ t.render(y=None)
+ assert False
+ except UnboundLocalError:
+ assert True
+
+ def test_scope_four(self):
+ """test that variables are pulled
+ from 'enclosing' scope before context."""
+ t = Template(
+ """
+ <%
+ x = 5
+ %>
+ <%def name="a()">
+ this is a. x is ${x}.
+ </%def>
+
+ <%def name="b()">
+ <%
+ x = 9
+ %>
+ this is b. x is ${x}.
+ calling a. ${a()}
+ </%def>
+
+ ${b()}
+"""
+ )
+ eq_(
+ flatten_result(t.render()),
+ "this is b. x is 9. calling a. this is a. x is 5.",
+ )
+
+ def test_scope_five(self):
+ """test that variables are pulled from
+ 'enclosing' scope before context."""
+ # same as test four, but adds a scope around it.
+ t = Template(
+ """
+ <%def name="enclosing()">
+ <%
+ x = 5
+ %>
+ <%def name="a()">
+ this is a. x is ${x}.
+ </%def>
+
+ <%def name="b()">
+ <%
+ x = 9
+ %>
+ this is b. x is ${x}.
+ calling a. ${a()}
+ </%def>
+
+ ${b()}
+ </%def>
+ ${enclosing()}
+"""
+ )
+ eq_(
+ flatten_result(t.render()),
+ "this is b. x is 9. calling a. this is a. x is 5.",
+ )
+
+ def test_scope_six(self):
+ """test that the initial context counts
+ as 'enclosing' scope, for plain defs"""
+ t = Template(
+ """
+
+ <%def name="a()">
+ a: x is ${x}
+ </%def>
+
+ <%def name="b()">
+ <%
+ x = 10
+ %>
+ b. x is ${x}. ${a()}
+ </%def>
+
+ ${b()}
+ """
+ )
+ eq_(flatten_result(t.render(x=5)), "b. x is 10. a: x is 5")
+
+ def test_scope_seven(self):
+ """test that the initial context counts
+ as 'enclosing' scope, for nested defs"""
+ t = Template(
+ """
+ <%def name="enclosing()">
+ <%def name="a()">
+ a: x is ${x}
+ </%def>
+
+ <%def name="b()">
+ <%
+ x = 10
+ %>
+ b. x is ${x}. ${a()}
+ </%def>
+
+ ${b()}
+ </%def>
+ ${enclosing()}
+ """
+ )
+ eq_(flatten_result(t.render(x=5)), "b. x is 10. a: x is 5")
+
+ def test_scope_eight(self):
+ """test that the initial context counts
+ as 'enclosing' scope, for nested defs"""
+ t = Template(
+ """
+ <%def name="enclosing()">
+ <%def name="a()">
+ a: x is ${x}
+ </%def>
+
+ <%def name="b()">
+ <%
+ x = 10
+ %>
+
+ b. x is ${x}. ${a()}
+ </%def>
+
+ ${b()}
+ </%def>
+ ${enclosing()}
+ """
+ )
+ eq_(flatten_result(t.render(x=5)), "b. x is 10. a: x is 5")
+
+ def test_scope_nine(self):
+ """test that 'enclosing scope' doesnt
+ get exported to other templates"""
+
+ l = lookup.TemplateLookup()
+ l.put_string(
+ "main",
+ """
+ <%
+ x = 5
+ %>
+ this is main. <%include file="secondary"/>
+""",
+ )
+
+ l.put_string(
+ "secondary",
+ """
+ this is secondary. x is ${x}
+""",
+ )
+
+ eq_(
+ flatten_result(l.get_template("main").render(x=2)),
+ "this is main. this is secondary. x is 2",
+ )
+
+ def test_scope_ten(self):
+ t = Template(
+ """
+ <%def name="a()">
+ <%def name="b()">
+ <%
+ y = 19
+ %>
+ b/c: ${c()}
+ b/y: ${y}
+ </%def>
+ <%def name="c()">
+ c/y: ${y}
+ </%def>
+
+ <%
+ # we assign to "y". but the 'enclosing
+ # scope' of "b" and "c" is from
+ # the "y" on the outside
+ y = 10
+ %>
+ a/y: ${y}
+ a/b: ${b()}
+ </%def>
+
+ <%
+ y = 7
+ %>
+ main/a: ${a()}
+ main/y: ${y}
+ """
+ )
+ eq_(
+ flatten_result(t.render()),
+ "main/a: a/y: 10 a/b: b/c: c/y: 10 b/y: 19 main/y: 7",
+ )
+
+ def test_scope_eleven(self):
+ t = Template(
+ """
+ x is ${x}
+ <%def name="a(x)">
+ this is a, ${b()}
+ <%def name="b()">
+ this is b, x is ${x}
+ </%def>
+ </%def>
+
+ ${a(x=5)}
+"""
+ )
+ eq_(
+ result_lines(t.render(x=10)),
+ ["x is 10", "this is a,", "this is b, x is 5"],
+ )
+
+ def test_unbound_scope(self):
+ t = Template(
+ """
+ <%
+ y = 10
+ %>
+ <%def name="a()">
+ y is: ${y}
+ <%
+ # should raise error ?
+ y = 15
+ %>
+ y is ${y}
+ </%def>
+ ${a()}
+"""
+ )
+ assert_raises(UnboundLocalError, t.render)
+
+ def test_unbound_scope_two(self):
+ t = Template(
+ """
+ <%def name="enclosing()">
+ <%
+ y = 10
+ %>
+ <%def name="a()">
+ y is: ${y}
+ <%
+ # should raise error ?
+ y = 15
+ %>
+ y is ${y}
+ </%def>
+ ${a()}
+ </%def>
+ ${enclosing()}
+"""
+ )
+ try:
+ print(t.render())
+ assert False
+ except UnboundLocalError:
+ assert True
+
+ def test_canget_kwargs(self):
+ """test that arguments passed to the body()
+ function are accessible by top-level defs"""
+ l = lookup.TemplateLookup()
+ l.put_string(
+ "base",
+ """
+
+ ${next.body(x=12)}
+
+ """,
+ )
+
+ l.put_string(
+ "main",
+ """
+ <%inherit file="base"/>
+ <%page args="x"/>
+ this is main. x is ${x}
+
+ ${a()}
+
+ <%def name="a(**args)">
+ this is a, x is ${x}
+ </%def>
+ """,
+ )
+
+ # test via inheritance
+ eq_(
+ result_lines(l.get_template("main").render()),
+ ["this is main. x is 12", "this is a, x is 12"],
+ )
+
+ l.put_string(
+ "another",
+ """
+ <%namespace name="ns" file="main"/>
+
+ ${ns.body(x=15)}
+ """,
+ )
+ # test via namespace
+ eq_(
+ result_lines(l.get_template("another").render()),
+ ["this is main. x is 15", "this is a, x is 15"],
+ )
+
+ def test_inline_expression_from_arg_one(self):
+ """test that cache_key=${foo} gets its value from
+ the 'foo' argument in the <%def> tag,
+ and strict_undefined doesn't complain.
+
+ this is #191.
+
+ """
+ t = Template(
+ """
+ <%def name="layout(foo)" cached="True" cache_key="${foo}">
+ foo: ${foo}
+ </%def>
+
+ ${layout(3)}
+ """,
+ strict_undefined=True,
+ cache_impl="plain",
+ )
+
+ eq_(result_lines(t.render()), ["foo: 3"])
+
+ def test_interpret_expression_from_arg_two(self):
+ """test that cache_key=${foo} gets its value from
+ the 'foo' argument regardless of it being passed
+ from the context.
+
+ This is here testing that there's no change
+ to existing behavior before and after #191.
+
+ """
+ t = Template(
+ """
+ <%def name="layout(foo)" cached="True" cache_key="${foo}">
+ foo: ${value}
+ </%def>
+
+ ${layout(3)}
+ """,
+ cache_impl="plain",
+ )
+
+ eq_(result_lines(t.render(foo="foo", value=1)), ["foo: 1"])
+ eq_(result_lines(t.render(foo="bar", value=2)), ["foo: 1"])
+
+
+class NestedDefTest(TemplateTest):
+ def test_nested_def(self):
+ t = Template(
+ """
+
+ ${hi()}
+
+ <%def name="hi()">
+ hey, im hi.
+ and heres ${foo()}, ${bar()}
+
+ <%def name="foo()">
+ this is foo
+ </%def>
+
+ <%def name="bar()">
+ this is bar
+ </%def>
+ </%def>
+"""
+ )
+ eq_(
+ flatten_result(t.render()),
+ "hey, im hi. and heres this is foo , this is bar",
+ )
+
+ def test_nested_2(self):
+ t = Template(
+ """
+ x is ${x}
+ <%def name="a()">
+ this is a, x is ${x}
+ ${b()}
+ <%def name="b()">
+ this is b: ${x}
+ </%def>
+ </%def>
+ ${a()}
+"""
+ )
+
+ eq_(
+ flatten_result(t.render(x=10)),
+ "x is 10 this is a, x is 10 this is b: 10",
+ )
+
+ def test_nested_with_args(self):
+ t = Template(
+ """
+ ${a()}
+ <%def name="a()">
+ <%def name="b(x, y=2)">
+ b x is ${x} y is ${y}
+ </%def>
+ a ${b(5)}
+ </%def>
+"""
+ )
+ eq_(flatten_result(t.render()), "a b x is 5 y is 2")
+
+ def test_nested_def_2(self):
+ template = Template(
+ """
+ ${a()}
+ <%def name="a()">
+ <%def name="b()">
+ <%def name="c()">
+ comp c
+ </%def>
+ ${c()}
+ </%def>
+ ${b()}
+ </%def>
+"""
+ )
+ eq_(flatten_result(template.render()), "comp c")
+
+ def test_nested_nested_def(self):
+ t = Template(
+ """
+
+ ${a()}
+ <%def name="a()">
+ a
+ <%def name="b1()">
+ a_b1
+ </%def>
+ <%def name="b2()">
+ a_b2 ${c1()}
+ <%def name="c1()">
+ a_b2_c1
+ </%def>
+ </%def>
+ <%def name="b3()">
+ a_b3 ${c1()}
+ <%def name="c1()">
+ a_b3_c1 heres x: ${x}
+ <%
+ y = 7
+ %>
+ y is ${y}
+ </%def>
+ <%def name="c2()">
+ a_b3_c2
+ y is ${y}
+ c1 is ${c1()}
+ </%def>
+ ${c2()}
+ </%def>
+
+ ${b1()} ${b2()} ${b3()}
+ </%def>
+"""
+ )
+ eq_(
+ flatten_result(t.render(x=5, y=None)),
+ "a a_b1 a_b2 a_b2_c1 a_b3 a_b3_c1 "
+ "heres x: 5 y is 7 a_b3_c2 y is "
+ "None c1 is a_b3_c1 heres x: 5 y is 7",
+ )
+
+ def test_nested_nested_def_2(self):
+ t = Template(
+ """
+ <%def name="a()">
+ this is a ${b()}
+ <%def name="b()">
+ this is b
+ ${c()}
+ </%def>
+
+ <%def name="c()">
+ this is c
+ </%def>
+ </%def>
+ ${a()}
+"""
+ )
+ eq_(flatten_result(t.render()), "this is a this is b this is c")
+
+ def test_outer_scope(self):
+ t = Template(
+ """
+ <%def name="a()">
+ a: x is ${x}
+ </%def>
+
+ <%def name="b()">
+ <%def name="c()">
+ <%
+ x = 10
+ %>
+ c. x is ${x}. ${a()}
+ </%def>
+
+ b. ${c()}
+ </%def>
+
+ ${b()}
+
+ x is ${x}
+"""
+ )
+ eq_(flatten_result(t.render(x=5)), "b. c. x is 10. a: x is 5 x is 5")
+
+
+class ExceptionTest(TemplateTest):
+ def test_raise(self):
+ template = Template(
+ """
+ <%
+ raise Exception("this is a test")
+ %>
+ """,
+ format_exceptions=False,
+ )
+ assert_raises(Exception, template.render)
+
+ def test_handler(self):
+ def handle(context, error):
+ context.write("error message is " + str(error))
+ return True
+
+ template = Template(
+ """
+ <%
+ raise Exception("this is a test")
+ %>
+ """,
+ error_handler=handle,
+ )
+ eq_(template.render().strip(), "error message is this is a test")