• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1from jinja2 import nodes
2from jinja2.idtracking import symbols_for_node
3
4
5def test_basics():
6    for_loop = nodes.For(
7        nodes.Name("foo", "store"),
8        nodes.Name("seq", "load"),
9        [nodes.Output([nodes.Name("foo", "load")])],
10        [],
11        None,
12        False,
13    )
14    tmpl = nodes.Template(
15        [nodes.Assign(nodes.Name("foo", "store"), nodes.Name("bar", "load")), for_loop]
16    )
17
18    sym = symbols_for_node(tmpl)
19    assert sym.refs == {
20        "foo": "l_0_foo",
21        "bar": "l_0_bar",
22        "seq": "l_0_seq",
23    }
24    assert sym.loads == {
25        "l_0_foo": ("undefined", None),
26        "l_0_bar": ("resolve", "bar"),
27        "l_0_seq": ("resolve", "seq"),
28    }
29
30    sym = symbols_for_node(for_loop, sym)
31    assert sym.refs == {
32        "foo": "l_1_foo",
33    }
34    assert sym.loads == {
35        "l_1_foo": ("param", None),
36    }
37
38
39def test_complex():
40    title_block = nodes.Block(
41        "title", [nodes.Output([nodes.TemplateData("Page Title")])], False
42    )
43
44    render_title_macro = nodes.Macro(
45        "render_title",
46        [nodes.Name("title", "param")],
47        [],
48        [
49            nodes.Output(
50                [
51                    nodes.TemplateData('\n  <div class="title">\n    <h1>'),
52                    nodes.Name("title", "load"),
53                    nodes.TemplateData("</h1>\n    <p>"),
54                    nodes.Name("subtitle", "load"),
55                    nodes.TemplateData("</p>\n    "),
56                ]
57            ),
58            nodes.Assign(
59                nodes.Name("subtitle", "store"), nodes.Const("something else")
60            ),
61            nodes.Output(
62                [
63                    nodes.TemplateData("\n    <p>"),
64                    nodes.Name("subtitle", "load"),
65                    nodes.TemplateData("</p>\n  </div>\n"),
66                    nodes.If(
67                        nodes.Name("something", "load"),
68                        [
69                            nodes.Assign(
70                                nodes.Name("title_upper", "store"),
71                                nodes.Filter(
72                                    nodes.Name("title", "load"),
73                                    "upper",
74                                    [],
75                                    [],
76                                    None,
77                                    None,
78                                ),
79                            ),
80                            nodes.Output(
81                                [
82                                    nodes.Name("title_upper", "load"),
83                                    nodes.Call(
84                                        nodes.Name("render_title", "load"),
85                                        [nodes.Const("Aha")],
86                                        [],
87                                        None,
88                                        None,
89                                    ),
90                                ]
91                            ),
92                        ],
93                        [],
94                        [],
95                    ),
96                ]
97            ),
98        ],
99    )
100
101    for_loop = nodes.For(
102        nodes.Name("item", "store"),
103        nodes.Name("seq", "load"),
104        [
105            nodes.Output(
106                [
107                    nodes.TemplateData("\n    <li>"),
108                    nodes.Name("item", "load"),
109                    nodes.TemplateData("</li>\n    <span>"),
110                ]
111            ),
112            nodes.Include(nodes.Const("helper.html"), True, False),
113            nodes.Output([nodes.TemplateData("</span>\n  ")]),
114        ],
115        [],
116        None,
117        False,
118    )
119
120    body_block = nodes.Block(
121        "body",
122        [
123            nodes.Output(
124                [
125                    nodes.TemplateData("\n  "),
126                    nodes.Call(
127                        nodes.Name("render_title", "load"),
128                        [nodes.Name("item", "load")],
129                        [],
130                        None,
131                        None,
132                    ),
133                    nodes.TemplateData("\n  <ul>\n  "),
134                ]
135            ),
136            for_loop,
137            nodes.Output([nodes.TemplateData("\n  </ul>\n")]),
138        ],
139        False,
140    )
141
142    tmpl = nodes.Template(
143        [
144            nodes.Extends(nodes.Const("layout.html")),
145            title_block,
146            render_title_macro,
147            body_block,
148        ]
149    )
150
151    tmpl_sym = symbols_for_node(tmpl)
152    assert tmpl_sym.refs == {
153        "render_title": "l_0_render_title",
154    }
155    assert tmpl_sym.loads == {
156        "l_0_render_title": ("undefined", None),
157    }
158    assert tmpl_sym.stores == {"render_title"}
159    assert tmpl_sym.dump_stores() == {
160        "render_title": "l_0_render_title",
161    }
162
163    macro_sym = symbols_for_node(render_title_macro, tmpl_sym)
164    assert macro_sym.refs == {
165        "subtitle": "l_1_subtitle",
166        "something": "l_1_something",
167        "title": "l_1_title",
168        "title_upper": "l_1_title_upper",
169    }
170    assert macro_sym.loads == {
171        "l_1_subtitle": ("resolve", "subtitle"),
172        "l_1_something": ("resolve", "something"),
173        "l_1_title": ("param", None),
174        "l_1_title_upper": ("resolve", "title_upper"),
175    }
176    assert macro_sym.stores == {"title", "title_upper", "subtitle"}
177    assert macro_sym.find_ref("render_title") == "l_0_render_title"
178    assert macro_sym.dump_stores() == {
179        "title": "l_1_title",
180        "title_upper": "l_1_title_upper",
181        "subtitle": "l_1_subtitle",
182        "render_title": "l_0_render_title",
183    }
184
185    body_sym = symbols_for_node(body_block)
186    assert body_sym.refs == {
187        "item": "l_0_item",
188        "seq": "l_0_seq",
189        "render_title": "l_0_render_title",
190    }
191    assert body_sym.loads == {
192        "l_0_item": ("resolve", "item"),
193        "l_0_seq": ("resolve", "seq"),
194        "l_0_render_title": ("resolve", "render_title"),
195    }
196    assert body_sym.stores == set()
197
198    for_sym = symbols_for_node(for_loop, body_sym)
199    assert for_sym.refs == {
200        "item": "l_1_item",
201    }
202    assert for_sym.loads == {
203        "l_1_item": ("param", None),
204    }
205    assert for_sym.stores == {"item"}
206    assert for_sym.dump_stores() == {
207        "item": "l_1_item",
208    }
209
210
211def test_if_branching_stores():
212    tmpl = nodes.Template(
213        [
214            nodes.If(
215                nodes.Name("expression", "load"),
216                [nodes.Assign(nodes.Name("variable", "store"), nodes.Const(42))],
217                [],
218                [],
219            )
220        ]
221    )
222
223    sym = symbols_for_node(tmpl)
224    assert sym.refs == {"variable": "l_0_variable", "expression": "l_0_expression"}
225    assert sym.stores == {"variable"}
226    assert sym.loads == {
227        "l_0_variable": ("resolve", "variable"),
228        "l_0_expression": ("resolve", "expression"),
229    }
230    assert sym.dump_stores() == {
231        "variable": "l_0_variable",
232    }
233
234
235def test_if_branching_stores_undefined():
236    tmpl = nodes.Template(
237        [
238            nodes.Assign(nodes.Name("variable", "store"), nodes.Const(23)),
239            nodes.If(
240                nodes.Name("expression", "load"),
241                [nodes.Assign(nodes.Name("variable", "store"), nodes.Const(42))],
242                [],
243                [],
244            ),
245        ]
246    )
247
248    sym = symbols_for_node(tmpl)
249    assert sym.refs == {"variable": "l_0_variable", "expression": "l_0_expression"}
250    assert sym.stores == {"variable"}
251    assert sym.loads == {
252        "l_0_variable": ("undefined", None),
253        "l_0_expression": ("resolve", "expression"),
254    }
255    assert sym.dump_stores() == {
256        "variable": "l_0_variable",
257    }
258
259
260def test_if_branching_multi_scope():
261    for_loop = nodes.For(
262        nodes.Name("item", "store"),
263        nodes.Name("seq", "load"),
264        [
265            nodes.If(
266                nodes.Name("expression", "load"),
267                [nodes.Assign(nodes.Name("x", "store"), nodes.Const(42))],
268                [],
269                [],
270            ),
271            nodes.Include(nodes.Const("helper.html"), True, False),
272        ],
273        [],
274        None,
275        False,
276    )
277
278    tmpl = nodes.Template(
279        [nodes.Assign(nodes.Name("x", "store"), nodes.Const(23)), for_loop]
280    )
281
282    tmpl_sym = symbols_for_node(tmpl)
283    for_sym = symbols_for_node(for_loop, tmpl_sym)
284    assert for_sym.stores == {"item", "x"}
285    assert for_sym.loads == {
286        "l_1_x": ("alias", "l_0_x"),
287        "l_1_item": ("param", None),
288        "l_1_expression": ("resolve", "expression"),
289    }
290