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