python-liquid 1.12.2__tar.gz → 1.13.0__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 (192) hide show
  1. {python_liquid-1.12.2 → python_liquid-1.13.0}/PKG-INFO +8 -2
  2. {python_liquid-1.12.2 → python_liquid-1.13.0}/README.md +7 -1
  3. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/__init__.py +1 -1
  4. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/tags/case_tag.py +5 -2
  5. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/environment.py +72 -18
  6. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/expressions/boolean/parse.py +15 -4
  7. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/expressions/common.py +29 -6
  8. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/expressions/conditional/parse.py +26 -11
  9. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/expressions/filtered/parse.py +29 -12
  10. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/expressions/loop/parse.py +5 -2
  11. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/expressions/stream.py +3 -1
  12. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/extra/tags/if_not.py +1 -2
  13. {python_liquid-1.12.2 → python_liquid-1.13.0}/pyproject.toml +1 -0
  14. {python_liquid-1.12.2 → python_liquid-1.13.0}/.gitignore +0 -0
  15. {python_liquid-1.12.2 → python_liquid-1.13.0}/LICENSE +0 -0
  16. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/analyze_tags.py +0 -0
  17. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/ast.py +0 -0
  18. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/__init__.py +0 -0
  19. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/drops/__init__.py +0 -0
  20. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/drops/drops.py +0 -0
  21. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/filters/__init__.py +0 -0
  22. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/filters/array.py +0 -0
  23. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/filters/extra.py +0 -0
  24. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/filters/math.py +0 -0
  25. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/filters/misc.py +0 -0
  26. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/filters/string.py +0 -0
  27. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/illegal.py +0 -0
  28. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/literal.py +0 -0
  29. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/loaders/__init__.py +0 -0
  30. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/loaders/base_loader.py +0 -0
  31. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/loaders/caching_file_system_loader.py +0 -0
  32. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/loaders/choice_loader.py +0 -0
  33. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/loaders/file_system_loader.py +0 -0
  34. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/loaders/mixins.py +0 -0
  35. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/loaders/package_loader.py +0 -0
  36. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/statement.py +0 -0
  37. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/tags/__init__.py +0 -0
  38. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/tags/assign_tag.py +0 -0
  39. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/tags/capture_tag.py +0 -0
  40. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/tags/comment_tag.py +0 -0
  41. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/tags/cycle_tag.py +0 -0
  42. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/tags/decrement_tag.py +0 -0
  43. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/tags/echo_tag.py +0 -0
  44. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/tags/for_tag.py +0 -0
  45. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/tags/if_tag.py +0 -0
  46. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/tags/ifchanged_tag.py +0 -0
  47. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/tags/include_tag.py +0 -0
  48. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/tags/increment_tag.py +0 -0
  49. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/tags/inline_comment_tag.py +0 -0
  50. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/tags/liquid_tag.py +0 -0
  51. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/tags/render_tag.py +0 -0
  52. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/tags/tablerow_tag.py +0 -0
  53. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/tags/unless_tag.py +0 -0
  54. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/chain_map.py +0 -0
  55. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/context.py +0 -0
  56. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/exceptions.py +0 -0
  57. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/expression.py +0 -0
  58. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/expressions/__init__.py +0 -0
  59. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/expressions/arguments/__init__.py +0 -0
  60. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/expressions/arguments/lex.py +0 -0
  61. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/expressions/arguments/parse.py +0 -0
  62. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/expressions/boolean/__init__.py +0 -0
  63. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/expressions/boolean/lex.py +0 -0
  64. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/expressions/conditional/__init__.py +0 -0
  65. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/expressions/conditional/lex.py +0 -0
  66. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/expressions/filtered/__init__.py +0 -0
  67. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/expressions/filtered/lex.py +0 -0
  68. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/expressions/include/__init__.py +0 -0
  69. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/expressions/include/lex.py +0 -0
  70. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/expressions/loop/__init__.py +0 -0
  71. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/expressions/loop/lex.py +0 -0
  72. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/extra/__init__.py +0 -0
  73. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/extra/filters/__init__.py +0 -0
  74. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/extra/filters/_json.py +0 -0
  75. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/extra/filters/array.py +0 -0
  76. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/extra/filters/html.py +0 -0
  77. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/extra/tags/__init__.py +0 -0
  78. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/extra/tags/_with.py +0 -0
  79. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/extra/tags/extends.py +0 -0
  80. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/extra/tags/if_expressions.py +0 -0
  81. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/extra/tags/macro.py +0 -0
  82. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/filter.py +0 -0
  83. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/future/__init__.py +0 -0
  84. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/future/environment.py +0 -0
  85. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/future/filters/__init__.py +0 -0
  86. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/future/filters/_split.py +0 -0
  87. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/future/tags/__init__.py +0 -0
  88. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/future/tags/_case_tag.py +0 -0
  89. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/future/tags/_if_tag.py +0 -0
  90. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/future/tags/_tablerow_tag.py +0 -0
  91. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/future/tags/_unless_tag.py +0 -0
  92. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/__init__.py +0 -0
  93. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/abs_filter.py +0 -0
  94. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/append_filter.py +0 -0
  95. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/assign_tag.py +0 -0
  96. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/at_least_filter.py +0 -0
  97. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/at_most_filter.py +0 -0
  98. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/base64_decode_filter.py +0 -0
  99. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/base64_encode_filter.py +0 -0
  100. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/base64_url_safe_decode_filter.py +0 -0
  101. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/base64_url_safe_encode_filter.py +0 -0
  102. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/capitalize_filter.py +0 -0
  103. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/capture_tag.py +0 -0
  104. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/case.py +0 -0
  105. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/case_tag.py +0 -0
  106. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/ceil_filter.py +0 -0
  107. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/comment_tag.py +0 -0
  108. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/compact_filter.py +0 -0
  109. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/concat_filter.py +0 -0
  110. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/cycle_tag.py +0 -0
  111. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/date_filter.py +0 -0
  112. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/decrement_tag.py +0 -0
  113. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/default_filter.py +0 -0
  114. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/divided_by_filter.py +0 -0
  115. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/downcase_filter.py +0 -0
  116. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/echo_tag.py +0 -0
  117. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/escape_filter.py +0 -0
  118. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/escape_once_filter.py +0 -0
  119. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/first_filter.py +0 -0
  120. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/floor_filter.py +0 -0
  121. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/for_tag.py +0 -0
  122. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/identifiers.py +0 -0
  123. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/if_tag.py +0 -0
  124. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/ifchanged_tag.py +0 -0
  125. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/illegal.py +0 -0
  126. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/include_tag.py +0 -0
  127. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/increment_tag.py +0 -0
  128. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/inline_comment_tag.py +0 -0
  129. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/join_filter.py +0 -0
  130. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/last_filter.py +0 -0
  131. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/liquid_tag.py +0 -0
  132. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/lstrip_filter.py +0 -0
  133. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/map_filter.py +0 -0
  134. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/minus_filter.py +0 -0
  135. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/modulo_filter.py +0 -0
  136. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/newline_to_br_filter.py +0 -0
  137. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/not_liquid.py +0 -0
  138. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/output_statement.py +0 -0
  139. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/plus_filter.py +0 -0
  140. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/prepend_filter.py +0 -0
  141. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/range_objects.py +0 -0
  142. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/raw_tag.py +0 -0
  143. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/remove_filter.py +0 -0
  144. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/remove_first_filter.py +0 -0
  145. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/remove_last_filter.py +0 -0
  146. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/render_tag.py +0 -0
  147. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/replace_filter.py +0 -0
  148. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/replace_first_filter.py +0 -0
  149. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/replace_last_filter.py +0 -0
  150. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/reverse_filter.py +0 -0
  151. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/round_filter.py +0 -0
  152. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/rstrip_filter.py +0 -0
  153. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/size_filter.py +0 -0
  154. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/slice_filter.py +0 -0
  155. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/sort_filter.py +0 -0
  156. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/sort_natural_filter.py +0 -0
  157. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/special.py +0 -0
  158. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/split_filter.py +0 -0
  159. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/strip_filter.py +0 -0
  160. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/strip_html_filter.py +0 -0
  161. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/strip_newlines_filter.py +0 -0
  162. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/sum_filter.py +0 -0
  163. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/tablerow_tag.py +0 -0
  164. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/times_filter.py +0 -0
  165. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/truncate_filter.py +0 -0
  166. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/truncatewords_filter.py +0 -0
  167. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/uniq_filter.py +0 -0
  168. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/unless_tag.py +0 -0
  169. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/upcase_filter.py +0 -0
  170. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/url_decode_filter.py +0 -0
  171. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/url_encode_filter.py +0 -0
  172. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/where_filter.py +0 -0
  173. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/whitespace_control.py +0 -0
  174. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/lex.py +0 -0
  175. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/limits.py +0 -0
  176. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/loaders.py +0 -0
  177. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/mode.py +0 -0
  178. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/output.py +0 -0
  179. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/parse.py +0 -0
  180. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/py.typed +0 -0
  181. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/static_analysis.py +0 -0
  182. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/stream.py +0 -0
  183. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/stringify.py +0 -0
  184. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/tag.py +0 -0
  185. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/template.py +0 -0
  186. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/token.py +0 -0
  187. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/undefined.py +0 -0
  188. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/utils/__init__.py +0 -0
  189. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/utils/cache.py +0 -0
  190. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/utils/cache.pyi +0 -0
  191. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/utils/html.py +0 -0
  192. {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/utils/text.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-liquid
3
- Version: 1.12.2
3
+ Version: 1.13.0
4
4
  Summary: A Python engine for the Liquid template language.
5
5
  Project-URL: Change Log, https://github.com/jg-rp/liquid/blob/main/CHANGES.md
6
6
  Project-URL: Documentation, https://jg-rp.github.io/liquid/
@@ -31,6 +31,11 @@ Provides-Extra: autoescape
31
31
  Requires-Dist: markupsafe<3,>=2; extra == 'autoescape'
32
32
  Description-Content-Type: text/markdown
33
33
 
34
+ > [!IMPORTANT]
35
+ > 🎉 Announcing the release of [Python Liquid2](https://github.com/jg-rp/python-liquid2) 🎉 See the [migration guide](https://jg-rp.github.io/python-liquid2/migration/) and the list of [new features](https://jg-rp.github.io/python-liquid2/migration/#new-features).
36
+
37
+ ---
38
+
34
39
  <h1 align="center">Python Liquid</h1>
35
40
 
36
41
  <p align="center">
@@ -120,7 +125,8 @@ print(template.render(you="Liquid")) # "Hello, Liquid!"
120
125
 
121
126
  ## Related Projects
122
127
 
123
- - [liquid-babel](https://github.com/jg-rp/liquid-babel) Internationalization and localization for Liquid templates.
128
+ - [Python Liquid2](https://github.com/jg-rp/python-liquid2): A new Python pakage for Liquid, with extra features.
129
+ - [liquid-babel](https://github.com/jg-rp/liquid-babel): Internationalization and localization for Liquid templates.
124
130
  - [LiquidScript](https://github.com/jg-rp/liquidscript): A JavaScript and TypeScript engine for Liquid with a similar high-level API to Python Liquid.
125
131
  - [django-liquid](https://github.com/jg-rp/django-liquid): A Django template backend for Liquid. Render Liquid templates in your Django apps.
126
132
  - [Flask-Liquid](https://github.com/jg-rp/Flask-Liquid): A Flask extension for Liquid. Render Liquid templates in your Flask applications.
@@ -1,3 +1,8 @@
1
+ > [!IMPORTANT]
2
+ > 🎉 Announcing the release of [Python Liquid2](https://github.com/jg-rp/python-liquid2) 🎉 See the [migration guide](https://jg-rp.github.io/python-liquid2/migration/) and the list of [new features](https://jg-rp.github.io/python-liquid2/migration/#new-features).
3
+
4
+ ---
5
+
1
6
  <h1 align="center">Python Liquid</h1>
2
7
 
3
8
  <p align="center">
@@ -87,7 +92,8 @@ print(template.render(you="Liquid")) # "Hello, Liquid!"
87
92
 
88
93
  ## Related Projects
89
94
 
90
- - [liquid-babel](https://github.com/jg-rp/liquid-babel) Internationalization and localization for Liquid templates.
95
+ - [Python Liquid2](https://github.com/jg-rp/python-liquid2): A new Python pakage for Liquid, with extra features.
96
+ - [liquid-babel](https://github.com/jg-rp/liquid-babel): Internationalization and localization for Liquid templates.
91
97
  - [LiquidScript](https://github.com/jg-rp/liquidscript): A JavaScript and TypeScript engine for Liquid with a similar high-level API to Python Liquid.
92
98
  - [django-liquid](https://github.com/jg-rp/django-liquid): A Django template backend for Liquid. Render Liquid templates in your Django apps.
93
99
  - [Flask-Liquid](https://github.com/jg-rp/Flask-Liquid): A Flask extension for Liquid. Render Liquid templates in your Flask applications.
@@ -46,7 +46,7 @@ from .static_analysis import ContextualTemplateAnalysis
46
46
 
47
47
  from . import future
48
48
 
49
- __version__ = "1.12.2"
49
+ __version__ = "1.13.0"
50
50
 
51
51
  __all__ = (
52
52
  "AwareBoundTemplate",
@@ -1,4 +1,5 @@
1
1
  """Tag and node definition for the built-in "case" tag."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  import sys
@@ -193,14 +194,16 @@ class CaseTag(Tag):
193
194
 
194
195
  def _parse_case_expression(self, expr: str, linenum: int) -> Expression:
195
196
  stream = ExpressionTokenStream(
196
- tokenize_common_expression(expr, linenum=linenum)
197
+ tokenize_common_expression(expr, linenum=linenum),
198
+ shorthand_indexes=self.env.shorthand_indexes,
197
199
  )
198
200
  return parse_common_expression(stream)
199
201
 
200
202
  def _parse_when_expression(self, expr: str, linenum: int) -> List[Expression]:
201
203
  expressions = []
202
204
  stream = ExpressionTokenStream(
203
- tokenize_common_expression(expr, linenum=linenum)
205
+ tokenize_common_expression(expr, linenum=linenum),
206
+ shorthand_indexes=self.env.shorthand_indexes,
204
207
  )
205
208
 
206
209
  while True:
@@ -1,8 +1,10 @@
1
1
  """Shared configuration from which templates can be loaded and parsed."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  import warnings
5
6
  from functools import lru_cache
7
+ from functools import partial
6
8
  from typing import TYPE_CHECKING
7
9
  from typing import Any
8
10
  from typing import Callable
@@ -154,6 +156,10 @@ class Environment:
154
156
  # Whether to output blocks that only contain only whitespace when rendered.
155
157
  render_whitespace_only_blocks: bool = False
156
158
 
159
+ # When `True`, accept indexes without enclosing square brackets in paths to
160
+ # variables. Defaults to `False`.
161
+ shorthand_indexes: bool = False
162
+
157
163
  def __init__(
158
164
  self,
159
165
  tag_start_string: str = r"{%",
@@ -578,29 +584,77 @@ class Environment:
578
584
  def _get_expression_parsers(
579
585
  self, cache_size: int = 0
580
586
  ) -> Tuple[
581
- Callable[[str, int], "BooleanExpression"],
582
- Callable[[str, int], "BooleanExpression"],
583
- Callable[[str, int], "FilteredExpression"],
584
- Callable[[str, int], "FilteredExpression"],
585
- Callable[[str, int], "FilteredExpression"],
586
- Callable[[str, int], "LoopExpression"],
587
+ Callable[[str, int], BooleanExpression],
588
+ Callable[[str, int], BooleanExpression],
589
+ Callable[[str, int], FilteredExpression],
590
+ Callable[[str, int], FilteredExpression],
591
+ Callable[[str, int], FilteredExpression],
592
+ Callable[[str, int], LoopExpression],
587
593
  ]:
588
594
  if cache_size >= 1:
589
595
  return (
590
- lru_cache(maxsize=cache_size)(parse_boolean_expression),
591
- lru_cache(maxsize=cache_size)(parse_boolean_expression_with_parens),
592
- lru_cache(maxsize=cache_size)(parse_conditional_expression),
593
- lru_cache(maxsize=cache_size)(parse_conditional_expression_with_parens),
594
- lru_cache(maxsize=cache_size)(parse_filtered_expression),
595
- lru_cache(maxsize=cache_size)(parse_loop_expression),
596
+ lru_cache(maxsize=cache_size)(
597
+ partial(
598
+ parse_boolean_expression,
599
+ shorthand_indexes=self.shorthand_indexes,
600
+ )
601
+ ),
602
+ lru_cache(maxsize=cache_size)(
603
+ partial(
604
+ parse_boolean_expression_with_parens,
605
+ shorthand_indexes=self.shorthand_indexes,
606
+ )
607
+ ),
608
+ lru_cache(maxsize=cache_size)(
609
+ partial(
610
+ parse_conditional_expression,
611
+ shorthand_indexes=self.shorthand_indexes,
612
+ )
613
+ ),
614
+ lru_cache(maxsize=cache_size)(
615
+ partial(
616
+ parse_conditional_expression_with_parens,
617
+ shorthand_indexes=self.shorthand_indexes,
618
+ )
619
+ ),
620
+ lru_cache(maxsize=cache_size)(
621
+ partial(
622
+ parse_filtered_expression,
623
+ shorthand_indexes=self.shorthand_indexes,
624
+ )
625
+ ),
626
+ lru_cache(maxsize=cache_size)(
627
+ partial(
628
+ parse_loop_expression,
629
+ shorthand_indexes=self.shorthand_indexes,
630
+ )
631
+ ),
596
632
  )
597
633
  return (
598
- parse_boolean_expression,
599
- parse_boolean_expression_with_parens,
600
- parse_conditional_expression,
601
- parse_conditional_expression_with_parens,
602
- parse_filtered_expression,
603
- parse_loop_expression,
634
+ partial(
635
+ parse_boolean_expression,
636
+ shorthand_indexes=self.shorthand_indexes,
637
+ ),
638
+ partial(
639
+ parse_boolean_expression_with_parens,
640
+ shorthand_indexes=self.shorthand_indexes,
641
+ ),
642
+ partial(
643
+ parse_conditional_expression,
644
+ shorthand_indexes=self.shorthand_indexes,
645
+ ),
646
+ partial(
647
+ parse_conditional_expression_with_parens,
648
+ shorthand_indexes=self.shorthand_indexes,
649
+ ),
650
+ partial(
651
+ parse_filtered_expression,
652
+ shorthand_indexes=self.shorthand_indexes,
653
+ ),
654
+ partial(
655
+ parse_loop_expression,
656
+ shorthand_indexes=self.shorthand_indexes,
657
+ ),
604
658
  )
605
659
 
606
660
 
@@ -1,4 +1,5 @@
1
1
  """Functions for parsing boolean expressions."""
2
+
2
3
  from typing import Callable
3
4
  from typing import Dict
4
5
 
@@ -188,9 +189,15 @@ parse_range = make_parse_range(parse_simple_obj)
188
189
  TOKEN_MAP[TOKEN_LPAREN] = parse_range
189
190
 
190
191
 
191
- def parse(expr: str, linenum: int = 1) -> BooleanExpression:
192
+ def parse(
193
+ expr: str, linenum: int = 1, *, shorthand_indexes: bool = False
194
+ ) -> BooleanExpression:
192
195
  """Parse a string as a "standard" boolean expression."""
193
- return BooleanExpression(parse_obj(TokenStream(tokenize(expr, linenum))))
196
+ return BooleanExpression(
197
+ parse_obj(
198
+ TokenStream(tokenize(expr, linenum), shorthand_indexes=shorthand_indexes)
199
+ )
200
+ )
194
201
 
195
202
 
196
203
  def parse_grouped_expression(stream: TokenStream) -> Expression:
@@ -261,13 +268,17 @@ def parse_obj_with_parens(
261
268
  return left
262
269
 
263
270
 
264
- def parse_with_parens(expr: str, linenum: int = 1) -> BooleanExpression:
271
+ def parse_with_parens(
272
+ expr: str, linenum: int = 1, *, shorthand_indexes: bool = False
273
+ ) -> BooleanExpression:
265
274
  """Parse a string as a boolean expression.
266
275
 
267
276
  This function handles expressions containing the logical `not` operator and
268
277
  parentheses for grouping terms.
269
278
  """
270
- stream = TokenStream(tokenize_with_parens(expr, linenum))
279
+ stream = TokenStream(
280
+ tokenize_with_parens(expr, linenum), shorthand_indexes=shorthand_indexes
281
+ )
271
282
  rv = BooleanExpression(parse_obj_with_parens(stream))
272
283
  peek_typ = stream.peek[1]
273
284
  if peek_typ == TOKEN_RPAREN:
@@ -1,4 +1,5 @@
1
1
  """Patterns and parse functions common to multiple built-in expression types."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  import re
@@ -145,10 +146,17 @@ def parse_identifier(stream: "TokenStream") -> Identifier:
145
146
  stream.next_token()
146
147
  stream.expect(TOKEN_RBRACKET)
147
148
  elif typ == TOKEN_FLOAT:
148
- raise LiquidSyntaxError(
149
- f"expected an identifier, found {val!r}",
150
- linenum=pos,
151
- )
149
+ if stream.shorthand_indexes:
150
+ path.extend(
151
+ IdentifierPathElement(to_int(i)) for i in val.rstrip(".").split(".")
152
+ )
153
+ else:
154
+ raise LiquidSyntaxError(
155
+ f"expected an identifier, found {val!r}",
156
+ linenum=pos,
157
+ )
158
+ elif typ == TOKEN_INTEGER and stream.shorthand_indexes:
159
+ path.append(IdentifierPathElement(to_int(val)))
152
160
  elif typ == TOKEN_DOT:
153
161
  pass
154
162
  else:
@@ -194,7 +202,7 @@ def parse_unchained_identifier(stream: "TokenStream") -> Identifier:
194
202
 
195
203
 
196
204
  def make_parse_range(
197
- parse_obj: Callable[["TokenStream"], Expression]
205
+ parse_obj: Callable[["TokenStream"], Expression],
198
206
  ) -> Callable[["TokenStream"], RangeLiteral]:
199
207
  """Return a function that parses range expressions using _parse_obj_."""
200
208
 
@@ -246,6 +254,8 @@ _IDENT_TOKENS = frozenset(
246
254
  TOKEN_IDENTINDEX,
247
255
  TOKEN_DOT,
248
256
  TOKEN_LBRACKET,
257
+ TOKEN_INTEGER,
258
+ TOKEN_FLOAT,
249
259
  )
250
260
  )
251
261
 
@@ -259,7 +269,7 @@ def _parse_common_identifier(stream: "TokenStream") -> Identifier:
259
269
  path: IdentifierPath = []
260
270
 
261
271
  while True:
262
- _, _type, value = stream.current
272
+ pos, _type, value = stream.current
263
273
  if _type == TOKEN_IDENTIFIER:
264
274
  path.append(IdentifierPathElement(value))
265
275
  elif _type == TOKEN_IDENTINDEX:
@@ -269,6 +279,19 @@ def _parse_common_identifier(stream: "TokenStream") -> Identifier:
269
279
  path.append(_parse_common_identifier(stream))
270
280
  stream.next_token()
271
281
  stream.expect(TOKEN_RBRACKET)
282
+ elif _type == TOKEN_FLOAT:
283
+ if stream.shorthand_indexes:
284
+ path.extend(
285
+ IdentifierPathElement(to_int(i))
286
+ for i in value.rstrip(".").split(".")
287
+ )
288
+ else:
289
+ raise LiquidSyntaxError(
290
+ f"expected an identifier, found {value!r}",
291
+ linenum=pos,
292
+ )
293
+ elif _type == TOKEN_INTEGER and stream.shorthand_indexes:
294
+ path.append(IdentifierPathElement(to_int(value)))
272
295
  elif _type == TOKEN_DOT:
273
296
  pass
274
297
 
@@ -1,4 +1,5 @@
1
1
  """Functions for parsing non-standard conditional expressions."""
2
+
2
3
  from functools import partial
3
4
  from typing import Dict
4
5
  from typing import Iterable
@@ -65,13 +66,15 @@ split_at_first_if = partial(_split_at_first, _type=TOKEN_IF)
65
66
  split_at_first_else = partial(_split_at_first, _type=TOKEN_ELSE)
66
67
 
67
68
 
68
- def _parse_filter(tokens: List[Token], linenum: int) -> Filter:
69
+ def _parse_filter(
70
+ tokens: List[Token], linenum: int, *, shorthand_indexes: bool = False
71
+ ) -> Filter:
69
72
  if not tokens:
70
73
  raise LiquidSyntaxError(
71
74
  "unexpected pipe or missing filter name", linenum=linenum
72
75
  )
73
76
 
74
- stream = TokenStream(iter(tokens))
77
+ stream = TokenStream(iter(tokens), shorthand_indexes=shorthand_indexes)
75
78
  stream.expect(TOKEN_IDENTIFIER)
76
79
  name = stream.current[2]
77
80
 
@@ -108,13 +111,17 @@ def _parse_filter(tokens: List[Token], linenum: int) -> Filter:
108
111
  return Filter(name, args, kwargs)
109
112
 
110
113
 
111
- def parse(expr: str, linenum: int = 1) -> FilteredExpression:
114
+ def parse(
115
+ expr: str, linenum: int = 1, *, shorthand_indexes: bool = False
116
+ ) -> FilteredExpression:
112
117
  """Parse a conditional expression string."""
113
118
  tokens = tokenize(expr, linenum)
114
119
  standard_tokens, _conditional_tokens = split_at_first_if(tokens)
115
120
 
116
121
  # This expression includes filters.
117
- _expr = parse_standard_filtered(iter(standard_tokens), linenum)
122
+ _expr = parse_standard_filtered(
123
+ iter(standard_tokens), linenum, shorthand_indexes=shorthand_indexes
124
+ )
118
125
 
119
126
  if not _conditional_tokens:
120
127
  # A standard filtered expression
@@ -126,7 +133,10 @@ def parse(expr: str, linenum: int = 1) -> FilteredExpression:
126
133
  )
127
134
 
128
135
  if conditional_tokens:
129
- condition = parse_boolean_obj(TokenStream(iter(conditional_tokens)), linenum)
136
+ condition = parse_boolean_obj(
137
+ TokenStream(iter(conditional_tokens), shorthand_indexes=shorthand_indexes),
138
+ linenum,
139
+ )
130
140
 
131
141
  else:
132
142
  # A missing condition (an `if` with nothing after it).
@@ -138,7 +148,7 @@ def parse(expr: str, linenum: int = 1) -> FilteredExpression:
138
148
 
139
149
  if alternative_tokens:
140
150
  alternative: Optional[Expression] = parse_standard_filtered(
141
- iter(alternative_tokens), linenum
151
+ iter(alternative_tokens), linenum, shorthand_indexes=shorthand_indexes
142
152
  )
143
153
  else:
144
154
  alternative = None
@@ -156,7 +166,9 @@ def parse(expr: str, linenum: int = 1) -> FilteredExpression:
156
166
  return ConditionalExpression(_expr, tail_filters, condition, alternative)
157
167
 
158
168
 
159
- def parse_with_parens(expr: str, linenum: int = 1) -> FilteredExpression:
169
+ def parse_with_parens(
170
+ expr: str, linenum: int = 1, shorthand_indexes: bool = False
171
+ ) -> FilteredExpression:
160
172
  """Parse a conditional expression string.
161
173
 
162
174
  This parse function handles logical `not` and grouping terms with parentheses.
@@ -165,7 +177,9 @@ def parse_with_parens(expr: str, linenum: int = 1) -> FilteredExpression:
165
177
  standard_tokens, _conditional_tokens = split_at_first_if(tokens)
166
178
 
167
179
  # This expression includes filters.
168
- _expr = parse_standard_filtered(iter(standard_tokens), linenum)
180
+ _expr = parse_standard_filtered(
181
+ iter(standard_tokens), linenum, shorthand_indexes=shorthand_indexes
182
+ )
169
183
 
170
184
  if not _conditional_tokens:
171
185
  # A standard filtered expression
@@ -178,7 +192,8 @@ def parse_with_parens(expr: str, linenum: int = 1) -> FilteredExpression:
178
192
 
179
193
  if conditional_tokens:
180
194
  condition = parse_boolean_obj_with_parens(
181
- TokenStream(iter(conditional_tokens)), linenum
195
+ TokenStream(iter(conditional_tokens), shorthand_indexes=shorthand_indexes),
196
+ linenum,
182
197
  )
183
198
  else:
184
199
  # A missing condition (an `if` with nothing after it).
@@ -190,7 +205,7 @@ def parse_with_parens(expr: str, linenum: int = 1) -> FilteredExpression:
190
205
 
191
206
  if alternative_tokens:
192
207
  alternative: Optional[Expression] = parse_standard_filtered(
193
- iter(alternative_tokens), linenum
208
+ iter(alternative_tokens), linenum, shorthand_indexes=shorthand_indexes
194
209
  )
195
210
  else:
196
211
  alternative = None
@@ -199,7 +214,7 @@ def parse_with_parens(expr: str, linenum: int = 1) -> FilteredExpression:
199
214
 
200
215
  if _filter_tokens:
201
216
  tail_filters = [
202
- _parse_filter(_tokens, linenum)
217
+ _parse_filter(_tokens, linenum, shorthand_indexes=shorthand_indexes)
203
218
  for _tokens in split_at_pipe(iter(_filter_tokens))
204
219
  ]
205
220
  else:
@@ -2,7 +2,9 @@
2
2
 
3
3
  Like those found in output statements and assign tags.
4
4
  """
5
+
5
6
  from itertools import islice
7
+ from typing import Callable
6
8
  from typing import Dict
7
9
  from typing import Iterable
8
10
  from typing import Iterator
@@ -43,7 +45,7 @@ from liquid.token import TOKEN_RANGE_LITERAL
43
45
  from liquid.token import TOKEN_STRING
44
46
  from liquid.token import TOKEN_TRUE
45
47
 
46
- TOKEN_MAP = {
48
+ TOKEN_MAP: Dict[str, Callable[[TokenStream], Expression]] = {
47
49
  TOKEN_FALSE: parse_boolean,
48
50
  TOKEN_TRUE: parse_boolean,
49
51
  TOKEN_NIL: parse_nil,
@@ -126,7 +128,7 @@ def split_at_comma(
126
128
 
127
129
 
128
130
  def bucket_args(
129
- arguments: Iterable[Tuple[str, Expression]]
131
+ arguments: Iterable[Tuple[str, Expression]],
130
132
  ) -> Tuple[List[Expression], Dict[str, Expression]]: # pragma: no cover
131
133
  """Split filter arguments into positional and keyword arguments."""
132
134
  args = []
@@ -166,12 +168,16 @@ def parse_args(
166
168
  yield parse_arg(arg_tokens)
167
169
 
168
170
 
169
- def parse_arg(tokens: List[Token]) -> Tuple[str, Expression]: # pragma: no cover
171
+ def parse_arg(
172
+ tokens: List[Token], *, shorthand_indexes: bool = False
173
+ ) -> Tuple[str, Expression]: # pragma: no cover
170
174
  """Parse a single argument from a list of tokens."""
171
175
  if len(tokens) > 1 and tokens[1][1] == TOKEN_COLON:
172
176
  # A named/keyword parameter/argument
173
- return tokens[0][2], parse_obj(TokenStream(islice(tokens, 2, None)))
174
- return "", parse_obj(TokenStream(iter(tokens)))
177
+ return tokens[0][2], parse_obj(
178
+ TokenStream(islice(tokens, 2, None), shorthand_indexes=shorthand_indexes)
179
+ )
180
+ return "", parse_obj(TokenStream(iter(tokens), shorthand_indexes=shorthand_indexes))
175
181
 
176
182
 
177
183
  # _parse_filter has replaced the parse_* functions above in the name of better syntax
@@ -179,13 +185,15 @@ def parse_arg(tokens: List[Token]) -> Tuple[str, Expression]: # pragma: no cove
179
185
  # be depreciated as we approach Python Liquid version 2 and then removed.
180
186
 
181
187
 
182
- def _parse_filter(tokens: List[Token], linenum: int) -> Filter:
188
+ def _parse_filter(
189
+ tokens: List[Token], linenum: int, *, shorthand_indexes: bool = False
190
+ ) -> Filter:
183
191
  if not tokens:
184
192
  raise LiquidSyntaxError(
185
193
  "unexpected pipe or missing filter name", linenum=linenum
186
194
  )
187
195
 
188
- stream = TokenStream(iter(tokens))
196
+ stream = TokenStream(iter(tokens), shorthand_indexes=shorthand_indexes)
189
197
  stream.expect(TOKEN_IDENTIFIER)
190
198
  name = stream.current[2]
191
199
 
@@ -222,10 +230,12 @@ def _parse_filter(tokens: List[Token], linenum: int) -> Filter:
222
230
  return Filter(name, args, kwargs)
223
231
 
224
232
 
225
- def parse_from_tokens(tokens: Iterator[Token], linenum: int = 1) -> FilteredExpression:
233
+ def parse_from_tokens(
234
+ tokens: Iterator[Token], linenum: int = 1, *, shorthand_indexes: bool = False
235
+ ) -> FilteredExpression:
226
236
  """Parse an expression with zero or more filters from a token iterator."""
227
237
  parts = tuple(split_at_first_pipe(tokens))
228
- stream = TokenStream(iter(parts[0]))
238
+ stream = TokenStream(iter(parts[0]), shorthand_indexes=shorthand_indexes)
229
239
  left = parse_obj(stream)
230
240
 
231
241
  if stream.peek[1] != TOKEN_EOF:
@@ -237,10 +247,17 @@ def parse_from_tokens(tokens: Iterator[Token], linenum: int = 1) -> FilteredExpr
237
247
  if len(parts) == 1:
238
248
  return FilteredExpression(left)
239
249
 
240
- filters = [_parse_filter(_tokens, linenum) for _tokens in split_at_pipe(parts[1])]
250
+ filters = [
251
+ _parse_filter(_tokens, linenum, shorthand_indexes=shorthand_indexes)
252
+ for _tokens in split_at_pipe(parts[1])
253
+ ]
241
254
  return FilteredExpression(left, filters)
242
255
 
243
256
 
244
- def parse(expr: str, linenum: int = 1) -> FilteredExpression:
257
+ def parse(
258
+ expr: str, linenum: int = 1, *, shorthand_indexes: bool = False
259
+ ) -> FilteredExpression:
245
260
  """Parse an expression string with zero or more filters."""
246
- return parse_from_tokens(tokenize(expr, linenum))
261
+ return parse_from_tokens(
262
+ tokenize(expr, linenum), shorthand_indexes=shorthand_indexes
263
+ )
@@ -2,6 +2,7 @@
2
2
 
3
3
  Like those found in `for` and `tablerow` tags.
4
4
  """
5
+
5
6
  from typing import Callable
6
7
  from typing import Dict
7
8
  from typing import Tuple
@@ -109,9 +110,11 @@ def parse_loop_arguments(stream: TokenStream) -> Tuple[Dict[str, LoopArgument],
109
110
  return arguments, _reversed
110
111
 
111
112
 
112
- def parse(expr: str, linenum: int = 1) -> LoopExpression:
113
+ def parse(
114
+ expr: str, linenum: int = 1, *, shorthand_indexes: bool = False
115
+ ) -> LoopExpression:
113
116
  """Parse a loop expression string."""
114
- stream = TokenStream(tokenize(expr, linenum))
117
+ stream = TokenStream(tokenize(expr, linenum), shorthand_indexes=shorthand_indexes)
115
118
  stream.expect(TOKEN_IDENTIFIER)
116
119
  name = next(stream)[2]
117
120
 
@@ -19,13 +19,15 @@ if TYPE_CHECKING:
19
19
  class TokenStream:
20
20
  """Step through or iterate a stream of tokens."""
21
21
 
22
- def __init__(self, tokeniter: Iterator[Token]):
22
+ def __init__(self, tokeniter: Iterator[Token], *, shorthand_indexes: bool = False):
23
23
  self.iter = tokeniter
24
24
  self._pushed: Deque[Token] = deque()
25
25
 
26
26
  self.current: Token = (0, TOKEN_INITIAL, "")
27
27
  next(self)
28
28
 
29
+ self.shorthand_indexes = shorthand_indexes
30
+
29
31
  class TokenStreamIterator:
30
32
  """An iterable token stream."""
31
33
 
@@ -6,7 +6,6 @@ logical `not` operator and grouping terms with parentheses.
6
6
 
7
7
  from liquid.builtin.tags.if_tag import IfTag
8
8
  from liquid.expression import Expression
9
- from liquid.expressions import parse_boolean_expression_with_parens
10
9
  from liquid.parse import expect
11
10
  from liquid.stream import TokenStream
12
11
  from liquid.token import TOKEN_EXPRESSION
@@ -20,6 +19,6 @@ class IfNotTag(IfTag):
20
19
  def parse_expression(self, stream: TokenStream) -> Expression:
21
20
  """Pare a boolean expression from a stream of tokens."""
22
21
  expect(stream, TOKEN_EXPRESSION)
23
- return parse_boolean_expression_with_parens(
22
+ return self.env.parse_boolean_expression_value_with_parens(
24
23
  stream.current.value, stream.current.linenum
25
24
  )
@@ -211,6 +211,7 @@ select = [
211
211
 
212
212
  # TODO: review ignores
213
213
  ignore = [
214
+ "A005",
214
215
  "S105",
215
216
  "S101",
216
217
  "D107",
File without changes