| from mako.template import Template |
| from mako import util |
| from test.util import result_lines, flatten_result |
| from test import TemplateTest, eq_ |
| |
| class CallTest(TemplateTest): |
| def test_call(self): |
| t = Template(""" |
| <%def name="foo()"> |
| hi im foo ${caller.body(y=5)} |
| </%def> |
| |
| <%call expr="foo()" args="y, **kwargs"> |
| this is the body, y is ${y} |
| </%call> |
| """) |
| assert result_lines(t.render()) == ['hi im foo', 'this is the body, y is 5'] |
| |
| |
| def test_compound_call(self): |
| t = Template(""" |
| |
| <%def name="bar()"> |
| this is bar |
| </%def> |
| |
| <%def name="comp1()"> |
| this comp1 should not be called |
| </%def> |
| |
| <%def name="foo()"> |
| foo calling comp1: ${caller.comp1(x=5)} |
| foo calling body: ${caller.body()} |
| </%def> |
| |
| <%call expr="foo()"> |
| <%def name="comp1(x)"> |
| this is comp1, ${x} |
| </%def> |
| this is the body, ${comp1(6)} |
| </%call> |
| ${bar()} |
| |
| """) |
| assert result_lines(t.render()) == ['foo calling comp1:', 'this is comp1, 5', 'foo calling body:', 'this is the body,', 'this is comp1, 6', 'this is bar'] |
| |
| def test_new_syntax(self): |
| """test foo:bar syntax, including multiline args and expression eval.""" |
| |
| # note the trailing whitespace in the bottom ${} expr, need to strip |
| # that off < python 2.7 |
| |
| t = Template(""" |
| <%def name="foo(x, y, q, z)"> |
| ${x} |
| ${y} |
| ${q} |
| ${",".join("%s->%s" % (a, b) for a, b in z)} |
| </%def> |
| |
| <%self:foo x="this is x" y="${'some ' + 'y'}" q=" |
| this |
| is |
| q" |
| |
| z="${[ |
| (1, 2), |
| (3, 4), |
| (5, 6) |
| ] |
| |
| }"/> |
| """) |
| |
| eq_( |
| result_lines(t.render()), |
| ['this is x', 'some y', 'this', 'is', 'q', '1->2,3->4,5->6'] |
| ) |
| |
| def test_ccall_caller(self): |
| t = Template(""" |
| <%def name="outer_func()"> |
| OUTER BEGIN |
| <%call expr="caller.inner_func()"> |
| INNER CALL |
| </%call> |
| OUTER END |
| </%def> |
| |
| <%call expr="outer_func()"> |
| <%def name="inner_func()"> |
| INNER BEGIN |
| ${caller.body()} |
| INNER END |
| </%def> |
| </%call> |
| |
| """) |
| #print t.code |
| assert result_lines(t.render()) == [ |
| "OUTER BEGIN", |
| "INNER BEGIN", |
| "INNER CALL", |
| "INNER END", |
| "OUTER END", |
| ] |
| |
| def test_stack_pop(self): |
| t = Template(""" |
| <%def name="links()" buffered="True"> |
| Some links |
| </%def> |
| |
| <%def name="wrapper(links)"> |
| <h1>${caller.body()}</h1> |
| ${links} |
| </%def> |
| |
| ## links() pushes a stack frame on. when complete, |
| ## 'nextcaller' must be restored |
| <%call expr="wrapper(links())"> |
| Some title |
| </%call> |
| |
| """) |
| |
| assert result_lines(t.render()) == [ |
| "<h1>", |
| "Some title", |
| "</h1>", |
| "Some links" |
| ] |
| |
| def test_conditional_call(self): |
| """test that 'caller' is non-None only if the immediate <%def> was called via <%call>""" |
| |
| t = Template(""" |
| <%def name="a()"> |
| % if caller: |
| ${ caller.body() } \\ |
| % endif |
| AAA |
| ${ b() } |
| </%def> |
| |
| <%def name="b()"> |
| % if caller: |
| ${ caller.body() } \\ |
| % endif |
| BBB |
| ${ c() } |
| </%def> |
| |
| <%def name="c()"> |
| % if caller: |
| ${ caller.body() } \\ |
| % endif |
| CCC |
| </%def> |
| |
| <%call expr="a()"> |
| CALL |
| </%call> |
| |
| """) |
| assert result_lines(t.render()) == [ |
| "CALL", |
| "AAA", |
| "BBB", |
| "CCC" |
| ] |
| |
| def test_chained_call(self): |
| """test %calls that are chained through their targets""" |
| t = Template(""" |
| <%def name="a()"> |
| this is a. |
| <%call expr="b()"> |
| this is a's ccall. heres my body: ${caller.body()} |
| </%call> |
| </%def> |
| <%def name="b()"> |
| this is b. heres my body: ${caller.body()} |
| whats in the body's caller's body ? |
| ${context.caller_stack[-2].body()} |
| </%def> |
| |
| <%call expr="a()"> |
| heres the main templ call |
| </%call> |
| |
| """) |
| assert result_lines(t.render()) == [ |
| 'this is a.', |
| 'this is b. heres my body:', |
| "this is a's ccall. heres my body:", |
| 'heres the main templ call', |
| "whats in the body's caller's body ?", |
| 'heres the main templ call' |
| ] |
| |
| def test_nested_call(self): |
| """test %calls that are nested inside each other""" |
| t = Template(""" |
| <%def name="foo()"> |
| ${caller.body(x=10)} |
| </%def> |
| |
| x is ${x} |
| <%def name="bar()"> |
| bar: ${caller.body()} |
| </%def> |
| |
| <%call expr="foo()" args="x"> |
| this is foo body: ${x} |
| |
| <%call expr="bar()"> |
| this is bar body: ${x} |
| </%call> |
| </%call> |
| """) |
| assert result_lines(t.render(x=5)) == [ |
| "x is 5", |
| "this is foo body: 10", |
| "bar:", |
| "this is bar body: 10" |
| ] |
| |
| def test_nested_call_2(self): |
| t = Template(""" |
| x is ${x} |
| <%def name="foo()"> |
| ${caller.foosub(x=10)} |
| </%def> |
| |
| <%def name="bar()"> |
| bar: ${caller.barsub()} |
| </%def> |
| |
| <%call expr="foo()"> |
| <%def name="foosub(x)"> |
| this is foo body: ${x} |
| |
| <%call expr="bar()"> |
| <%def name="barsub()"> |
| this is bar body: ${x} |
| </%def> |
| </%call> |
| |
| </%def> |
| |
| </%call> |
| """) |
| assert result_lines(t.render(x=5)) == [ |
| "x is 5", |
| "this is foo body: 10", |
| "bar:", |
| "this is bar body: 10" |
| ] |
| |
| def test_nested_call_3(self): |
| template = Template('''\ |
| <%def name="A()"> |
| ${caller.body()} |
| </%def> |
| |
| <%def name="B()"> |
| ${caller.foo()} |
| </%def> |
| |
| <%call expr="A()"> |
| <%call expr="B()"> |
| <%def name="foo()"> |
| foo |
| </%def> |
| </%call> |
| </%call> |
| |
| ''') |
| assert flatten_result(template.render()) == "foo" |
| |
| def test_nested_call_4(self): |
| base = """ |
| <%def name="A()"> |
| A_def |
| ${caller.body()} |
| </%def> |
| |
| <%def name="B()"> |
| B_def |
| ${caller.body()} |
| </%def> |
| """ |
| |
| template = Template(base + """ |
| <%def name="C()"> |
| C_def |
| <%self:B> |
| <%self:A> |
| A_body |
| </%self:A> |
| B_body |
| ${caller.body()} |
| </%self:B> |
| </%def> |
| |
| <%self:C> |
| C_body |
| </%self:C> |
| """) |
| |
| eq_( |
| flatten_result(template.render()), |
| "C_def B_def A_def A_body B_body C_body" |
| ) |
| |
| template = Template(base + """ |
| <%def name="C()"> |
| C_def |
| <%self:B> |
| B_body |
| ${caller.body()} |
| <%self:A> |
| A_body |
| </%self:A> |
| </%self:B> |
| </%def> |
| |
| <%self:C> |
| C_body |
| </%self:C> |
| """) |
| |
| eq_( |
| flatten_result(template.render()), |
| "C_def B_def B_body C_body A_def A_body" |
| ) |
| |
| def test_chained_call_in_nested(self): |
| t = Template(""" |
| <%def name="embedded()"> |
| <%def name="a()"> |
| this is a. |
| <%call expr="b()"> |
| this is a's ccall. heres my body: ${caller.body()} |
| </%call> |
| </%def> |
| <%def name="b()"> |
| this is b. heres my body: ${caller.body()} |
| whats in the body's caller's body ? ${context.caller_stack[-2].body()} |
| </%def> |
| |
| <%call expr="a()"> |
| heres the main templ call |
| </%call> |
| </%def> |
| ${embedded()} |
| """) |
| #print t.code |
| #print result_lines(t.render()) |
| assert result_lines(t.render()) == [ |
| 'this is a.', |
| 'this is b. heres my body:', |
| "this is a's ccall. heres my body:", |
| 'heres the main templ call', |
| "whats in the body's caller's body ?", |
| 'heres the main templ call' |
| ] |
| |
| def test_call_in_nested(self): |
| t = Template(""" |
| <%def name="a()"> |
| this is a ${b()} |
| <%def name="b()"> |
| this is b |
| <%call expr="c()"> |
| this is the body in b's call |
| </%call> |
| </%def> |
| <%def name="c()"> |
| this is c: ${caller.body()} |
| </%def> |
| </%def> |
| ${a()} |
| """) |
| assert result_lines(t.render()) == ['this is a', 'this is b', 'this is c:', "this is the body in b's call"] |
| |
| def test_composed_def(self): |
| t = Template(""" |
| <%def name="f()"><f>${caller.body()}</f></%def> |
| <%def name="g()"><g>${caller.body()}</g></%def> |
| <%def name="fg()"> |
| <%self:f><%self:g>${caller.body()}</%self:g></%self:f> |
| </%def> |
| <%self:fg>fgbody</%self:fg> |
| """) |
| assert result_lines(t.render()) == ['<f><g>fgbody</g></f>'] |
| |
| def test_regular_defs(self): |
| t = Template(""" |
| <%! |
| @runtime.supports_caller |
| def a(context): |
| context.write("this is a") |
| if context['caller']: |
| context['caller'].body() |
| context.write("a is done") |
| return '' |
| %> |
| |
| <%def name="b()"> |
| this is b |
| our body: ${caller.body()} |
| ${a(context)} |
| </%def> |
| test 1 |
| <%call expr="a(context)"> |
| this is the body |
| </%call> |
| test 2 |
| <%call expr="b()"> |
| this is the body |
| </%call> |
| test 3 |
| <%call expr="b()"> |
| this is the body |
| <%call expr="b()"> |
| this is the nested body |
| </%call> |
| </%call> |
| |
| |
| """) |
| assert result_lines(t.render()) == [ |
| "test 1", |
| "this is a", |
| "this is the body", |
| "a is done", |
| "test 2", |
| "this is b", |
| "our body:", |
| "this is the body", |
| "this is aa is done", |
| "test 3", |
| "this is b", |
| "our body:", |
| "this is the body", |
| "this is b", |
| "our body:", |
| "this is the nested body", |
| "this is aa is done", |
| "this is aa is done" |
| ] |
| |
| def test_call_in_nested_2(self): |
| t = Template(""" |
| <%def name="a()"> |
| <%def name="d()"> |
| not this d |
| </%def> |
| this is a ${b()} |
| <%def name="b()"> |
| <%def name="d()"> |
| not this d either |
| </%def> |
| this is b |
| <%call expr="c()"> |
| <%def name="d()"> |
| this is d |
| </%def> |
| this is the body in b's call |
| </%call> |
| </%def> |
| <%def name="c()"> |
| this is c: ${caller.body()} |
| the embedded "d" is: ${caller.d()} |
| </%def> |
| </%def> |
| ${a()} |
| """) |
| assert result_lines(t.render()) == ['this is a', 'this is b', 'this is c:', "this is the body in b's call", 'the embedded "d" is:', 'this is d'] |
| |
| class SelfCacheTest(TemplateTest): |
| """this test uses a now non-public API.""" |
| |
| def test_basic(self): |
| t = Template(""" |
| <%! |
| cached = None |
| %> |
| <%def name="foo()"> |
| <% |
| global cached |
| if cached: |
| return "cached: " + cached |
| __M_writer = context._push_writer() |
| %> |
| this is foo |
| <% |
| buf, __M_writer = context._pop_buffer_and_writer() |
| cached = buf.getvalue() |
| return cached |
| %> |
| </%def> |
| |
| ${foo()} |
| ${foo()} |
| """) |
| assert result_lines(t.render()) == [ |
| "this is foo", |
| "cached:", |
| "this is foo" |
| ] |
| |