from mako.template import Template from test import eq_ from test import TemplateTest from test.util import flatten_result from test.util import result_lines 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", ]