python-liquid 1.10.2__tar.gz → 1.12.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.10.2 → python_liquid-1.12.0}/PKG-INFO +8 -2
- {python_liquid-1.10.2 → python_liquid-1.12.0}/README.md +5 -1
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/__init__.py +9 -1
- python_liquid-1.12.0/liquid/builtin/loaders/__init__.py +133 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/builtin/loaders/base_loader.py +6 -5
- python_liquid-1.12.0/liquid/builtin/loaders/caching_file_system_loader.py +75 -0
- python_liquid-1.12.0/liquid/builtin/loaders/choice_loader.py +143 -0
- python_liquid-1.10.2/liquid/builtin/loaders/caching_file_system_loader.py → python_liquid-1.12.0/liquid/builtin/loaders/mixins.py +117 -105
- python_liquid-1.12.0/liquid/builtin/loaders/package_loader.py +108 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/exceptions.py +4 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/expression.py +68 -47
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/if_tag.py +48 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/loaders.py +8 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/utils/cache.py +5 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/pyproject.toml +105 -107
- python_liquid-1.10.2/liquid/builtin/loaders/__init__.py +0 -24
- python_liquid-1.10.2/liquid/builtin/loaders/choice_loader.py +0 -49
- {python_liquid-1.10.2 → python_liquid-1.12.0}/.gitignore +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/LICENSE +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/analyze_tags.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/ast.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/builtin/__init__.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/builtin/drops/__init__.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/builtin/drops/drops.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/builtin/filters/__init__.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/builtin/filters/array.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/builtin/filters/extra.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/builtin/filters/math.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/builtin/filters/misc.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/builtin/filters/string.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/builtin/illegal.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/builtin/literal.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/builtin/loaders/file_system_loader.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/builtin/statement.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/builtin/tags/__init__.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/builtin/tags/assign_tag.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/builtin/tags/capture_tag.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/builtin/tags/case_tag.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/builtin/tags/comment_tag.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/builtin/tags/cycle_tag.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/builtin/tags/decrement_tag.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/builtin/tags/echo_tag.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/builtin/tags/for_tag.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/builtin/tags/if_tag.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/builtin/tags/ifchanged_tag.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/builtin/tags/include_tag.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/builtin/tags/increment_tag.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/builtin/tags/inline_comment_tag.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/builtin/tags/liquid_tag.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/builtin/tags/render_tag.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/builtin/tags/tablerow_tag.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/builtin/tags/unless_tag.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/chain_map.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/context.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/environment.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/expressions/__init__.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/expressions/arguments/__init__.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/expressions/arguments/lex.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/expressions/arguments/parse.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/expressions/boolean/__init__.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/expressions/boolean/lex.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/expressions/boolean/parse.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/expressions/common.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/expressions/conditional/__init__.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/expressions/conditional/lex.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/expressions/conditional/parse.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/expressions/filtered/__init__.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/expressions/filtered/lex.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/expressions/filtered/parse.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/expressions/include/__init__.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/expressions/include/lex.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/expressions/loop/__init__.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/expressions/loop/lex.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/expressions/loop/parse.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/expressions/stream.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/extra/__init__.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/extra/filters/__init__.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/extra/filters/_json.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/extra/filters/array.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/extra/filters/html.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/extra/tags/__init__.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/extra/tags/_with.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/extra/tags/extends.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/extra/tags/if_expressions.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/extra/tags/if_not.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/extra/tags/macro.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/filter.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/future/__init__.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/future/environment.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/future/filters/__init__.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/future/filters/_split.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/__init__.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/abs_filter.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/append_filter.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/assign_tag.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/at_least_filter.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/at_most_filter.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/base64_decode_filter.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/base64_encode_filter.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/base64_url_safe_decode_filter.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/base64_url_safe_encode_filter.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/capitalize_filter.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/capture_tag.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/case.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/case_tag.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/ceil_filter.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/comment_tag.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/compact_filter.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/concat_filter.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/cycle_tag.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/date_filter.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/decrement_tag.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/default_filter.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/divided_by_filter.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/downcase_filter.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/echo_tag.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/escape_filter.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/escape_once_filter.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/first_filter.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/floor_filter.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/for_tag.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/identifiers.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/ifchanged_tag.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/illegal.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/include_tag.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/increment_tag.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/inline_comment_tag.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/join_filter.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/last_filter.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/liquid_tag.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/lstrip_filter.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/map_filter.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/minus_filter.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/modulo_filter.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/newline_to_br_filter.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/not_liquid.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/output_statement.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/plus_filter.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/prepend_filter.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/range_objects.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/raw_tag.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/remove_filter.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/remove_first_filter.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/remove_last_filter.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/render_tag.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/replace_filter.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/replace_first_filter.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/replace_last_filter.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/reverse_filter.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/round_filter.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/rstrip_filter.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/size_filter.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/slice_filter.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/sort_filter.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/sort_natural_filter.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/special.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/split_filter.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/strip_filter.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/strip_html_filter.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/strip_newlines_filter.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/sum_filter.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/tablerow_tag.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/times_filter.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/truncate_filter.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/truncatewords_filter.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/uniq_filter.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/unless_tag.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/upcase_filter.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/url_decode_filter.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/url_encode_filter.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/where_filter.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/golden/whitespace_control.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/lex.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/limits.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/mode.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/output.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/parse.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/py.typed +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/static_analysis.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/stream.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/stringify.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/tag.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/template.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/token.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/undefined.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/utils/__init__.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/utils/cache.pyi +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/utils/html.py +0 -0
- {python_liquid-1.10.2 → python_liquid-1.12.0}/liquid/utils/text.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: python-liquid
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.12.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/
|
|
@@ -19,9 +19,11 @@ Classifier: Programming Language :: Python :: 3.8
|
|
|
19
19
|
Classifier: Programming Language :: Python :: 3.9
|
|
20
20
|
Classifier: Programming Language :: Python :: 3.10
|
|
21
21
|
Classifier: Programming Language :: Python :: 3.11
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
23
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
23
24
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
24
25
|
Requires-Python: >=3.7
|
|
26
|
+
Requires-Dist: importlib-resources>=5.10.0
|
|
25
27
|
Requires-Dist: python-dateutil>=2.8.1
|
|
26
28
|
Requires-Dist: typing-extensions>=4.2.0
|
|
27
29
|
Provides-Extra: autoescape
|
|
@@ -32,8 +34,8 @@ Description-Content-Type: text/markdown
|
|
|
32
34
|
|
|
33
35
|
<p align="center">
|
|
34
36
|
A Python engine for <a href="https://shopify.github.io/liquid/">Liquid</a>, the safe customer-facing template language for flexible web apps.
|
|
37
|
+
<br>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.
|
|
35
38
|
</p>
|
|
36
|
-
|
|
37
39
|
<p align="center">
|
|
38
40
|
<a href="https://github.com/jg-rp/liquid/blob/main/LICENSE">
|
|
39
41
|
<img src="https://img.shields.io/pypi/l/python-liquid.svg?style=flat-square" alt="License">
|
|
@@ -59,6 +61,10 @@ A Python engine for <a href="https://shopify.github.io/liquid/">Liquid</a>, the
|
|
|
59
61
|
<a href="https://github.com/jg-rp/liquid/actions/workflows/coverage.yaml">
|
|
60
62
|
<img src="https://img.shields.io/github/actions/workflow/status/jg-rp/liquid/coverage.yaml?branch=main&label=coverage&style=flat-square" alt="Coverage">
|
|
61
63
|
</a>
|
|
64
|
+
<br>
|
|
65
|
+
<a href="https://pypi.org/project/python-liquid/">
|
|
66
|
+
<img alt="PyPI - Downloads" src="https://img.shields.io/pypi/dm/python-liquid?style=flat-square">
|
|
67
|
+
</a>
|
|
62
68
|
</p>
|
|
63
69
|
|
|
64
70
|
---
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
<p align="center">
|
|
4
4
|
A Python engine for <a href="https://shopify.github.io/liquid/">Liquid</a>, the safe customer-facing template language for flexible web apps.
|
|
5
|
+
<br>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.
|
|
5
6
|
</p>
|
|
6
|
-
|
|
7
7
|
<p align="center">
|
|
8
8
|
<a href="https://github.com/jg-rp/liquid/blob/main/LICENSE">
|
|
9
9
|
<img src="https://img.shields.io/pypi/l/python-liquid.svg?style=flat-square" alt="License">
|
|
@@ -29,6 +29,10 @@ A Python engine for <a href="https://shopify.github.io/liquid/">Liquid</a>, the
|
|
|
29
29
|
<a href="https://github.com/jg-rp/liquid/actions/workflows/coverage.yaml">
|
|
30
30
|
<img src="https://img.shields.io/github/actions/workflow/status/jg-rp/liquid/coverage.yaml?branch=main&label=coverage&style=flat-square" alt="Coverage">
|
|
31
31
|
</a>
|
|
32
|
+
<br>
|
|
33
|
+
<a href="https://pypi.org/project/python-liquid/">
|
|
34
|
+
<img alt="PyPI - Downloads" src="https://img.shields.io/pypi/dm/python-liquid?style=flat-square">
|
|
35
|
+
</a>
|
|
32
36
|
</p>
|
|
33
37
|
|
|
34
38
|
---
|
|
@@ -12,11 +12,15 @@ from .mode import Mode
|
|
|
12
12
|
from .token import Token
|
|
13
13
|
from .expression import Expression
|
|
14
14
|
|
|
15
|
+
from .loaders import CachingChoiceLoader
|
|
15
16
|
from .loaders import CachingFileSystemLoader
|
|
16
17
|
from .loaders import ChoiceLoader
|
|
17
18
|
from .loaders import DictLoader
|
|
18
19
|
from .loaders import FileExtensionLoader
|
|
19
20
|
from .loaders import FileSystemLoader
|
|
21
|
+
from .loaders import PackageLoader
|
|
22
|
+
from .loaders import make_choice_loader
|
|
23
|
+
from .loaders import make_file_system_loader
|
|
20
24
|
|
|
21
25
|
from .context import Context
|
|
22
26
|
from .context import DebugUndefined
|
|
@@ -42,11 +46,12 @@ from .static_analysis import ContextualTemplateAnalysis
|
|
|
42
46
|
|
|
43
47
|
from . import future
|
|
44
48
|
|
|
45
|
-
__version__ = "1.
|
|
49
|
+
__version__ = "1.12.0"
|
|
46
50
|
|
|
47
51
|
__all__ = (
|
|
48
52
|
"AwareBoundTemplate",
|
|
49
53
|
"BoundTemplate",
|
|
54
|
+
"CachingChoiceLoader",
|
|
50
55
|
"CachingFileSystemLoader",
|
|
51
56
|
"ChoiceLoader",
|
|
52
57
|
"Context",
|
|
@@ -64,8 +69,11 @@ __all__ = (
|
|
|
64
69
|
"FutureBoundTemplate",
|
|
65
70
|
"FutureContext",
|
|
66
71
|
"is_undefined",
|
|
72
|
+
"make_choice_loader",
|
|
73
|
+
"make_file_system_loader",
|
|
67
74
|
"Markup",
|
|
68
75
|
"Mode",
|
|
76
|
+
"PackageLoader",
|
|
69
77
|
"soft_str",
|
|
70
78
|
"StrictDefaultUndefined",
|
|
71
79
|
"StrictUndefined",
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from typing import Iterable
|
|
3
|
+
from typing import List
|
|
4
|
+
from typing import Union
|
|
5
|
+
|
|
6
|
+
from .base_loader import BaseLoader
|
|
7
|
+
from .base_loader import DictLoader
|
|
8
|
+
from .base_loader import TemplateNamespace
|
|
9
|
+
from .base_loader import TemplateSource
|
|
10
|
+
from .base_loader import UpToDate
|
|
11
|
+
|
|
12
|
+
from .choice_loader import CachingChoiceLoader
|
|
13
|
+
from .choice_loader import ChoiceLoader
|
|
14
|
+
|
|
15
|
+
from .file_system_loader import FileExtensionLoader
|
|
16
|
+
from .file_system_loader import FileSystemLoader
|
|
17
|
+
|
|
18
|
+
from .caching_file_system_loader import CachingFileSystemLoader
|
|
19
|
+
|
|
20
|
+
from .package_loader import PackageLoader
|
|
21
|
+
|
|
22
|
+
__all__ = (
|
|
23
|
+
"BaseLoader",
|
|
24
|
+
"CachingChoiceLoader",
|
|
25
|
+
"CachingFileSystemLoader",
|
|
26
|
+
"ChoiceLoader",
|
|
27
|
+
"DictLoader",
|
|
28
|
+
"FileExtensionLoader",
|
|
29
|
+
"FileSystemLoader",
|
|
30
|
+
"make_choice_loader",
|
|
31
|
+
"make_file_system_loader",
|
|
32
|
+
"PackageLoader",
|
|
33
|
+
"TemplateNamespace",
|
|
34
|
+
"TemplateSource",
|
|
35
|
+
"UpToDate",
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def make_file_system_loader(
|
|
40
|
+
search_path: Union[str, Path, Iterable[Union[str, Path]]],
|
|
41
|
+
*,
|
|
42
|
+
encoding: str = "utf-8",
|
|
43
|
+
ext: str = ".liquid",
|
|
44
|
+
auto_reload: bool = True,
|
|
45
|
+
namespace_key: str = "",
|
|
46
|
+
cache_size: int = 300,
|
|
47
|
+
) -> BaseLoader:
|
|
48
|
+
"""A _file system_ template loader factory.
|
|
49
|
+
|
|
50
|
+
Returns one of `CachingFileSystemLoader`, `FileExtensionLoader` or
|
|
51
|
+
`FileSystemLoader` depending in the given arguments.
|
|
52
|
+
|
|
53
|
+
A `CachingFileSystemLoader` is returned if _cache_size_ is greater than 0.
|
|
54
|
+
Otherwise a `FileExtensionLoader` is returned if _ext_ is not empty.
|
|
55
|
+
If _ext_ is empty, a `FileSystemLoader` is returned.
|
|
56
|
+
|
|
57
|
+
_auto_reload_ and _namespace_key_ are ignored if _cache_key_ is less than 1.
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
search_path: One or more paths to search.
|
|
61
|
+
encoding: Open template files with the given encoding.
|
|
62
|
+
ext: A default file extension. Should include a leading period.
|
|
63
|
+
auto_reload: If `True`, automatically reload a cached template if it has been
|
|
64
|
+
updated.
|
|
65
|
+
namespace_key: The name of a global render context variable or loader keyword
|
|
66
|
+
argument that resolves to the current loader "namespace" or "scope".
|
|
67
|
+
|
|
68
|
+
If you're developing a multi-user application, a good namespace might be
|
|
69
|
+
`uid`, where `uid` is a unique identifier for a user and templates are
|
|
70
|
+
arranged in folders named for each `uid` inside the search path.
|
|
71
|
+
cache_size: The maximum number of templates to hold in the cache before removing
|
|
72
|
+
the least recently used template.
|
|
73
|
+
|
|
74
|
+
_New in version 1.12.0_
|
|
75
|
+
"""
|
|
76
|
+
if cache_size > 0:
|
|
77
|
+
return CachingFileSystemLoader(
|
|
78
|
+
search_path=search_path,
|
|
79
|
+
encoding=encoding,
|
|
80
|
+
ext=ext,
|
|
81
|
+
auto_reload=auto_reload,
|
|
82
|
+
namespace_key=namespace_key,
|
|
83
|
+
cache_size=cache_size,
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
if ext:
|
|
87
|
+
return FileExtensionLoader(
|
|
88
|
+
search_path=search_path,
|
|
89
|
+
encoding=encoding,
|
|
90
|
+
ext=ext,
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
return FileSystemLoader(search_path=search_path, encoding=encoding)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def make_choice_loader(
|
|
97
|
+
loaders: List[BaseLoader],
|
|
98
|
+
*,
|
|
99
|
+
auto_reload: bool = True,
|
|
100
|
+
namespace_key: str = "",
|
|
101
|
+
cache_size: int = 300,
|
|
102
|
+
) -> BaseLoader:
|
|
103
|
+
"""A _choice loader_ factory.
|
|
104
|
+
|
|
105
|
+
Returns one of `CachingChoiceLoader` or `ChoiceLoader` depending on the
|
|
106
|
+
given arguments.
|
|
107
|
+
|
|
108
|
+
A `CachingChoiceLoader` is returned if _cache_size_ > 0, otherwise a
|
|
109
|
+
`ChoiceLoader` is returned.
|
|
110
|
+
|
|
111
|
+
_auto_reload_ and _namespace_key_ are ignored if _cache_key_ is less than 1.
|
|
112
|
+
|
|
113
|
+
Args:
|
|
114
|
+
loaders: A list of loaders implementing `liquid.loaders.BaseLoader`.
|
|
115
|
+
auto_reload: If `True`, automatically reload a cached template if it
|
|
116
|
+
has been updated.
|
|
117
|
+
namespace_key: The name of a global render context variable or loader
|
|
118
|
+
keyword argument that resolves to the current loader "namespace" or
|
|
119
|
+
"scope".
|
|
120
|
+
cache_size: The maximum number of templates to hold in the cache before
|
|
121
|
+
removing the least recently used template.
|
|
122
|
+
|
|
123
|
+
_New in version 1.12.0_
|
|
124
|
+
"""
|
|
125
|
+
if cache_size > 0:
|
|
126
|
+
return CachingChoiceLoader(
|
|
127
|
+
loaders=loaders,
|
|
128
|
+
auto_reload=auto_reload,
|
|
129
|
+
namespace_key=namespace_key,
|
|
130
|
+
cache_size=cache_size,
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
return ChoiceLoader(loaders=loaders)
|
|
@@ -129,11 +129,12 @@ class BaseLoader(ABC): # noqa: B024
|
|
|
129
129
|
name: str,
|
|
130
130
|
globals: TemplateNamespace = None, # noqa: A002
|
|
131
131
|
) -> BoundTemplate:
|
|
132
|
-
"""
|
|
132
|
+
"""Find and parse template source code.
|
|
133
133
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
than overriding
|
|
134
|
+
This is used internally by `liquid.Environment` to load template
|
|
135
|
+
source text. `load()` delegates to `BaseLoader.get_source()`. Custom
|
|
136
|
+
loaders would typically implement `get_source()` rather than overriding
|
|
137
|
+
`load()`.
|
|
137
138
|
"""
|
|
138
139
|
try:
|
|
139
140
|
source, filename, uptodate, matter = self.get_source(env, name)
|
|
@@ -156,7 +157,7 @@ class BaseLoader(ABC): # noqa: B024
|
|
|
156
157
|
name: str,
|
|
157
158
|
globals: TemplateNamespace = None, # noqa: A002
|
|
158
159
|
) -> BoundTemplate:
|
|
159
|
-
"""An async version of `load`."""
|
|
160
|
+
"""An async version of `load()`."""
|
|
160
161
|
try:
|
|
161
162
|
template_source = await self.get_source_async(env, name)
|
|
162
163
|
source, filename, uptodate, matter = template_source
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"""A file system loader that caches parsed templates in memory."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
from typing import Iterable
|
|
6
|
+
from typing import Union
|
|
7
|
+
|
|
8
|
+
from .file_system_loader import FileExtensionLoader
|
|
9
|
+
from .mixins import CachingLoaderMixin
|
|
10
|
+
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
|
|
14
|
+
from liquid import Context
|
|
15
|
+
|
|
16
|
+
from .base_loader import TemplateSource
|
|
17
|
+
|
|
18
|
+
# ruff: noqa: D102
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class CachingFileSystemLoader(CachingLoaderMixin, FileExtensionLoader):
|
|
22
|
+
"""A file system loader that caches parsed templates in memory.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
search_path: One or more paths to search.
|
|
26
|
+
encoding: Open template files with the given encoding.
|
|
27
|
+
ext: A default file extension. Should include a leading period.
|
|
28
|
+
auto_reload: If `True`, automatically reload a cached template if it has been
|
|
29
|
+
updated.
|
|
30
|
+
namespace_key: The name of a global render context variable or loader keyword
|
|
31
|
+
argument that resolves to the current loader "namespace" or "scope".
|
|
32
|
+
|
|
33
|
+
If you're developing a multi-user application, a good namespace might be
|
|
34
|
+
`uid`, where `uid` is a unique identifier for a user and templates are
|
|
35
|
+
arranged in folders named for each `uid` inside the search path.
|
|
36
|
+
cache_size: The maximum number of templates to hold in the cache before removing
|
|
37
|
+
the least recently used template.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
def __init__(
|
|
41
|
+
self,
|
|
42
|
+
search_path: Union[str, Path, Iterable[Union[str, Path]]],
|
|
43
|
+
encoding: str = "utf-8",
|
|
44
|
+
ext: str = ".liquid",
|
|
45
|
+
*,
|
|
46
|
+
auto_reload: bool = True,
|
|
47
|
+
namespace_key: str = "",
|
|
48
|
+
cache_size: int = 300,
|
|
49
|
+
):
|
|
50
|
+
super().__init__(
|
|
51
|
+
auto_reload=auto_reload,
|
|
52
|
+
namespace_key=namespace_key,
|
|
53
|
+
cache_size=cache_size,
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
FileExtensionLoader.__init__(
|
|
57
|
+
self,
|
|
58
|
+
search_path=search_path,
|
|
59
|
+
encoding=encoding,
|
|
60
|
+
ext=ext,
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
def get_source_with_context(
|
|
64
|
+
self, context: Context, template_name: str, **kwargs: str
|
|
65
|
+
) -> TemplateSource:
|
|
66
|
+
# In this case, our cache key and real file name are the same.
|
|
67
|
+
name = self.cache_key_with_context(template_name, context, **kwargs)
|
|
68
|
+
return self.get_source(context.env, name)
|
|
69
|
+
|
|
70
|
+
async def get_source_with_context_async(
|
|
71
|
+
self, context: Context, template_name: str, **kwargs: str
|
|
72
|
+
) -> TemplateSource:
|
|
73
|
+
# In this case, our cache key and real file name are the same.
|
|
74
|
+
name = self.cache_key_with_context(template_name, context, **kwargs)
|
|
75
|
+
return await self.get_source_async(context.env, name)
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
"""A template loader that delegates to other template loaders."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
from typing import List
|
|
6
|
+
|
|
7
|
+
from liquid.exceptions import TemplateNotFound
|
|
8
|
+
|
|
9
|
+
from .base_loader import BaseLoader
|
|
10
|
+
from .mixins import CachingLoaderMixin
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from liquid import Context
|
|
14
|
+
from liquid import Environment
|
|
15
|
+
|
|
16
|
+
from .base_loader import TemplateSource
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class ChoiceLoader(BaseLoader):
|
|
20
|
+
"""A template loader that will try each of a list of loaders in turn.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
loaders: A list of loaders implementing `liquid.loaders.BaseLoader`.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
def __init__(self, loaders: List[BaseLoader]):
|
|
27
|
+
super().__init__()
|
|
28
|
+
self.loaders = loaders
|
|
29
|
+
|
|
30
|
+
def get_source(self, env: Environment, template_name: str) -> TemplateSource:
|
|
31
|
+
"""Get source code for a template from one of the configured loaders."""
|
|
32
|
+
for loader in self.loaders:
|
|
33
|
+
try:
|
|
34
|
+
return loader.get_source(env, template_name)
|
|
35
|
+
except TemplateNotFound:
|
|
36
|
+
pass
|
|
37
|
+
|
|
38
|
+
raise TemplateNotFound(template_name)
|
|
39
|
+
|
|
40
|
+
async def get_source_async(
|
|
41
|
+
self,
|
|
42
|
+
env: Environment,
|
|
43
|
+
template_name: str,
|
|
44
|
+
) -> TemplateSource:
|
|
45
|
+
"""An async version of `get_source`."""
|
|
46
|
+
for loader in self.loaders:
|
|
47
|
+
try:
|
|
48
|
+
return await loader.get_source_async(env, template_name)
|
|
49
|
+
except TemplateNotFound:
|
|
50
|
+
pass
|
|
51
|
+
|
|
52
|
+
raise TemplateNotFound(template_name)
|
|
53
|
+
|
|
54
|
+
def get_source_with_args(
|
|
55
|
+
self,
|
|
56
|
+
env: Environment,
|
|
57
|
+
template_name: str,
|
|
58
|
+
**kwargs: object,
|
|
59
|
+
) -> TemplateSource:
|
|
60
|
+
"""Get source code for a template from one of the configured loaders."""
|
|
61
|
+
for loader in self.loaders:
|
|
62
|
+
try:
|
|
63
|
+
return loader.get_source_with_args(env, template_name, **kwargs)
|
|
64
|
+
except TemplateNotFound:
|
|
65
|
+
pass
|
|
66
|
+
|
|
67
|
+
# TODO: include arguments in TemplateNotFound exception.
|
|
68
|
+
raise TemplateNotFound(template_name)
|
|
69
|
+
|
|
70
|
+
async def get_source_with_args_async(
|
|
71
|
+
self,
|
|
72
|
+
env: Environment,
|
|
73
|
+
template_name: str,
|
|
74
|
+
**kwargs: object,
|
|
75
|
+
) -> TemplateSource:
|
|
76
|
+
"""An async version of `get_source_with_args`."""
|
|
77
|
+
for loader in self.loaders:
|
|
78
|
+
try:
|
|
79
|
+
return await loader.get_source_with_args_async(
|
|
80
|
+
env, template_name, **kwargs
|
|
81
|
+
)
|
|
82
|
+
except TemplateNotFound:
|
|
83
|
+
pass
|
|
84
|
+
|
|
85
|
+
raise TemplateNotFound(template_name)
|
|
86
|
+
|
|
87
|
+
def get_source_with_context(
|
|
88
|
+
self, context: Context, template_name: str, **kwargs: str
|
|
89
|
+
) -> TemplateSource:
|
|
90
|
+
"""Get source code for a template from one of the configured loaders."""
|
|
91
|
+
for loader in self.loaders:
|
|
92
|
+
try:
|
|
93
|
+
return loader.get_source_with_context(context, template_name, **kwargs)
|
|
94
|
+
except TemplateNotFound:
|
|
95
|
+
pass
|
|
96
|
+
|
|
97
|
+
raise TemplateNotFound(template_name)
|
|
98
|
+
|
|
99
|
+
async def get_source_with_context_async(
|
|
100
|
+
self, context: Context, template_name: str, **kwargs: str
|
|
101
|
+
) -> TemplateSource:
|
|
102
|
+
"""Get source code for a template from one of the configured loaders."""
|
|
103
|
+
for loader in self.loaders:
|
|
104
|
+
try:
|
|
105
|
+
return await loader.get_source_with_context_async(
|
|
106
|
+
context, template_name, **kwargs
|
|
107
|
+
)
|
|
108
|
+
except TemplateNotFound:
|
|
109
|
+
pass
|
|
110
|
+
|
|
111
|
+
raise TemplateNotFound(template_name)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
class CachingChoiceLoader(CachingLoaderMixin, ChoiceLoader):
|
|
115
|
+
"""A `ChoiceLoader` that caches parsed templates in memory.
|
|
116
|
+
|
|
117
|
+
Args:
|
|
118
|
+
loaders: A list of loaders implementing `liquid.loaders.BaseLoader`.
|
|
119
|
+
auto_reload: If `True`, automatically reload a cached template if it has been
|
|
120
|
+
updated.
|
|
121
|
+
namespace_key: The name of a global render context variable or loader keyword
|
|
122
|
+
argument that resolves to the current loader "namespace" or "scope".
|
|
123
|
+
cache_size: The maximum number of templates to hold in the cache before removing
|
|
124
|
+
the least recently used template.
|
|
125
|
+
|
|
126
|
+
_New in version 1.11.0._
|
|
127
|
+
"""
|
|
128
|
+
|
|
129
|
+
def __init__(
|
|
130
|
+
self,
|
|
131
|
+
loaders: List[BaseLoader],
|
|
132
|
+
*,
|
|
133
|
+
auto_reload: bool = True,
|
|
134
|
+
namespace_key: str = "",
|
|
135
|
+
cache_size: int = 300,
|
|
136
|
+
):
|
|
137
|
+
super().__init__(
|
|
138
|
+
auto_reload=auto_reload,
|
|
139
|
+
namespace_key=namespace_key,
|
|
140
|
+
cache_size=cache_size,
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
ChoiceLoader.__init__(self, loaders)
|