1from mako import lookup
2from mako.testing.helpers import result_lines
3
4
5class InheritanceTest:
6    def test_basic(self):
7        collection = lookup.TemplateLookup()
8
9        collection.put_string(
10            "main",
11            """
12<%inherit file="base"/>
13
14<%def name="header()">
15    main header.
16</%def>
17
18this is the content.
19""",
20        )
21
22        collection.put_string(
23            "base",
24            """
25This is base.
26
27header: ${self.header()}
28
29body: ${self.body()}
30
31footer: ${self.footer()}
32
33<%def name="footer()">
34    this is the footer. header again ${next.header()}
35</%def>
36""",
37        )
38
39        assert result_lines(collection.get_template("main").render()) == [
40            "This is base.",
41            "header:",
42            "main header.",
43            "body:",
44            "this is the content.",
45            "footer:",
46            "this is the footer. header again",
47            "main header.",
48        ]
49
50    def test_multilevel_nesting(self):
51        collection = lookup.TemplateLookup()
52
53        collection.put_string(
54            "main",
55            """
56<%inherit file="layout"/>
57<%def name="d()">main_d</%def>
58main_body ${parent.d()}
59full stack from the top:
60    ${self.name} ${parent.name} ${parent.context['parent'].name} """
61            """${parent.context['parent'].context['parent'].name}
62""",
63        )
64
65        collection.put_string(
66            "layout",
67            """
68<%inherit file="general"/>
69<%def name="d()">layout_d</%def>
70layout_body
71parent name: ${parent.name}
72${parent.d()}
73${parent.context['parent'].d()}
74${next.body()}
75""",
76        )
77
78        collection.put_string(
79            "general",
80            """
81<%inherit file="base"/>
82<%def name="d()">general_d</%def>
83general_body
84${next.d()}
85${next.context['next'].d()}
86${next.body()}
87""",
88        )
89        collection.put_string(
90            "base",
91            """
92base_body
93full stack from the base:
94    ${self.name} ${self.context['parent'].name} """
95            """${self.context['parent'].context['parent'].name} """
96            """${self.context['parent'].context['parent'].context['parent'].name}
97${next.body()}
98<%def name="d()">base_d</%def>
99""",
100        )
101
102        assert result_lines(collection.get_template("main").render()) == [
103            "base_body",
104            "full stack from the base:",
105            "self:main self:layout self:general self:base",
106            "general_body",
107            "layout_d",
108            "main_d",
109            "layout_body",
110            "parent name: self:general",
111            "general_d",
112            "base_d",
113            "main_body layout_d",
114            "full stack from the top:",
115            "self:main self:layout self:general self:base",
116        ]
117
118    def test_includes(self):
119        """test that an included template also has its full hierarchy
120        invoked."""
121        collection = lookup.TemplateLookup()
122
123        collection.put_string(
124            "base",
125            """
126        <%def name="a()">base_a</%def>
127        This is the base.
128        ${next.body()}
129        End base.
130""",
131        )
132
133        collection.put_string(
134            "index",
135            """
136        <%inherit file="base"/>
137        this is index.
138        a is: ${self.a()}
139        <%include file="secondary"/>
140""",
141        )
142
143        collection.put_string(
144            "secondary",
145            """
146        <%inherit file="base"/>
147        this is secondary.
148        a is: ${self.a()}
149""",
150        )
151
152        assert result_lines(collection.get_template("index").render()) == [
153            "This is the base.",
154            "this is index.",
155            "a is: base_a",
156            "This is the base.",
157            "this is secondary.",
158            "a is: base_a",
159            "End base.",
160            "End base.",
161        ]
162
163    def test_namespaces(self):
164        """test that templates used via <%namespace> have access to an
165        inheriting 'self', and that the full 'self' is also exported."""
166        collection = lookup.TemplateLookup()
167
168        collection.put_string(
169            "base",
170            """
171        <%def name="a()">base_a</%def>
172        <%def name="b()">base_b</%def>
173        This is the base.
174        ${next.body()}
175""",
176        )
177
178        collection.put_string(
179            "layout",
180            """
181        <%inherit file="base"/>
182        <%def name="a()">layout_a</%def>
183        This is the layout..
184        ${next.body()}
185""",
186        )
187
188        collection.put_string(
189            "index",
190            """
191        <%inherit file="base"/>
192        <%namespace name="sc" file="secondary"/>
193        this is index.
194        a is: ${self.a()}
195        sc.a is: ${sc.a()}
196        sc.b is: ${sc.b()}
197        sc.c is: ${sc.c()}
198        sc.body is: ${sc.body()}
199""",
200        )
201
202        collection.put_string(
203            "secondary",
204            """
205        <%inherit file="layout"/>
206        <%def name="c()">secondary_c.  a is ${self.a()} b is ${self.b()} """
207            """d is ${self.d()}</%def>
208        <%def name="d()">secondary_d.</%def>
209        this is secondary.
210        a is: ${self.a()}
211        c is: ${self.c()}
212""",
213        )
214
215        assert result_lines(collection.get_template("index").render()) == [
216            "This is the base.",
217            "this is index.",
218            "a is: base_a",
219            "sc.a is: layout_a",
220            "sc.b is: base_b",
221            "sc.c is: secondary_c. a is layout_a b is base_b d is "
222            "secondary_d.",
223            "sc.body is:",
224            "this is secondary.",
225            "a is: layout_a",
226            "c is: secondary_c. a is layout_a b is base_b d is secondary_d.",
227        ]
228
229    def test_pageargs(self):
230        collection = lookup.TemplateLookup()
231        collection.put_string(
232            "base",
233            """
234            this is the base.
235
236            <%
237            sorted_ = pageargs.items()
238            sorted_ = sorted(sorted_)
239            %>
240            pageargs: (type: ${type(pageargs)}) ${sorted_}
241            <%def name="foo()">
242                ${next.body(**context.kwargs)}
243            </%def>
244
245            ${foo()}
246        """,
247        )
248        collection.put_string(
249            "index",
250            """
251            <%inherit file="base"/>
252            <%page args="x, y, z=7"/>
253            print ${x}, ${y}, ${z}
254        """,
255        )
256
257        assert result_lines(
258            collection.get_template("index").render_unicode(x=5, y=10)
259        ) == [
260            "this is the base.",
261            "pageargs: (type: <class 'dict'>) [('x', 5), ('y', 10)]",
262            "print 5, 10, 7",
263        ]
264
265    def test_pageargs_2(self):
266        collection = lookup.TemplateLookup()
267        collection.put_string(
268            "base",
269            """
270            this is the base.
271
272            ${next.body(**context.kwargs)}
273
274            <%def name="foo(**kwargs)">
275                ${next.body(**kwargs)}
276            </%def>
277
278            <%def name="bar(**otherargs)">
279                ${next.body(z=16, **context.kwargs)}
280            </%def>
281
282            ${foo(x=12, y=15, z=8)}
283            ${bar(x=19, y=17)}
284        """,
285        )
286        collection.put_string(
287            "index",
288            """
289            <%inherit file="base"/>
290            <%page args="x, y, z=7"/>
291            pageargs: ${x}, ${y}, ${z}
292        """,
293        )
294        assert result_lines(
295            collection.get_template("index").render(x=5, y=10)
296        ) == [
297            "this is the base.",
298            "pageargs: 5, 10, 7",
299            "pageargs: 12, 15, 8",
300            "pageargs: 5, 10, 16",
301        ]
302
303    def test_pageargs_err(self):
304        collection = lookup.TemplateLookup()
305        collection.put_string(
306            "base",
307            """
308            this is the base.
309            ${next.body()}
310        """,
311        )
312        collection.put_string(
313            "index",
314            """
315            <%inherit file="base"/>
316            <%page args="x, y, z=7"/>
317            print ${x}, ${y}, ${z}
318        """,
319        )
320        try:
321            print(collection.get_template("index").render(x=5, y=10))
322            assert False
323        except TypeError:
324            assert True
325
326    def test_toplevel(self):
327        collection = lookup.TemplateLookup()
328        collection.put_string(
329            "base",
330            """
331            this is the base.
332            ${next.body()}
333        """,
334        )
335        collection.put_string(
336            "index",
337            """
338            <%inherit file="base"/>
339            this is the body
340        """,
341        )
342        assert result_lines(collection.get_template("index").render()) == [
343            "this is the base.",
344            "this is the body",
345        ]
346        assert result_lines(
347            collection.get_template("index").get_def("body").render()
348        ) == ["this is the body"]
349
350    def test_dynamic(self):
351        collection = lookup.TemplateLookup()
352        collection.put_string(
353            "base",
354            """
355            this is the base.
356            ${next.body()}
357        """,
358        )
359        collection.put_string(
360            "index",
361            """
362            <%!
363                def dyn(context):
364                    if context.get('base', None) is not None:
365                        return 'base'
366                    else:
367                        return None
368            %>
369            <%inherit file="${dyn(context)}"/>
370            this is index.
371        """,
372        )
373        assert result_lines(collection.get_template("index").render()) == [
374            "this is index."
375        ]
376        assert result_lines(
377            collection.get_template("index").render(base=True)
378        ) == ["this is the base.", "this is index."]
379
380    def test_in_call(self):
381        collection = lookup.TemplateLookup()
382        collection.put_string(
383            "/layout.html",
384            """
385        Super layout!
386        <%call expr="self.grid()">
387            ${next.body()}
388        </%call>
389        Oh yea!
390
391        <%def name="grid()">
392            Parent grid
393                ${caller.body()}
394            End Parent
395        </%def>
396        """,
397        )
398
399        collection.put_string(
400            "/subdir/layout.html",
401            """
402        ${next.body()}
403        <%def name="grid()">
404           Subdir grid
405               ${caller.body()}
406           End subdir
407        </%def>
408        <%inherit file="/layout.html"/>
409        """,
410        )
411
412        collection.put_string(
413            "/subdir/renderedtemplate.html",
414            """
415        Holy smokes!
416        <%inherit file="/subdir/layout.html"/>
417        """,
418        )
419
420        assert result_lines(
421            collection.get_template("/subdir/renderedtemplate.html").render()
422        ) == [
423            "Super layout!",
424            "Subdir grid",
425            "Holy smokes!",
426            "End subdir",
427            "Oh yea!",
428        ]
429