python-liquid 1.13.0__tar.gz → 2.0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (255) hide show
  1. python_liquid-2.0.1/PKG-INFO +165 -0
  2. python_liquid-2.0.1/README.md +135 -0
  3. python_liquid-2.0.1/liquid/__init__.py +246 -0
  4. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/analyze_tags.py +28 -23
  5. python_liquid-2.0.1/liquid/ast.py +239 -0
  6. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/builtin/__init__.py +34 -5
  7. python_liquid-2.0.1/liquid/builtin/content.py +41 -0
  8. python_liquid-2.0.1/liquid/builtin/expressions/__init__.py +47 -0
  9. python_liquid-2.0.1/liquid/builtin/expressions/_tokenize.py +186 -0
  10. python_liquid-2.0.1/liquid/builtin/expressions/arguments.py +207 -0
  11. python_liquid-2.0.1/liquid/builtin/expressions/filtered.py +387 -0
  12. python_liquid-2.0.1/liquid/builtin/expressions/logical.py +642 -0
  13. python_liquid-2.0.1/liquid/builtin/expressions/loop.py +278 -0
  14. python_liquid-2.0.1/liquid/builtin/expressions/path.py +163 -0
  15. python_liquid-2.0.1/liquid/builtin/expressions/primitive.py +417 -0
  16. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/builtin/filters/array.py +144 -65
  17. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/builtin/filters/extra.py +2 -5
  18. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/builtin/filters/math.py +7 -12
  19. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/builtin/filters/misc.py +5 -8
  20. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/builtin/filters/string.py +37 -25
  21. python_liquid-2.0.1/liquid/builtin/illegal.py +28 -0
  22. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/builtin/loaders/caching_file_system_loader.py +9 -27
  23. python_liquid-2.0.1/liquid/builtin/loaders/choice_loader.py +94 -0
  24. python_liquid-2.0.1/liquid/builtin/loaders/dict_loader.py +64 -0
  25. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/builtin/loaders/file_system_loader.py +36 -53
  26. python_liquid-2.0.1/liquid/builtin/loaders/mixins.py +184 -0
  27. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/builtin/loaders/package_loader.py +30 -20
  28. python_liquid-2.0.1/liquid/builtin/output.py +74 -0
  29. python_liquid-2.0.1/liquid/builtin/tags/assign_tag.py +75 -0
  30. python_liquid-2.0.1/liquid/builtin/tags/capture_tag.py +98 -0
  31. python_liquid-2.0.1/liquid/builtin/tags/case_tag.py +287 -0
  32. python_liquid-2.0.1/liquid/builtin/tags/comment_tag.py +77 -0
  33. python_liquid-2.0.1/liquid/builtin/tags/cycle_tag.py +127 -0
  34. python_liquid-2.0.1/liquid/builtin/tags/decrement_tag.py +59 -0
  35. python_liquid-2.0.1/liquid/builtin/tags/doc_tag.py +68 -0
  36. python_liquid-2.0.1/liquid/builtin/tags/echo_tag.py +45 -0
  37. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/builtin/tags/for_tag.py +177 -213
  38. python_liquid-2.0.1/liquid/builtin/tags/if_tag.py +209 -0
  39. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/builtin/tags/ifchanged_tag.py +33 -33
  40. python_liquid-2.0.1/liquid/builtin/tags/include_tag.py +251 -0
  41. python_liquid-2.0.1/liquid/builtin/tags/increment_tag.py +60 -0
  42. python_liquid-2.0.1/liquid/builtin/tags/inline_comment_tag.py +47 -0
  43. python_liquid-2.0.1/liquid/builtin/tags/liquid_tag.py +182 -0
  44. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/builtin/tags/render_tag.py +136 -143
  45. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/builtin/tags/tablerow_tag.py +57 -54
  46. python_liquid-2.0.1/liquid/builtin/tags/unless_tag.py +218 -0
  47. python_liquid-2.0.1/liquid/context.py +606 -0
  48. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/environment.py +182 -370
  49. python_liquid-2.0.1/liquid/exceptions.py +284 -0
  50. python_liquid-2.0.1/liquid/expression.py +41 -0
  51. python_liquid-2.0.1/liquid/extra/__init__.py +97 -0
  52. python_liquid-2.0.1/liquid/extra/filters/__init__.py +33 -0
  53. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/extra/filters/_json.py +1 -2
  54. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/extra/filters/array.py +3 -4
  55. python_liquid-2.0.1/liquid/extra/filters/babel.py +552 -0
  56. python_liquid-2.0.1/liquid/extra/filters/translate.py +448 -0
  57. python_liquid-2.0.1/liquid/extra/tags/__init__.py +15 -0
  58. python_liquid-2.0.1/liquid/extra/tags/_with.py +83 -0
  59. python_liquid-2.0.1/liquid/extra/tags/extends_tag.py +577 -0
  60. python_liquid-2.0.1/liquid/extra/tags/macro_tag.py +268 -0
  61. python_liquid-2.0.1/liquid/extra/tags/translate_tag.py +388 -0
  62. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/filter.py +24 -18
  63. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/future/environment.py +10 -15
  64. python_liquid-2.0.1/liquid/future/filters/__init__.py +1 -0
  65. python_liquid-2.0.1/liquid/future/tags/__init__.py +1 -0
  66. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/__init__.py +10 -0
  67. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/case.py +3 -3
  68. python_liquid-2.0.1/liquid/golden/comment_tag.py +119 -0
  69. python_liquid-2.0.1/liquid/golden/doc_tag.py +61 -0
  70. python_liquid-2.0.1/liquid/golden/find_filter.py +90 -0
  71. python_liquid-2.0.1/liquid/golden/find_index_filter.py +96 -0
  72. python_liquid-2.0.1/liquid/golden/has_filter.py +139 -0
  73. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/if_tag.py +135 -0
  74. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/output_statement.py +57 -2
  75. python_liquid-2.0.1/liquid/golden/range_objects.py +79 -0
  76. python_liquid-2.0.1/liquid/golden/reject_filter.py +268 -0
  77. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/split_filter.py +31 -0
  78. python_liquid-2.0.1/liquid/lex.py +252 -0
  79. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/limits.py +2 -1
  80. python_liquid-2.0.1/liquid/loader.py +141 -0
  81. python_liquid-2.0.1/liquid/messages.py +357 -0
  82. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/output.py +10 -1
  83. python_liquid-2.0.1/liquid/parser.py +113 -0
  84. python_liquid-2.0.1/liquid/py.typed +0 -0
  85. python_liquid-2.0.1/liquid/span.py +35 -0
  86. python_liquid-2.0.1/liquid/static_analysis.py +364 -0
  87. python_liquid-2.0.1/liquid/stream.py +150 -0
  88. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/tag.py +12 -11
  89. python_liquid-2.0.1/liquid/template.py +603 -0
  90. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/token.py +29 -69
  91. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/undefined.py +78 -18
  92. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/utils/__init__.py +5 -1
  93. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/utils/html.py +2 -4
  94. python_liquid-2.0.1/liquid/utils/lru_cache.py +129 -0
  95. {python_liquid-1.13.0 → python_liquid-2.0.1}/pyproject.toml +28 -36
  96. python_liquid-1.13.0/PKG-INFO +0 -186
  97. python_liquid-1.13.0/README.md +0 -153
  98. python_liquid-1.13.0/liquid/__init__.py +0 -85
  99. python_liquid-1.13.0/liquid/ast.py +0 -239
  100. python_liquid-1.13.0/liquid/builtin/illegal.py +0 -24
  101. python_liquid-1.13.0/liquid/builtin/literal.py +0 -47
  102. python_liquid-1.13.0/liquid/builtin/loaders/__init__.py +0 -133
  103. python_liquid-1.13.0/liquid/builtin/loaders/base_loader.py +0 -302
  104. python_liquid-1.13.0/liquid/builtin/loaders/choice_loader.py +0 -143
  105. python_liquid-1.13.0/liquid/builtin/loaders/mixins.py +0 -240
  106. python_liquid-1.13.0/liquid/builtin/statement.py +0 -65
  107. python_liquid-1.13.0/liquid/builtin/tags/assign_tag.py +0 -91
  108. python_liquid-1.13.0/liquid/builtin/tags/capture_tag.py +0 -108
  109. python_liquid-1.13.0/liquid/builtin/tags/case_tag.py +0 -217
  110. python_liquid-1.13.0/liquid/builtin/tags/comment_tag.py +0 -95
  111. python_liquid-1.13.0/liquid/builtin/tags/cycle_tag.py +0 -141
  112. python_liquid-1.13.0/liquid/builtin/tags/decrement_tag.py +0 -71
  113. python_liquid-1.13.0/liquid/builtin/tags/echo_tag.py +0 -46
  114. python_liquid-1.13.0/liquid/builtin/tags/if_tag.py +0 -260
  115. python_liquid-1.13.0/liquid/builtin/tags/include_tag.py +0 -256
  116. python_liquid-1.13.0/liquid/builtin/tags/increment_tag.py +0 -67
  117. python_liquid-1.13.0/liquid/builtin/tags/inline_comment_tag.py +0 -34
  118. python_liquid-1.13.0/liquid/builtin/tags/liquid_tag.py +0 -92
  119. python_liquid-1.13.0/liquid/builtin/tags/unless_tag.py +0 -254
  120. python_liquid-1.13.0/liquid/context.py +0 -765
  121. python_liquid-1.13.0/liquid/exceptions.py +0 -241
  122. python_liquid-1.13.0/liquid/expression.py +0 -1172
  123. python_liquid-1.13.0/liquid/expressions/__init__.py +0 -29
  124. python_liquid-1.13.0/liquid/expressions/arguments/__init__.py +0 -11
  125. python_liquid-1.13.0/liquid/expressions/arguments/lex.py +0 -105
  126. python_liquid-1.13.0/liquid/expressions/arguments/parse.py +0 -140
  127. python_liquid-1.13.0/liquid/expressions/boolean/__init__.py +0 -11
  128. python_liquid-1.13.0/liquid/expressions/boolean/lex.py +0 -188
  129. python_liquid-1.13.0/liquid/expressions/boolean/parse.py +0 -290
  130. python_liquid-1.13.0/liquid/expressions/common.py +0 -402
  131. python_liquid-1.13.0/liquid/expressions/conditional/__init__.py +0 -11
  132. python_liquid-1.13.0/liquid/expressions/conditional/lex.py +0 -196
  133. python_liquid-1.13.0/liquid/expressions/conditional/parse.py +0 -223
  134. python_liquid-1.13.0/liquid/expressions/filtered/__init__.py +0 -7
  135. python_liquid-1.13.0/liquid/expressions/filtered/lex.py +0 -109
  136. python_liquid-1.13.0/liquid/expressions/filtered/parse.py +0 -263
  137. python_liquid-1.13.0/liquid/expressions/include/__init__.py +0 -3
  138. python_liquid-1.13.0/liquid/expressions/include/lex.py +0 -109
  139. python_liquid-1.13.0/liquid/expressions/loop/__init__.py +0 -7
  140. python_liquid-1.13.0/liquid/expressions/loop/lex.py +0 -105
  141. python_liquid-1.13.0/liquid/expressions/loop/parse.py +0 -138
  142. python_liquid-1.13.0/liquid/expressions/stream.py +0 -106
  143. python_liquid-1.13.0/liquid/extra/__init__.py +0 -110
  144. python_liquid-1.13.0/liquid/extra/filters/__init__.py +0 -13
  145. python_liquid-1.13.0/liquid/extra/tags/__init__.py +0 -27
  146. python_liquid-1.13.0/liquid/extra/tags/_with.py +0 -94
  147. python_liquid-1.13.0/liquid/extra/tags/extends.py +0 -558
  148. python_liquid-1.13.0/liquid/extra/tags/if_expressions.py +0 -85
  149. python_liquid-1.13.0/liquid/extra/tags/if_not.py +0 -24
  150. python_liquid-1.13.0/liquid/extra/tags/macro.py +0 -326
  151. python_liquid-1.13.0/liquid/future/filters/__init__.py +0 -3
  152. python_liquid-1.13.0/liquid/future/filters/_split.py +0 -23
  153. python_liquid-1.13.0/liquid/future/tags/__init__.py +0 -11
  154. python_liquid-1.13.0/liquid/future/tags/_case_tag.py +0 -182
  155. python_liquid-1.13.0/liquid/future/tags/_if_tag.py +0 -8
  156. python_liquid-1.13.0/liquid/future/tags/_tablerow_tag.py +0 -14
  157. python_liquid-1.13.0/liquid/future/tags/_unless_tag.py +0 -8
  158. python_liquid-1.13.0/liquid/golden/comment_tag.py +0 -27
  159. python_liquid-1.13.0/liquid/golden/range_objects.py +0 -36
  160. python_liquid-1.13.0/liquid/lex.py +0 -525
  161. python_liquid-1.13.0/liquid/loaders.py +0 -30
  162. python_liquid-1.13.0/liquid/parse.py +0 -791
  163. python_liquid-1.13.0/liquid/static_analysis.py +0 -904
  164. python_liquid-1.13.0/liquid/stream.py +0 -87
  165. python_liquid-1.13.0/liquid/template.py +0 -453
  166. python_liquid-1.13.0/liquid/utils/cache.py +0 -194
  167. python_liquid-1.13.0/liquid/utils/cache.pyi +0 -13
  168. {python_liquid-1.13.0 → python_liquid-2.0.1}/.gitignore +0 -0
  169. {python_liquid-1.13.0 → python_liquid-2.0.1}/LICENSE +0 -0
  170. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/builtin/drops/__init__.py +0 -0
  171. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/builtin/drops/drops.py +0 -0
  172. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/builtin/filters/__init__.py +0 -0
  173. {python_liquid-1.13.0/liquid/builtin/tags → python_liquid-2.0.1/liquid/builtin/loaders}/__init__.py +0 -0
  174. /python_liquid-1.13.0/liquid/py.typed → /python_liquid-2.0.1/liquid/builtin/tags/__init__.py +0 -0
  175. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/extra/filters/html.py +0 -0
  176. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/future/__init__.py +0 -0
  177. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/abs_filter.py +0 -0
  178. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/append_filter.py +0 -0
  179. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/assign_tag.py +0 -0
  180. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/at_least_filter.py +0 -0
  181. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/at_most_filter.py +0 -0
  182. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/base64_decode_filter.py +0 -0
  183. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/base64_encode_filter.py +0 -0
  184. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/base64_url_safe_decode_filter.py +0 -0
  185. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/base64_url_safe_encode_filter.py +0 -0
  186. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/capitalize_filter.py +0 -0
  187. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/capture_tag.py +0 -0
  188. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/case_tag.py +0 -0
  189. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/ceil_filter.py +0 -0
  190. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/compact_filter.py +0 -0
  191. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/concat_filter.py +0 -0
  192. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/cycle_tag.py +0 -0
  193. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/date_filter.py +0 -0
  194. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/decrement_tag.py +0 -0
  195. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/default_filter.py +0 -0
  196. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/divided_by_filter.py +0 -0
  197. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/downcase_filter.py +0 -0
  198. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/echo_tag.py +0 -0
  199. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/escape_filter.py +0 -0
  200. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/escape_once_filter.py +0 -0
  201. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/first_filter.py +0 -0
  202. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/floor_filter.py +0 -0
  203. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/for_tag.py +0 -0
  204. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/identifiers.py +0 -0
  205. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/ifchanged_tag.py +0 -0
  206. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/illegal.py +0 -0
  207. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/include_tag.py +0 -0
  208. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/increment_tag.py +0 -0
  209. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/inline_comment_tag.py +0 -0
  210. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/join_filter.py +0 -0
  211. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/last_filter.py +0 -0
  212. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/liquid_tag.py +0 -0
  213. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/lstrip_filter.py +0 -0
  214. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/map_filter.py +0 -0
  215. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/minus_filter.py +0 -0
  216. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/modulo_filter.py +0 -0
  217. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/newline_to_br_filter.py +0 -0
  218. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/not_liquid.py +0 -0
  219. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/plus_filter.py +0 -0
  220. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/prepend_filter.py +0 -0
  221. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/raw_tag.py +0 -0
  222. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/remove_filter.py +0 -0
  223. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/remove_first_filter.py +0 -0
  224. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/remove_last_filter.py +0 -0
  225. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/render_tag.py +0 -0
  226. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/replace_filter.py +0 -0
  227. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/replace_first_filter.py +0 -0
  228. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/replace_last_filter.py +0 -0
  229. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/reverse_filter.py +0 -0
  230. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/round_filter.py +0 -0
  231. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/rstrip_filter.py +0 -0
  232. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/size_filter.py +0 -0
  233. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/slice_filter.py +0 -0
  234. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/sort_filter.py +0 -0
  235. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/sort_natural_filter.py +0 -0
  236. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/special.py +0 -0
  237. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/strip_filter.py +0 -0
  238. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/strip_html_filter.py +0 -0
  239. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/strip_newlines_filter.py +0 -0
  240. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/sum_filter.py +0 -0
  241. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/tablerow_tag.py +0 -0
  242. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/times_filter.py +0 -0
  243. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/truncate_filter.py +0 -0
  244. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/truncatewords_filter.py +0 -0
  245. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/uniq_filter.py +0 -0
  246. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/unless_tag.py +0 -0
  247. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/upcase_filter.py +0 -0
  248. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/url_decode_filter.py +0 -0
  249. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/url_encode_filter.py +0 -0
  250. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/where_filter.py +0 -0
  251. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/golden/whitespace_control.py +0 -0
  252. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/mode.py +0 -0
  253. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/stringify.py +0 -0
  254. {python_liquid-1.13.0/liquid → python_liquid-2.0.1/liquid/utils}/chain_map.py +0 -0
  255. {python_liquid-1.13.0 → python_liquid-2.0.1}/liquid/utils/text.py +0 -0
@@ -0,0 +1,165 @@
1
+ Metadata-Version: 2.4
2
+ Name: python-liquid
3
+ Version: 2.0.1
4
+ Summary: A Python engine for the Liquid template language.
5
+ Project-URL: Change Log, https://github.com/jg-rp/liquid/blob/main/CHANGES.md
6
+ Project-URL: Documentation, https://jg-rp.github.io/liquid/
7
+ Project-URL: Homepage, https://jg-rp.github.io/liquid/
8
+ Project-URL: Issue Tracker, https://github.com/jg-rp/liquid/issues
9
+ Project-URL: Source Code, https://github.com/jg-rp/liquid
10
+ Author-email: James Prior <jamesgr.prior@gmail.com>
11
+ License-Expression: MIT
12
+ License-File: LICENSE
13
+ Classifier: Development Status :: 5 - Production/Stable
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.9
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Programming Language :: Python :: Implementation :: CPython
23
+ Classifier: Programming Language :: Python :: Implementation :: PyPy
24
+ Requires-Python: >=3.7
25
+ Requires-Dist: babel>=2
26
+ Requires-Dist: markupsafe>=3
27
+ Requires-Dist: python-dateutil>=2.8.1
28
+ Requires-Dist: pytz
29
+ Description-Content-Type: text/markdown
30
+
31
+ <h1 align="center">Python Liquid</h1>
32
+
33
+ <p align="center">
34
+ Python Liquid is a Python engine for <a href="https://shopify.github.io/liquid/">Liquid</a>, the safe, customer-facing template language.
35
+ <br>
36
+ We follow <a href="https://github.com/Shopify/liquid">Shopify/Liquid</a> closely and test against the <a href="https://github.com/jg-rp/golden-liquid">Golden Liquid</a> test suite.
37
+ </p>
38
+ <p align="center">
39
+ <a href="https://pypi.org/project/python-liquid/">
40
+ <img src="https://img.shields.io/pypi/v/python-liquid.svg?style=flat-square" alt="PyPi - Version">
41
+ </a>
42
+ <a href="https://anaconda.org/conda-forge/python-liquid">
43
+ <img src="https://img.shields.io/conda/vn/conda-forge/python-liquid?style=flat-square" alt="conda-forge">
44
+ </a>
45
+ <a href="https://pypi.org/project/python-liquid/">
46
+ <img src="https://img.shields.io/pypi/pyversions/python-liquid.svg?style=flat-square" alt="Python versions">
47
+ </a>
48
+ <br>
49
+ <a href="https://github.com/jg-rp/liquid/actions/workflows/tests.yaml">
50
+ <img src="https://img.shields.io/github/actions/workflow/status/jg-rp/liquid/tests.yaml?branch=main&label=tests&style=flat-square" alt="Tests">
51
+ </a>
52
+ <a href="https://github.com/jg-rp/liquid/actions/workflows/coverage.yaml">
53
+ <img src="https://img.shields.io/github/actions/workflow/status/jg-rp/liquid/coverage.yaml?branch=main&label=coverage&style=flat-square" alt="Coverage">
54
+ </a>
55
+ <br>
56
+ <a href="https://pypi.org/project/python-liquid/">
57
+ <img alt="PyPI - Downloads" src="https://img.shields.io/pypi/dm/python-liquid?style=flat-square">
58
+ </a>
59
+ <br>
60
+ <a href="https://github.com/jg-rp/liquid/blob/main/LICENSE">
61
+ <img src="https://img.shields.io/pypi/l/python-liquid.svg?style=flat-square" alt="License">
62
+ </a>
63
+ </p>
64
+
65
+ ---
66
+
67
+ **Table of Contents**
68
+
69
+ - [Install](#install)
70
+ - [Links](#links)
71
+ - [Related Projects](#related-projects)
72
+ - [Quick Start](#example)
73
+ - [Contributing](#contributing)
74
+
75
+ ## Install
76
+
77
+ Install Python Liquid using [Pipenv](https://pipenv.pypa.io/en/latest/):
78
+
79
+ ```shell
80
+ $ pipenv install -u python-liquid
81
+ ```
82
+
83
+ Or [pip](https://pip.pypa.io/en/stable/getting-started/):
84
+
85
+ ```shell
86
+ $ pip install python-liquid
87
+ ```
88
+
89
+ Or from [conda-forge](https://anaconda.org/conda-forge/python-liquid):
90
+
91
+ ```shell
92
+ $ conda install -c conda-forge python-liquid
93
+ ```
94
+
95
+ ## Links
96
+
97
+ - Documentation: https://jg-rp.github.io/liquid/
98
+ - Documentation for Python Liquid version 1.x: https://jg-rp.github.io/python-liquid-docs-archive/
99
+ - Change Log: https://github.com/jg-rp/liquid/blob/main/CHANGES.md
100
+ - PyPi: https://pypi.org/project/python-liquid/
101
+ - Source Code: https://github.com/jg-rp/liquid
102
+ - Issue Tracker: https://github.com/jg-rp/liquid/issues
103
+
104
+ ## Related Projects
105
+
106
+ - [Python Liquid2](https://github.com/jg-rp/python-liquid2): A new Python engine for Liquid with [extra features](https://jg-rp.github.io/python-liquid2/migration/#new-features).
107
+ - [LiquidScript](https://github.com/jg-rp/liquidscript): A JavaScript engine for Liquid with a similar high-level API to Python Liquid.
108
+
109
+ ## Quick Start
110
+
111
+ ### `render()`
112
+
113
+ This example renders a template from a string of text with the package-level `render()` function. The template has just one placeholder variable `you`, which we've given the value `"World"`.
114
+
115
+ ```python
116
+ from liquid import render
117
+
118
+ print(render("Hello, {{ you }}!", you="World"))
119
+ # Hello, World!
120
+ ```
121
+
122
+ ### `parse()`
123
+
124
+ Often you'll want to render the same template several times with different variables. We can parse source text without immediately rendering it using the `parse()` function. `parse()` returns a `BoundTemplate` instance with a `render()` method.
125
+
126
+ ```python
127
+ from liquid import parse
128
+
129
+ template = parse("Hello, {{ you }}!")
130
+ print(template.render(you="World")) # Hello, World!
131
+ print(template.render(you="Liquid")) # Hello, Liquid!
132
+ ```
133
+
134
+ ### Configure
135
+
136
+ Both `parse()` and `render()` are convenience functions that use the default Liquid environment. For all but the simplest cases, you'll want to configure an instance of `Environment`, then load and render templates from that.
137
+
138
+ ```python
139
+ from liquid import CachingFileSystemLoader
140
+ from liquid import Environment
141
+
142
+ env = Environment(
143
+ autoescape=True,
144
+ loader=CachingFileSystemLoader("./templates"),
145
+ )
146
+ ```
147
+
148
+ Then, using `env.parse()` or `env.get_template()`, we can create a `BoundTemplate` from a string or read from the file system, respectively.
149
+
150
+ ```python
151
+ # ... continued from above
152
+ template = env.parse("Hello, {{ you }}!")
153
+ print(template.render(you="World")) # Hello, World!
154
+
155
+ # Try to load "./templates/index.html"
156
+ another_template = env.get_template("index.html")
157
+ data = {"some": {"thing": [1, 2, 3]}}
158
+ result = another_template.render(**data)
159
+ ```
160
+
161
+ Unless you happen to have a relative folder called `templates` with a file called `index.html` within it, we would expect a `TemplateNotFoundError` to be raised when running the example above.
162
+
163
+ ## Contributing
164
+
165
+ Please see [Contributing to Python Liquid](https://github.com/jg-rp/liquid/blob/main/contributing.md).
@@ -0,0 +1,135 @@
1
+ <h1 align="center">Python Liquid</h1>
2
+
3
+ <p align="center">
4
+ Python Liquid is a Python engine for <a href="https://shopify.github.io/liquid/">Liquid</a>, the safe, customer-facing template language.
5
+ <br>
6
+ We follow <a href="https://github.com/Shopify/liquid">Shopify/Liquid</a> closely and test against the <a href="https://github.com/jg-rp/golden-liquid">Golden Liquid</a> test suite.
7
+ </p>
8
+ <p align="center">
9
+ <a href="https://pypi.org/project/python-liquid/">
10
+ <img src="https://img.shields.io/pypi/v/python-liquid.svg?style=flat-square" alt="PyPi - Version">
11
+ </a>
12
+ <a href="https://anaconda.org/conda-forge/python-liquid">
13
+ <img src="https://img.shields.io/conda/vn/conda-forge/python-liquid?style=flat-square" alt="conda-forge">
14
+ </a>
15
+ <a href="https://pypi.org/project/python-liquid/">
16
+ <img src="https://img.shields.io/pypi/pyversions/python-liquid.svg?style=flat-square" alt="Python versions">
17
+ </a>
18
+ <br>
19
+ <a href="https://github.com/jg-rp/liquid/actions/workflows/tests.yaml">
20
+ <img src="https://img.shields.io/github/actions/workflow/status/jg-rp/liquid/tests.yaml?branch=main&label=tests&style=flat-square" alt="Tests">
21
+ </a>
22
+ <a href="https://github.com/jg-rp/liquid/actions/workflows/coverage.yaml">
23
+ <img src="https://img.shields.io/github/actions/workflow/status/jg-rp/liquid/coverage.yaml?branch=main&label=coverage&style=flat-square" alt="Coverage">
24
+ </a>
25
+ <br>
26
+ <a href="https://pypi.org/project/python-liquid/">
27
+ <img alt="PyPI - Downloads" src="https://img.shields.io/pypi/dm/python-liquid?style=flat-square">
28
+ </a>
29
+ <br>
30
+ <a href="https://github.com/jg-rp/liquid/blob/main/LICENSE">
31
+ <img src="https://img.shields.io/pypi/l/python-liquid.svg?style=flat-square" alt="License">
32
+ </a>
33
+ </p>
34
+
35
+ ---
36
+
37
+ **Table of Contents**
38
+
39
+ - [Install](#install)
40
+ - [Links](#links)
41
+ - [Related Projects](#related-projects)
42
+ - [Quick Start](#example)
43
+ - [Contributing](#contributing)
44
+
45
+ ## Install
46
+
47
+ Install Python Liquid using [Pipenv](https://pipenv.pypa.io/en/latest/):
48
+
49
+ ```shell
50
+ $ pipenv install -u python-liquid
51
+ ```
52
+
53
+ Or [pip](https://pip.pypa.io/en/stable/getting-started/):
54
+
55
+ ```shell
56
+ $ pip install python-liquid
57
+ ```
58
+
59
+ Or from [conda-forge](https://anaconda.org/conda-forge/python-liquid):
60
+
61
+ ```shell
62
+ $ conda install -c conda-forge python-liquid
63
+ ```
64
+
65
+ ## Links
66
+
67
+ - Documentation: https://jg-rp.github.io/liquid/
68
+ - Documentation for Python Liquid version 1.x: https://jg-rp.github.io/python-liquid-docs-archive/
69
+ - Change Log: https://github.com/jg-rp/liquid/blob/main/CHANGES.md
70
+ - PyPi: https://pypi.org/project/python-liquid/
71
+ - Source Code: https://github.com/jg-rp/liquid
72
+ - Issue Tracker: https://github.com/jg-rp/liquid/issues
73
+
74
+ ## Related Projects
75
+
76
+ - [Python Liquid2](https://github.com/jg-rp/python-liquid2): A new Python engine for Liquid with [extra features](https://jg-rp.github.io/python-liquid2/migration/#new-features).
77
+ - [LiquidScript](https://github.com/jg-rp/liquidscript): A JavaScript engine for Liquid with a similar high-level API to Python Liquid.
78
+
79
+ ## Quick Start
80
+
81
+ ### `render()`
82
+
83
+ This example renders a template from a string of text with the package-level `render()` function. The template has just one placeholder variable `you`, which we've given the value `"World"`.
84
+
85
+ ```python
86
+ from liquid import render
87
+
88
+ print(render("Hello, {{ you }}!", you="World"))
89
+ # Hello, World!
90
+ ```
91
+
92
+ ### `parse()`
93
+
94
+ Often you'll want to render the same template several times with different variables. We can parse source text without immediately rendering it using the `parse()` function. `parse()` returns a `BoundTemplate` instance with a `render()` method.
95
+
96
+ ```python
97
+ from liquid import parse
98
+
99
+ template = parse("Hello, {{ you }}!")
100
+ print(template.render(you="World")) # Hello, World!
101
+ print(template.render(you="Liquid")) # Hello, Liquid!
102
+ ```
103
+
104
+ ### Configure
105
+
106
+ Both `parse()` and `render()` are convenience functions that use the default Liquid environment. For all but the simplest cases, you'll want to configure an instance of `Environment`, then load and render templates from that.
107
+
108
+ ```python
109
+ from liquid import CachingFileSystemLoader
110
+ from liquid import Environment
111
+
112
+ env = Environment(
113
+ autoescape=True,
114
+ loader=CachingFileSystemLoader("./templates"),
115
+ )
116
+ ```
117
+
118
+ Then, using `env.parse()` or `env.get_template()`, we can create a `BoundTemplate` from a string or read from the file system, respectively.
119
+
120
+ ```python
121
+ # ... continued from above
122
+ template = env.parse("Hello, {{ you }}!")
123
+ print(template.render(you="World")) # Hello, World!
124
+
125
+ # Try to load "./templates/index.html"
126
+ another_template = env.get_template("index.html")
127
+ data = {"some": {"thing": [1, 2, 3]}}
128
+ result = another_template.render(**data)
129
+ ```
130
+
131
+ Unless you happen to have a relative folder called `templates` with a file called `index.html` within it, we would expect a `TemplateNotFoundError` to be raised when running the example above.
132
+
133
+ ## Contributing
134
+
135
+ Please see [Contributing to Python Liquid](https://github.com/jg-rp/liquid/blob/main/contributing.md).
@@ -0,0 +1,246 @@
1
+ from pathlib import Path
2
+ from typing import Iterable
3
+ from typing import Iterator
4
+ from typing import Optional
5
+ from typing import TextIO
6
+ from typing import Union
7
+
8
+ from markupsafe import Markup
9
+ from markupsafe import escape
10
+ from markupsafe import soft_str
11
+
12
+ from .mode import Mode
13
+ from .token import Token
14
+ from .expression import Expression
15
+
16
+ from .context import RenderContext
17
+ from .context import FutureContext
18
+ from .undefined import DebugUndefined
19
+ from .undefined import is_undefined
20
+ from .undefined import FalsyStrictUndefined
21
+ from .undefined import StrictDefaultUndefined
22
+ from .undefined import StrictUndefined
23
+ from .undefined import Undefined
24
+
25
+ from .environment import Environment
26
+ from .environment import Template
27
+
28
+ from .template import AwareBoundTemplate
29
+ from .template import BoundTemplate
30
+ from .template import FutureAwareBoundTemplate
31
+ from .template import FutureBoundTemplate
32
+
33
+ from .builtin import CachingDictLoader
34
+ from .builtin import DictLoader
35
+ from .builtin import ChoiceLoader
36
+ from .builtin import CachingChoiceLoader
37
+ from .builtin import CachingFileSystemLoader
38
+ from .builtin import FileSystemLoader
39
+ from .builtin import PackageLoader
40
+ from .builtin import CachingLoaderMixin
41
+ from .loader import BaseLoader
42
+
43
+ from .ast import Node
44
+ from .ast import BlockNode
45
+ from .ast import ConditionalBlockNode
46
+
47
+ from .analyze_tags import TagAnalysis
48
+ from .analyze_tags import DEFAULT_INNER_TAG_MAP
49
+
50
+ from .messages import MessageTuple
51
+ from .messages import Translations
52
+ from .messages import extract_from_template
53
+
54
+ from .stream import TokenStream
55
+ from .tag import Tag
56
+
57
+ from . import future
58
+
59
+ __version__ = "2.0.1"
60
+
61
+ __all__ = (
62
+ "AwareBoundTemplate",
63
+ "BlockNode",
64
+ "BoundTemplate",
65
+ "CachingChoiceLoader",
66
+ "CachingDictLoader",
67
+ "CachingFileSystemLoader",
68
+ "CachingLoaderMixin",
69
+ "ChoiceLoader",
70
+ "ConditionalBlockNode",
71
+ "DebugUndefined",
72
+ "DEFAULT_INNER_TAG_MAP",
73
+ "DictLoader",
74
+ "Environment",
75
+ "escape",
76
+ "Expression",
77
+ "extract_from_template",
78
+ "FalsyStrictUndefined",
79
+ "FileSystemLoader",
80
+ "future",
81
+ "FutureAwareBoundTemplate",
82
+ "FutureBoundTemplate",
83
+ "FutureContext",
84
+ "is_undefined",
85
+ "make_choice_loader",
86
+ "make_file_system_loader",
87
+ "Markup",
88
+ "MessageTuple",
89
+ "Mode",
90
+ "Node",
91
+ "PackageLoader",
92
+ "parse",
93
+ "render_async",
94
+ "render",
95
+ "RenderContext",
96
+ "soft_str",
97
+ "StrictDefaultUndefined",
98
+ "StrictUndefined",
99
+ "Tag",
100
+ "TagAnalysis",
101
+ "Template",
102
+ "Token",
103
+ "TokenStream",
104
+ "Translations",
105
+ "Undefined",
106
+ )
107
+
108
+ DEFAULT_ENVIRONMENT = Environment()
109
+
110
+
111
+ def parse(source: str) -> BoundTemplate:
112
+ """Parse template source text using the default environment."""
113
+ return DEFAULT_ENVIRONMENT.from_string(source)
114
+
115
+
116
+ def render(source: str, **data: object) -> str:
117
+ """Parse and render source text using the default environment."""
118
+ return DEFAULT_ENVIRONMENT.render(source, **data)
119
+
120
+
121
+ async def render_async(source: str, **data: object) -> str:
122
+ """Parse and render source text using the default environment."""
123
+ return await DEFAULT_ENVIRONMENT.render_async(source, **data)
124
+
125
+
126
+ def make_file_system_loader(
127
+ search_path: Union[str, Path, Iterable[Union[str, Path]]],
128
+ *,
129
+ encoding: str = "utf-8",
130
+ ext: str = ".liquid",
131
+ auto_reload: bool = True,
132
+ namespace_key: str = "",
133
+ cache_size: int = 300,
134
+ ) -> BaseLoader:
135
+ """A _file system_ template loader factory.
136
+
137
+ Returns one of `CachingFileSystemLoader` or `FileSystemLoader` depending in
138
+ the given arguments.
139
+
140
+ A `CachingFileSystemLoader` is returned if _cache_size_ is greater than 0.
141
+ Otherwise a `FileExtensionLoader` is returned if _ext_ is not empty.
142
+ If _ext_ is empty, a `FileSystemLoader` is returned.
143
+
144
+ _auto_reload_ and _namespace_key_ are ignored if _cache_key_ is less than 1.
145
+
146
+ Args:
147
+ search_path: One or more paths to search.
148
+ encoding: Open template files with the given encoding.
149
+ ext: A default file extension. Should include a leading period.
150
+ auto_reload: If `True`, automatically reload a cached template if it has been
151
+ updated.
152
+ namespace_key: The name of a global render context variable or loader keyword
153
+ argument that resolves to the current loader "namespace" or "scope".
154
+
155
+ If you're developing a multi-user application, a good namespace might be
156
+ `uid`, where `uid` is a unique identifier for a user and templates are
157
+ arranged in folders named for each `uid` inside the search path.
158
+ cache_size: The maximum number of templates to hold in the cache before removing
159
+ the least recently used template.
160
+
161
+ _New in version 1.12.0_
162
+ """
163
+ if cache_size > 0:
164
+ return CachingFileSystemLoader(
165
+ search_path=search_path,
166
+ encoding=encoding,
167
+ ext=ext,
168
+ auto_reload=auto_reload,
169
+ namespace_key=namespace_key,
170
+ capacity=cache_size,
171
+ )
172
+
173
+ return FileSystemLoader(search_path=search_path, encoding=encoding, ext=ext)
174
+
175
+
176
+ def make_choice_loader(
177
+ loaders: list[BaseLoader],
178
+ *,
179
+ auto_reload: bool = True,
180
+ namespace_key: str = "",
181
+ cache_size: int = 300,
182
+ ) -> BaseLoader:
183
+ """A _choice loader_ factory.
184
+
185
+ Returns one of `CachingChoiceLoader` or `ChoiceLoader` depending on the
186
+ given arguments.
187
+
188
+ A `CachingChoiceLoader` is returned if _cache_size_ > 0, otherwise a
189
+ `ChoiceLoader` is returned.
190
+
191
+ _auto_reload_ and _namespace_key_ are ignored if _cache_key_ is less than 1.
192
+
193
+ Args:
194
+ loaders: A list of loaders implementing `liquid.loaders.BaseLoader`.
195
+ auto_reload: If `True`, automatically reload a cached template if it
196
+ has been updated.
197
+ namespace_key: The name of a global render context variable or loader
198
+ keyword argument that resolves to the current loader "namespace" or
199
+ "scope".
200
+ cache_size: The maximum number of templates to hold in the cache before
201
+ removing the least recently used template.
202
+
203
+ _New in version 1.12.0_
204
+ """
205
+ if cache_size > 0:
206
+ return CachingChoiceLoader(
207
+ loaders=loaders,
208
+ auto_reload=auto_reload,
209
+ namespace_key=namespace_key,
210
+ capacity=cache_size,
211
+ )
212
+
213
+ return ChoiceLoader(loaders=loaders)
214
+
215
+
216
+ def extract_liquid(
217
+ fileobj: TextIO,
218
+ keywords: list[str],
219
+ comment_tags: Optional[list[str]] = None,
220
+ options: Optional[dict[object, object]] = None, # noqa: ARG001
221
+ ) -> Iterator[MessageTuple]:
222
+ """A babel compatible translation message extraction method for Liquid templates.
223
+
224
+ See https://babel.pocoo.org/en/latest/messages.html
225
+
226
+ Keywords are the names of Liquid filters or tags operating on translatable
227
+ strings. For a filter to contribute to message extraction, it must also
228
+ appear as a child of a `FilteredExpression` and be a `TranslatableFilter`.
229
+ Similarly, tags must produce a node that is a `TranslatableTag`.
230
+
231
+ Where a Liquid comment contains a prefix in `comment_tags`, the comment
232
+ will be attached to the translatable filter or tag immediately following
233
+ the comment. Python Liquid's non-standard shorthand comments are not
234
+ supported.
235
+
236
+ Options are arguments passed to the `liquid.Template` constructor with the
237
+ contents of `fileobj` as the template's source. Use `extract_from_template`
238
+ to extract messages from an existing template bound to an existing
239
+ environment.
240
+ """
241
+ template = Environment(extra=True).parse(fileobj.read())
242
+ return extract_from_template(
243
+ template=template,
244
+ keywords=keywords,
245
+ comment_tags=comment_tags,
246
+ )
@@ -1,20 +1,20 @@
1
1
  """Analyze template tags from tokenized source text."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  from collections import defaultdict
5
6
  from typing import TYPE_CHECKING
6
- from typing import Dict
7
+ from typing import DefaultDict
7
8
  from typing import Iterable
8
- from typing import List
9
9
  from typing import Mapping
10
10
  from typing import Optional
11
- from typing import Tuple
12
11
 
13
- from liquid.token import TOKEN_TAG
12
+ from .span import Span
13
+ from .token import TOKEN_TAG
14
14
 
15
15
  if TYPE_CHECKING:
16
- from liquid import Environment
17
- from liquid.token import Token
16
+ from .environment import Environment
17
+ from .token import Token
18
18
 
19
19
 
20
20
  DEFAULT_INNER_TAG_MAP = {
@@ -24,15 +24,16 @@ DEFAULT_INNER_TAG_MAP = {
24
24
  "unless": ["else", "elsif"],
25
25
  }
26
26
 
27
+
27
28
  InnerTagMap = Mapping[str, Iterable[str]]
28
- TagMap = Dict[str, List[Tuple[str, int]]]
29
+ TagMap = dict[str, list[Span]]
29
30
 
30
31
 
31
32
  class TagAnalysis:
32
33
  """The result of analyzing a template's tags with `Environment.analyze_tags()`.
33
34
 
34
35
  Each of the following properties maps tag names to a list of their locations.
35
- Locations are (template_name, line_number) tuples.
36
+ Locations are (template_name, start_index) tuples.
36
37
 
37
38
  Note that `raw` tags are not included at all. The lexer converts them to text
38
39
  tokens before we get a chance to analyze them.
@@ -58,7 +59,7 @@ class TagAnalysis:
58
59
  *,
59
60
  env: Environment,
60
61
  name: str,
61
- tokens: List[Token],
62
+ tokens: list[Token],
62
63
  inner_tags: Optional[InnerTagMap] = None,
63
64
  ) -> None:
64
65
  self.template_name = name
@@ -86,20 +87,20 @@ class TagAnalysis:
86
87
  self.unknown_tags,
87
88
  ) = self._audit_tags(env, tokens)
88
89
 
89
- def _all_tags(self, tokens: List[Token]) -> TagMap:
90
+ def _all_tags(self, tokens: list[Token]) -> TagMap:
90
91
  """Map tag names to their locations, similar to `Template.analyze` etc."""
91
- tags = defaultdict(list)
92
+ tags: DefaultDict[str, list[Span]] = defaultdict(list)
92
93
  for token in tokens:
93
- if token.type == TOKEN_TAG:
94
- tags[token.value].append((self.template_name, token.linenum))
94
+ if token.kind == TOKEN_TAG:
95
+ tags[token.value].append(Span(self.template_name, token.start_index))
95
96
  return dict(tags)
96
97
 
97
98
  def _audit_tags( # noqa: PLR0912
98
99
  self,
99
100
  env: Environment,
100
- tokens: List[Token],
101
- ) -> Tuple[TagMap, TagMap, TagMap]:
102
- block_stack: List[_BlockStackItem] = []
101
+ tokens: list[Token],
102
+ ) -> tuple[TagMap, TagMap, TagMap]:
103
+ block_stack: list[_BlockStackItem] = []
103
104
  unclosed_tags: TagMap = defaultdict(list)
104
105
  unexpected_tags: TagMap = defaultdict(list)
105
106
  unknown_tags: TagMap = defaultdict(list)
@@ -108,7 +109,7 @@ class TagAnalysis:
108
109
  end_tags = {
109
110
  token.value
110
111
  for token in tokens
111
- if token.type == TOKEN_TAG and token.value.startswith("end")
112
+ if token.kind == TOKEN_TAG and token.value.startswith("end")
112
113
  }
113
114
 
114
115
  # Infer which tags are block tags. This may or may not match what the
@@ -131,7 +132,7 @@ class TagAnalysis:
131
132
  }
132
133
 
133
134
  for token in tokens:
134
- if token.type != TOKEN_TAG:
135
+ if token.kind != TOKEN_TAG:
135
136
  continue
136
137
 
137
138
  tag_name = token.value
@@ -143,7 +144,7 @@ class TagAnalysis:
143
144
  if start_block_tag != tag_name[3:]:
144
145
  # if start_block_tag.name not in inline_tags:
145
146
  unclosed_tags[start_block_tag.name].append(
146
- (self.template_name, start_block_tag.token.linenum)
147
+ Span(self.template_name, start_block_tag.token.start_index)
147
148
  )
148
149
  continue
149
150
 
@@ -152,18 +153,22 @@ class TagAnalysis:
152
153
  enclosing_tags: Iterable[str] = self._inner_tags.get(tag_name, [])
153
154
  if not enclosing_tags:
154
155
  # Not an inner tag for any block.
155
- unknown_tags[tag_name].append((self.template_name, token.linenum))
156
+ unknown_tags[tag_name].append(
157
+ Span(self.template_name, token.start_index)
158
+ )
156
159
  elif not self._valid_inner_tag(
157
160
  self._inner_tags.get(tag_name, []), block_stack
158
161
  ):
159
162
  # An inner tag, but not valid for any blocks currently on the stack.
160
163
  unexpected_tags[tag_name].append(
161
- (self.template_name, token.linenum)
164
+ Span(self.template_name, token.start_index)
162
165
  )
163
166
 
164
167
  # Catch any unclosed tags.
165
168
  for block in block_stack:
166
- unclosed_tags[block.name].append((self.template_name, block.token.linenum))
169
+ unclosed_tags[block.name].append(
170
+ Span(self.template_name, block.token.start_index)
171
+ )
167
172
 
168
173
  # Catch bad "end" tags.
169
174
  for tag_name, locations in self.all_tags.items():
@@ -184,7 +189,7 @@ class TagAnalysis:
184
189
  def _valid_inner_tag(
185
190
  self,
186
191
  tag_names: Iterable[str],
187
- block_stack: List[_BlockStackItem],
192
+ block_stack: list[_BlockStackItem],
188
193
  ) -> bool:
189
194
  return any(tag_name in block_stack for tag_name in tag_names)
190
195