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.
- {python_liquid-1.12.2 → python_liquid-1.13.0}/PKG-INFO +8 -2
- {python_liquid-1.12.2 → python_liquid-1.13.0}/README.md +7 -1
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/__init__.py +1 -1
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/tags/case_tag.py +5 -2
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/environment.py +72 -18
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/expressions/boolean/parse.py +15 -4
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/expressions/common.py +29 -6
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/expressions/conditional/parse.py +26 -11
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/expressions/filtered/parse.py +29 -12
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/expressions/loop/parse.py +5 -2
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/expressions/stream.py +3 -1
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/extra/tags/if_not.py +1 -2
- {python_liquid-1.12.2 → python_liquid-1.13.0}/pyproject.toml +1 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/.gitignore +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/LICENSE +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/analyze_tags.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/ast.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/__init__.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/drops/__init__.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/drops/drops.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/filters/__init__.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/filters/array.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/filters/extra.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/filters/math.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/filters/misc.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/filters/string.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/illegal.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/literal.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/loaders/__init__.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/loaders/base_loader.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/loaders/caching_file_system_loader.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/loaders/choice_loader.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/loaders/file_system_loader.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/loaders/mixins.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/loaders/package_loader.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/statement.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/tags/__init__.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/tags/assign_tag.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/tags/capture_tag.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/tags/comment_tag.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/tags/cycle_tag.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/tags/decrement_tag.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/tags/echo_tag.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/tags/for_tag.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/tags/if_tag.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/tags/ifchanged_tag.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/tags/include_tag.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/tags/increment_tag.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/tags/inline_comment_tag.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/tags/liquid_tag.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/tags/render_tag.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/tags/tablerow_tag.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/tags/unless_tag.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/chain_map.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/context.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/exceptions.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/expression.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/expressions/__init__.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/expressions/arguments/__init__.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/expressions/arguments/lex.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/expressions/arguments/parse.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/expressions/boolean/__init__.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/expressions/boolean/lex.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/expressions/conditional/__init__.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/expressions/conditional/lex.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/expressions/filtered/__init__.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/expressions/filtered/lex.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/expressions/include/__init__.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/expressions/include/lex.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/expressions/loop/__init__.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/expressions/loop/lex.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/extra/__init__.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/extra/filters/__init__.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/extra/filters/_json.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/extra/filters/array.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/extra/filters/html.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/extra/tags/__init__.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/extra/tags/_with.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/extra/tags/extends.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/extra/tags/if_expressions.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/extra/tags/macro.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/filter.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/future/__init__.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/future/environment.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/future/filters/__init__.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/future/filters/_split.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/future/tags/__init__.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/future/tags/_case_tag.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/future/tags/_if_tag.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/future/tags/_tablerow_tag.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/future/tags/_unless_tag.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/__init__.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/abs_filter.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/append_filter.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/assign_tag.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/at_least_filter.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/at_most_filter.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/base64_decode_filter.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/base64_encode_filter.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/base64_url_safe_decode_filter.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/base64_url_safe_encode_filter.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/capitalize_filter.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/capture_tag.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/case.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/case_tag.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/ceil_filter.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/comment_tag.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/compact_filter.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/concat_filter.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/cycle_tag.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/date_filter.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/decrement_tag.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/default_filter.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/divided_by_filter.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/downcase_filter.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/echo_tag.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/escape_filter.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/escape_once_filter.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/first_filter.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/floor_filter.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/for_tag.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/identifiers.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/if_tag.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/ifchanged_tag.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/illegal.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/include_tag.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/increment_tag.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/inline_comment_tag.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/join_filter.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/last_filter.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/liquid_tag.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/lstrip_filter.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/map_filter.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/minus_filter.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/modulo_filter.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/newline_to_br_filter.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/not_liquid.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/output_statement.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/plus_filter.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/prepend_filter.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/range_objects.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/raw_tag.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/remove_filter.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/remove_first_filter.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/remove_last_filter.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/render_tag.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/replace_filter.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/replace_first_filter.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/replace_last_filter.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/reverse_filter.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/round_filter.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/rstrip_filter.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/size_filter.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/slice_filter.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/sort_filter.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/sort_natural_filter.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/special.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/split_filter.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/strip_filter.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/strip_html_filter.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/strip_newlines_filter.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/sum_filter.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/tablerow_tag.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/times_filter.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/truncate_filter.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/truncatewords_filter.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/uniq_filter.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/unless_tag.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/upcase_filter.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/url_decode_filter.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/url_encode_filter.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/where_filter.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/golden/whitespace_control.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/lex.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/limits.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/loaders.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/mode.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/output.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/parse.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/py.typed +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/static_analysis.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/stream.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/stringify.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/tag.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/template.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/token.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/undefined.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/utils/__init__.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/utils/cache.py +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/utils/cache.pyi +0 -0
- {python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/utils/html.py +0 -0
- {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.
|
|
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
|
-
- [
|
|
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
|
-
- [
|
|
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.
|
|
@@ -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],
|
|
582
|
-
Callable[[str, int],
|
|
583
|
-
Callable[[str, int],
|
|
584
|
-
Callable[[str, int],
|
|
585
|
-
Callable[[str, int],
|
|
586
|
-
Callable[[str, int],
|
|
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)(
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
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
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
-
|
|
149
|
-
|
|
150
|
-
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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)),
|
|
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(
|
|
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(
|
|
174
|
-
|
|
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(
|
|
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(
|
|
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 = [
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|
22
|
+
return self.env.parse_boolean_expression_value_with_parens(
|
|
24
23
|
stream.current.value, stream.current.linenum
|
|
25
24
|
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_liquid-1.12.2 → python_liquid-1.13.0}/liquid/builtin/loaders/caching_file_system_loader.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|