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)} <%call expr="foo()" args="y, **kwargs"> this is the body, y is ${y} """) 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 name="comp1()"> this comp1 should not be called <%def name="foo()"> foo calling comp1: ${caller.comp1(x=5)} foo calling body: ${caller.body()} <%call expr="foo()"> <%def name="comp1(x)"> this is comp1, ${x} this is the body, ${comp1(6)} ${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)} <%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 OUTER END <%call expr="outer_func()"> <%def name="inner_func()"> INNER BEGIN ${caller.body()} INNER END """) #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 name="wrapper(links)">

${caller.body()}

${links} ## links() pushes a stack frame on. when complete, ## 'nextcaller' must be restored <%call expr="wrapper(links())"> Some title """) assert result_lines(t.render()) == [ "

", "Some title", "

", "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 name="b()"> % if caller: ${ caller.body() } \\ % endif BBB ${ c() } <%def name="c()"> % if caller: ${ caller.body() } \\ % endif CCC <%call expr="a()"> 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()} <%def name="b()"> this is b. heres my body: ${caller.body()} whats in the body's caller's body ? ${context.caller_stack[-2].body()} <%call expr="a()"> heres the main templ 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)} x is ${x} <%def name="bar()"> bar: ${caller.body()} <%call expr="foo()" args="x"> this is foo body: ${x} <%call expr="bar()"> this is bar body: ${x} """) 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 name="bar()"> bar: ${caller.barsub()} <%call expr="foo()"> <%def name="foosub(x)"> this is foo body: ${x} <%call expr="bar()"> <%def name="barsub()"> this is bar body: ${x} """) 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 name="B()"> ${caller.foo()} <%call expr="A()"> <%call expr="B()"> <%def name="foo()"> foo ''') assert flatten_result(template.render()) == "foo" def test_nested_call_4(self): base = """ <%def name="A()"> A_def ${caller.body()} <%def name="B()"> B_def ${caller.body()} """ template = Template(base + """ <%def name="C()"> C_def <%self:B> <%self:A> A_body B_body ${caller.body()} <%self:C> C_body """) 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:C> C_body """) 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()} <%def name="b()"> this is b. heres my body: ${caller.body()} whats in the body's caller's body ? ${context.caller_stack[-2].body()} <%call expr="a()"> heres the main templ call ${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 <%def name="c()"> this is c: ${caller.body()} ${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()">${caller.body()} <%def name="g()">${caller.body()} <%def name="fg()"> <%self:f><%self:g>${caller.body()} <%self:fg>fgbody """) assert result_lines(t.render()) == ['fgbody'] 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)} test 1 <%call expr="a(context)"> this is the body test 2 <%call expr="b()"> this is the body test 3 <%call expr="b()"> this is the body <%call expr="b()"> this is the nested body """) 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 this is a ${b()} <%def name="b()"> <%def name="d()"> not this d either this is b <%call expr="c()"> <%def name="d()"> this is d this is the body in b's call <%def name="c()"> this is c: ${caller.body()} the embedded "d" is: ${caller.d()} ${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 %> ${foo()} ${foo()} """) assert result_lines(t.render()) == [ "this is foo", "cached:", "this is foo" ]