test_idtracking.py 8.5 KB

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