• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1from mako.template import Template
2from mako.testing.assertions import eq_
3from mako.testing.fixtures import TemplateTest
4from mako.testing.helpers import flatten_result
5from mako.testing.helpers import result_lines
6
7
8class CallTest(TemplateTest):
9    def test_call(self):
10        t = Template(
11            """
12        <%def name="foo()">
13            hi im foo ${caller.body(y=5)}
14        </%def>
15
16        <%call expr="foo()" args="y, **kwargs">
17            this is the body, y is ${y}
18        </%call>
19"""
20        )
21        assert result_lines(t.render()) == [
22            "hi im foo",
23            "this is the body, y is 5",
24        ]
25
26    def test_compound_call(self):
27        t = Template(
28            """
29
30        <%def name="bar()">
31            this is bar
32        </%def>
33
34        <%def name="comp1()">
35            this comp1 should not be called
36        </%def>
37
38        <%def name="foo()">
39            foo calling comp1: ${caller.comp1(x=5)}
40            foo calling body: ${caller.body()}
41        </%def>
42
43        <%call expr="foo()">
44            <%def name="comp1(x)">
45                this is comp1, ${x}
46            </%def>
47            this is the body, ${comp1(6)}
48        </%call>
49        ${bar()}
50
51"""
52        )
53        assert result_lines(t.render()) == [
54            "foo calling comp1:",
55            "this is comp1, 5",
56            "foo calling body:",
57            "this is the body,",
58            "this is comp1, 6",
59            "this is bar",
60        ]
61
62    def test_new_syntax(self):
63        """test foo:bar syntax, including multiline args and expression
64        eval."""
65
66        # note the trailing whitespace in the bottom ${} expr, need to strip
67        # that off < python 2.7
68
69        t = Template(
70            """
71            <%def name="foo(x, y, q, z)">
72                ${x}
73                ${y}
74                ${q}
75                ${",".join("%s->%s" % (a, b) for a, b in z)}
76            </%def>
77
78            <%self:foo x="this is x" y="${'some ' + 'y'}" q="
79                this
80                is
81                q"
82
83                z="${[
84                (1, 2),
85                (3, 4),
86                (5, 6)
87            ]
88
89            }"/>
90        """
91        )
92
93        eq_(
94            result_lines(t.render()),
95            ["this is x", "some y", "this", "is", "q", "1->2,3->4,5->6"],
96        )
97
98    def test_ccall_caller(self):
99        t = Template(
100            """
101        <%def name="outer_func()">
102        OUTER BEGIN
103            <%call expr="caller.inner_func()">
104                INNER CALL
105            </%call>
106        OUTER END
107        </%def>
108
109        <%call expr="outer_func()">
110            <%def name="inner_func()">
111                INNER BEGIN
112                ${caller.body()}
113                INNER END
114            </%def>
115        </%call>
116
117        """
118        )
119        # print t.code
120        assert result_lines(t.render()) == [
121            "OUTER BEGIN",
122            "INNER BEGIN",
123            "INNER CALL",
124            "INNER END",
125            "OUTER END",
126        ]
127
128    def test_stack_pop(self):
129        t = Template(
130            """
131        <%def name="links()" buffered="True">
132           Some links
133        </%def>
134
135        <%def name="wrapper(links)">
136           <h1>${caller.body()}</h1>
137           ${links}
138        </%def>
139
140        ## links() pushes a stack frame on.  when complete,
141        ## 'nextcaller' must be restored
142        <%call expr="wrapper(links())">
143           Some title
144        </%call>
145
146        """
147        )
148
149        assert result_lines(t.render()) == [
150            "<h1>",
151            "Some title",
152            "</h1>",
153            "Some links",
154        ]
155
156    def test_conditional_call(self):
157        """test that 'caller' is non-None only if the immediate <%def> was
158        called via <%call>"""
159
160        t = Template(
161            """
162        <%def name="a()">
163        % if caller:
164        ${ caller.body() } \\
165        % endif
166        AAA
167        ${ b() }
168        </%def>
169
170        <%def name="b()">
171        % if caller:
172        ${ caller.body() } \\
173        % endif
174        BBB
175        ${ c() }
176        </%def>
177
178        <%def name="c()">
179        % if caller:
180        ${ caller.body() } \\
181        % endif
182        CCC
183        </%def>
184
185        <%call expr="a()">
186        CALL
187        </%call>
188
189        """
190        )
191        assert result_lines(t.render()) == ["CALL", "AAA", "BBB", "CCC"]
192
193    def test_chained_call(self):
194        """test %calls that are chained through their targets"""
195        t = Template(
196            """
197            <%def name="a()">
198                this is a.
199                <%call expr="b()">
200                    this is a's ccall.  heres my body: ${caller.body()}
201                </%call>
202            </%def>
203            <%def name="b()">
204                this is b.  heres  my body: ${caller.body()}
205                whats in the body's caller's body ?
206                ${context.caller_stack[-2].body()}
207            </%def>
208
209            <%call expr="a()">
210                heres the main templ call
211            </%call>
212
213"""
214        )
215        assert result_lines(t.render()) == [
216            "this is a.",
217            "this is b. heres my body:",
218            "this is a's ccall. heres my body:",
219            "heres the main templ call",
220            "whats in the body's caller's body ?",
221            "heres the main templ call",
222        ]
223
224    def test_nested_call(self):
225        """test %calls that are nested inside each other"""
226        t = Template(
227            """
228            <%def name="foo()">
229                ${caller.body(x=10)}
230            </%def>
231
232            x is ${x}
233            <%def name="bar()">
234                bar: ${caller.body()}
235            </%def>
236
237            <%call expr="foo()" args="x">
238                this is foo body: ${x}
239
240                <%call expr="bar()">
241                    this is bar body: ${x}
242                </%call>
243            </%call>
244"""
245        )
246        assert result_lines(t.render(x=5)) == [
247            "x is 5",
248            "this is foo body: 10",
249            "bar:",
250            "this is bar body: 10",
251        ]
252
253    def test_nested_call_2(self):
254        t = Template(
255            """
256            x is ${x}
257            <%def name="foo()">
258                ${caller.foosub(x=10)}
259            </%def>
260
261            <%def name="bar()">
262                bar: ${caller.barsub()}
263            </%def>
264
265            <%call expr="foo()">
266                <%def name="foosub(x)">
267                this is foo body: ${x}
268
269                <%call expr="bar()">
270                    <%def name="barsub()">
271                    this is bar body: ${x}
272                    </%def>
273                </%call>
274
275                </%def>
276
277            </%call>
278"""
279        )
280        assert result_lines(t.render(x=5)) == [
281            "x is 5",
282            "this is foo body: 10",
283            "bar:",
284            "this is bar body: 10",
285        ]
286
287    def test_nested_call_3(self):
288        template = Template(
289            """\
290        <%def name="A()">
291          ${caller.body()}
292        </%def>
293
294        <%def name="B()">
295          ${caller.foo()}
296        </%def>
297
298        <%call expr="A()">
299          <%call expr="B()">
300            <%def name="foo()">
301              foo
302            </%def>
303          </%call>
304        </%call>
305
306        """
307        )
308        assert flatten_result(template.render()) == "foo"
309
310    def test_nested_call_4(self):
311        base = """
312        <%def name="A()">
313        A_def
314        ${caller.body()}
315        </%def>
316
317        <%def name="B()">
318        B_def
319        ${caller.body()}
320        </%def>
321        """
322
323        template = Template(
324            base
325            + """
326        <%def name="C()">
327         C_def
328         <%self:B>
329           <%self:A>
330              A_body
331           </%self:A>
332            B_body
333           ${caller.body()}
334         </%self:B>
335        </%def>
336
337        <%self:C>
338        C_body
339        </%self:C>
340        """
341        )
342
343        eq_(
344            flatten_result(template.render()),
345            "C_def B_def A_def A_body B_body C_body",
346        )
347
348        template = Template(
349            base
350            + """
351        <%def name="C()">
352         C_def
353         <%self:B>
354            B_body
355           ${caller.body()}
356           <%self:A>
357              A_body
358           </%self:A>
359         </%self:B>
360        </%def>
361
362        <%self:C>
363        C_body
364        </%self:C>
365        """
366        )
367
368        eq_(
369            flatten_result(template.render()),
370            "C_def B_def B_body C_body A_def A_body",
371        )
372
373    def test_chained_call_in_nested(self):
374        t = Template(
375            """
376            <%def name="embedded()">
377            <%def name="a()">
378                this is a.
379                <%call expr="b()">
380                    this is a's ccall.  heres my body: ${caller.body()}
381                </%call>
382            </%def>
383            <%def name="b()">
384                this is b.  heres  my body: ${caller.body()}
385                whats in the body's caller's body ? """
386            """${context.caller_stack[-2].body()}
387            </%def>
388
389            <%call expr="a()">
390                heres the main templ call
391            </%call>
392            </%def>
393            ${embedded()}
394"""
395        )
396        # print t.code
397        # print result_lines(t.render())
398        assert result_lines(t.render()) == [
399            "this is a.",
400            "this is b. heres my body:",
401            "this is a's ccall. heres my body:",
402            "heres the main templ call",
403            "whats in the body's caller's body ?",
404            "heres the main templ call",
405        ]
406
407    def test_call_in_nested(self):
408        t = Template(
409            """
410            <%def name="a()">
411                this is a ${b()}
412                <%def name="b()">
413                    this is b
414                    <%call expr="c()">
415                        this is the body in b's call
416                    </%call>
417                </%def>
418                <%def name="c()">
419                    this is c: ${caller.body()}
420                </%def>
421            </%def>
422        ${a()}
423"""
424        )
425        assert result_lines(t.render()) == [
426            "this is a",
427            "this is b",
428            "this is c:",
429            "this is the body in b's call",
430        ]
431
432    def test_composed_def(self):
433        t = Template(
434            """
435            <%def name="f()"><f>${caller.body()}</f></%def>
436            <%def name="g()"><g>${caller.body()}</g></%def>
437            <%def name="fg()">
438                <%self:f><%self:g>${caller.body()}</%self:g></%self:f>
439            </%def>
440            <%self:fg>fgbody</%self:fg>
441            """
442        )
443        assert result_lines(t.render()) == ["<f><g>fgbody</g></f>"]
444
445    def test_regular_defs(self):
446        t = Template(
447            """
448        <%!
449            @runtime.supports_caller
450            def a(context):
451                context.write("this is a")
452                if context['caller']:
453                    context['caller'].body()
454                context.write("a is done")
455                return ''
456        %>
457
458        <%def name="b()">
459            this is b
460            our body: ${caller.body()}
461            ${a(context)}
462        </%def>
463        test 1
464        <%call expr="a(context)">
465            this is the body
466        </%call>
467        test 2
468        <%call expr="b()">
469            this is the body
470        </%call>
471        test 3
472        <%call expr="b()">
473            this is the body
474            <%call expr="b()">
475                this is the nested body
476            </%call>
477        </%call>
478
479
480        """
481        )
482        assert result_lines(t.render()) == [
483            "test 1",
484            "this is a",
485            "this is the body",
486            "a is done",
487            "test 2",
488            "this is b",
489            "our body:",
490            "this is the body",
491            "this is aa is done",
492            "test 3",
493            "this is b",
494            "our body:",
495            "this is the body",
496            "this is b",
497            "our body:",
498            "this is the nested body",
499            "this is aa is done",
500            "this is aa is done",
501        ]
502
503    def test_call_in_nested_2(self):
504        t = Template(
505            """
506            <%def name="a()">
507                <%def name="d()">
508                    not this d
509                </%def>
510                this is a ${b()}
511                <%def name="b()">
512                    <%def name="d()">
513                        not this d either
514                    </%def>
515                    this is b
516                    <%call expr="c()">
517                        <%def name="d()">
518                            this is d
519                        </%def>
520                        this is the body in b's call
521                    </%call>
522                </%def>
523                <%def name="c()">
524                    this is c: ${caller.body()}
525                    the embedded "d" is: ${caller.d()}
526                </%def>
527            </%def>
528        ${a()}
529"""
530        )
531        assert result_lines(t.render()) == [
532            "this is a",
533            "this is b",
534            "this is c:",
535            "this is the body in b's call",
536            'the embedded "d" is:',
537            "this is d",
538        ]
539
540
541class SelfCacheTest(TemplateTest):
542    """this test uses a now non-public API."""
543
544    def test_basic(self):
545        t = Template(
546            """
547        <%!
548            cached = None
549        %>
550        <%def name="foo()">
551            <%
552                global cached
553                if cached:
554                    return "cached: " + cached
555                __M_writer = context._push_writer()
556            %>
557            this is foo
558            <%
559                buf, __M_writer = context._pop_buffer_and_writer()
560                cached = buf.getvalue()
561                return cached
562            %>
563        </%def>
564
565        ${foo()}
566        ${foo()}
567"""
568        )
569        assert result_lines(t.render()) == [
570            "this is foo",
571            "cached:",
572            "this is foo",
573        ]
574