python-liquid 2.3.5__tar.gz → 3.0.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-2.3.5 → python_liquid-3.0.0}/.gitignore +4 -1
- {python_liquid-2.3.5 → python_liquid-3.0.0}/LICENSE +1 -1
- {python_liquid-2.3.5 → python_liquid-3.0.0}/PKG-INFO +32 -39
- {python_liquid-2.3.5 → python_liquid-3.0.0}/README.md +27 -30
- python_liquid-3.0.0/liquid/__about__.py +1 -0
- python_liquid-3.0.0/liquid/__init__.py +220 -0
- python_liquid-3.0.0/liquid/_base_tag.py +66 -0
- python_liquid-2.3.5/liquid/utils/chain_map.py → python_liquid-3.0.0/liquid/_chain_map.py +18 -19
- python_liquid-3.0.0/liquid/_context.py +465 -0
- python_liquid-3.0.0/liquid/_drop.py +108 -0
- python_liquid-3.0.0/liquid/_filter.py +174 -0
- python_liquid-3.0.0/liquid/_io.py +18 -0
- python_liquid-3.0.0/liquid/_lax_parser_mixin.py +100 -0
- python_liquid-3.0.0/liquid/_lexer.py +93 -0
- python_liquid-3.0.0/liquid/_lexer_extended.py +623 -0
- python_liquid-3.0.0/liquid/_lexer_legacy.py +536 -0
- python_liquid-3.0.0/liquid/_loader.py +84 -0
- python_liquid-2.3.5/liquid/utils/lru_cache.py → python_liquid-3.0.0/liquid/_lru_cache.py +28 -36
- python_liquid-3.0.0/liquid/_markup.py +253 -0
- python_liquid-3.0.0/liquid/_messages.py +292 -0
- python_liquid-3.0.0/liquid/_missing.py +3 -0
- python_liquid-3.0.0/liquid/_nothing.py +28 -0
- python_liquid-3.0.0/liquid/_parser.py +460 -0
- python_liquid-3.0.0/liquid/_parser_extended.py +293 -0
- python_liquid-3.0.0/liquid/_parser_legacy.py +819 -0
- python_liquid-3.0.0/liquid/_resource_limits.py +50 -0
- python_liquid-3.0.0/liquid/_slice.py +41 -0
- python_liquid-3.0.0/liquid/_static_analysis.py +503 -0
- python_liquid-3.0.0/liquid/_strftime.py +186 -0
- python_liquid-3.0.0/liquid/_template.py +536 -0
- python_liquid-3.0.0/liquid/drops/__init__.py +20 -0
- python_liquid-3.0.0/liquid/drops/forloop.py +78 -0
- python_liquid-3.0.0/liquid/drops/iterable.py +25 -0
- python_liquid-3.0.0/liquid/drops/range.py +76 -0
- python_liquid-3.0.0/liquid/drops/self_.py +45 -0
- python_liquid-3.0.0/liquid/drops/tablerowloop.py +142 -0
- python_liquid-3.0.0/liquid/drops/undefined.py +228 -0
- python_liquid-3.0.0/liquid/environment.py +777 -0
- python_liquid-3.0.0/liquid/exceptions.py +142 -0
- python_liquid-3.0.0/liquid/expressions.py +1184 -0
- python_liquid-3.0.0/liquid/filters/__init__.py +134 -0
- python_liquid-3.0.0/liquid/filters/abs.py +7 -0
- python_liquid-3.0.0/liquid/filters/append.py +5 -0
- python_liquid-3.0.0/liquid/filters/at_least.py +9 -0
- python_liquid-3.0.0/liquid/filters/at_most.py +9 -0
- python_liquid-3.0.0/liquid/filters/babel.py +560 -0
- python_liquid-3.0.0/liquid/filters/base64.py +26 -0
- python_liquid-3.0.0/liquid/filters/capitalize.py +5 -0
- python_liquid-3.0.0/liquid/filters/ceil.py +8 -0
- python_liquid-3.0.0/liquid/filters/compact.py +25 -0
- python_liquid-3.0.0/liquid/filters/concat.py +11 -0
- python_liquid-3.0.0/liquid/filters/date.py +27 -0
- python_liquid-3.0.0/liquid/filters/default.py +25 -0
- python_liquid-3.0.0/liquid/filters/divided_by.py +21 -0
- python_liquid-3.0.0/liquid/filters/downcase.py +5 -0
- python_liquid-3.0.0/liquid/filters/escape.py +56 -0
- python_liquid-3.0.0/liquid/filters/find.py +56 -0
- python_liquid-3.0.0/liquid/filters/first.py +19 -0
- python_liquid-3.0.0/liquid/filters/floor.py +8 -0
- python_liquid-3.0.0/liquid/filters/html.py +23 -0
- python_liquid-3.0.0/liquid/filters/index.py +12 -0
- python_liquid-3.0.0/liquid/filters/join.py +13 -0
- python_liquid-3.0.0/liquid/filters/json_.py +30 -0
- python_liquid-3.0.0/liquid/filters/last.py +17 -0
- python_liquid-3.0.0/liquid/filters/map.py +5 -0
- python_liquid-3.0.0/liquid/filters/minus.py +13 -0
- python_liquid-3.0.0/liquid/filters/modulo.py +18 -0
- python_liquid-3.0.0/liquid/filters/newline_to_br.py +16 -0
- python_liquid-3.0.0/liquid/filters/plus.py +13 -0
- python_liquid-3.0.0/liquid/filters/prepend.py +5 -0
- python_liquid-3.0.0/liquid/filters/reject.py +19 -0
- python_liquid-3.0.0/liquid/filters/remove.py +36 -0
- python_liquid-3.0.0/liquid/filters/replace.py +32 -0
- python_liquid-3.0.0/liquid/filters/reverse.py +5 -0
- python_liquid-3.0.0/liquid/filters/round.py +35 -0
- python_liquid-3.0.0/liquid/filters/size.py +25 -0
- python_liquid-3.0.0/liquid/filters/slice.py +39 -0
- python_liquid-3.0.0/liquid/filters/sort.py +148 -0
- python_liquid-3.0.0/liquid/filters/split.py +34 -0
- python_liquid-3.0.0/liquid/filters/squish.py +9 -0
- python_liquid-3.0.0/liquid/filters/strip.py +13 -0
- python_liquid-3.0.0/liquid/filters/strip_html.py +19 -0
- python_liquid-3.0.0/liquid/filters/strip_newlines.py +17 -0
- python_liquid-3.0.0/liquid/filters/sum.py +21 -0
- python_liquid-3.0.0/liquid/filters/times.py +13 -0
- python_liquid-3.0.0/liquid/filters/translate.py +380 -0
- python_liquid-3.0.0/liquid/filters/truncate.py +39 -0
- python_liquid-3.0.0/liquid/filters/uniq.py +11 -0
- python_liquid-3.0.0/liquid/filters/upcase.py +5 -0
- python_liquid-3.0.0/liquid/filters/url.py +18 -0
- python_liquid-3.0.0/liquid/filters/where.py +18 -0
- python_liquid-3.0.0/liquid/loaders/__init__.py +17 -0
- python_liquid-3.0.0/liquid/loaders/caching_file_system_loader.py +64 -0
- python_liquid-3.0.0/liquid/loaders/choice_loader.py +93 -0
- python_liquid-3.0.0/liquid/loaders/dict_loader.py +56 -0
- python_liquid-3.0.0/liquid/loaders/file_system_loader.py +143 -0
- {python_liquid-2.3.5/liquid/builtin → python_liquid-3.0.0/liquid}/loaders/mixins.py +40 -52
- python_liquid-3.0.0/liquid/loaders/package_loader.py +110 -0
- python_liquid-3.0.0/liquid/tags/__init__.py +61 -0
- python_liquid-3.0.0/liquid/tags/assign.py +68 -0
- python_liquid-3.0.0/liquid/tags/capture.py +83 -0
- python_liquid-3.0.0/liquid/tags/case.py +199 -0
- python_liquid-3.0.0/liquid/tags/comment.py +56 -0
- python_liquid-3.0.0/liquid/tags/cycle.py +131 -0
- python_liquid-3.0.0/liquid/tags/decrement.py +55 -0
- python_liquid-3.0.0/liquid/tags/doc.py +56 -0
- python_liquid-3.0.0/liquid/tags/echo.py +65 -0
- python_liquid-3.0.0/liquid/tags/else_.py +53 -0
- python_liquid-3.0.0/liquid/tags/error.py +51 -0
- python_liquid-3.0.0/liquid/tags/extends.py +448 -0
- python_liquid-3.0.0/liquid/tags/for_.py +421 -0
- python_liquid-3.0.0/liquid/tags/if_.py +156 -0
- python_liquid-3.0.0/liquid/tags/ifchanged.py +69 -0
- python_liquid-3.0.0/liquid/tags/include.py +223 -0
- python_liquid-3.0.0/liquid/tags/increment.py +55 -0
- python_liquid-3.0.0/liquid/tags/inline_comment.py +70 -0
- python_liquid-3.0.0/liquid/tags/liquid.py +56 -0
- python_liquid-3.0.0/liquid/tags/macro.py +281 -0
- python_liquid-3.0.0/liquid/tags/output.py +58 -0
- python_liquid-3.0.0/liquid/tags/raw.py +60 -0
- python_liquid-3.0.0/liquid/tags/render.py +245 -0
- python_liquid-3.0.0/liquid/tags/tablerow.py +254 -0
- python_liquid-3.0.0/liquid/tags/template_comment.py +56 -0
- python_liquid-3.0.0/liquid/tags/translate.py +316 -0
- python_liquid-3.0.0/liquid/tags/unless.py +121 -0
- python_liquid-3.0.0/liquid/tags/with_.py +83 -0
- python_liquid-3.0.0/liquid/tokens.py +370 -0
- python_liquid-3.0.0/pyproject.toml +167 -0
- python_liquid-2.3.5/liquid/__init__.py +0 -246
- python_liquid-2.3.5/liquid/analyze_tags.py +0 -214
- python_liquid-2.3.5/liquid/ast.py +0 -252
- python_liquid-2.3.5/liquid/builtin/__init__.py +0 -203
- python_liquid-2.3.5/liquid/builtin/content.py +0 -41
- python_liquid-2.3.5/liquid/builtin/drops/__init__.py +0 -3
- python_liquid-2.3.5/liquid/builtin/drops/drops.py +0 -13
- python_liquid-2.3.5/liquid/builtin/expressions/__init__.py +0 -47
- python_liquid-2.3.5/liquid/builtin/expressions/_tokenize.py +0 -186
- python_liquid-2.3.5/liquid/builtin/expressions/arguments.py +0 -207
- python_liquid-2.3.5/liquid/builtin/expressions/filtered.py +0 -387
- python_liquid-2.3.5/liquid/builtin/expressions/logical.py +0 -672
- python_liquid-2.3.5/liquid/builtin/expressions/loop.py +0 -275
- python_liquid-2.3.5/liquid/builtin/expressions/path.py +0 -163
- python_liquid-2.3.5/liquid/builtin/expressions/primitive.py +0 -417
- python_liquid-2.3.5/liquid/builtin/filters/__init__.py +0 -0
- python_liquid-2.3.5/liquid/builtin/filters/array.py +0 -329
- python_liquid-2.3.5/liquid/builtin/filters/extra.py +0 -83
- python_liquid-2.3.5/liquid/builtin/filters/math.py +0 -129
- python_liquid-2.3.5/liquid/builtin/filters/misc.py +0 -137
- python_liquid-2.3.5/liquid/builtin/filters/string.py +0 -416
- python_liquid-2.3.5/liquid/builtin/illegal.py +0 -28
- python_liquid-2.3.5/liquid/builtin/loaders/__init__.py +0 -0
- python_liquid-2.3.5/liquid/builtin/loaders/caching_file_system_loader.py +0 -61
- python_liquid-2.3.5/liquid/builtin/loaders/choice_loader.py +0 -94
- python_liquid-2.3.5/liquid/builtin/loaders/dict_loader.py +0 -64
- python_liquid-2.3.5/liquid/builtin/loaders/file_system_loader.py +0 -146
- python_liquid-2.3.5/liquid/builtin/loaders/package_loader.py +0 -132
- python_liquid-2.3.5/liquid/builtin/output.py +0 -74
- python_liquid-2.3.5/liquid/builtin/tags/__init__.py +0 -0
- python_liquid-2.3.5/liquid/builtin/tags/assign_tag.py +0 -75
- python_liquid-2.3.5/liquid/builtin/tags/capture_tag.py +0 -98
- python_liquid-2.3.5/liquid/builtin/tags/case_tag.py +0 -287
- python_liquid-2.3.5/liquid/builtin/tags/comment_tag.py +0 -77
- python_liquid-2.3.5/liquid/builtin/tags/cycle_tag.py +0 -132
- python_liquid-2.3.5/liquid/builtin/tags/decrement_tag.py +0 -59
- python_liquid-2.3.5/liquid/builtin/tags/doc_tag.py +0 -68
- python_liquid-2.3.5/liquid/builtin/tags/echo_tag.py +0 -45
- python_liquid-2.3.5/liquid/builtin/tags/for_tag.py +0 -337
- python_liquid-2.3.5/liquid/builtin/tags/if_tag.py +0 -209
- python_liquid-2.3.5/liquid/builtin/tags/ifchanged_tag.py +0 -94
- python_liquid-2.3.5/liquid/builtin/tags/include_tag.py +0 -251
- python_liquid-2.3.5/liquid/builtin/tags/increment_tag.py +0 -60
- python_liquid-2.3.5/liquid/builtin/tags/inline_comment_tag.py +0 -47
- python_liquid-2.3.5/liquid/builtin/tags/liquid_tag.py +0 -183
- python_liquid-2.3.5/liquid/builtin/tags/render_tag.py +0 -371
- python_liquid-2.3.5/liquid/builtin/tags/tablerow_tag.py +0 -320
- python_liquid-2.3.5/liquid/builtin/tags/unless_tag.py +0 -218
- python_liquid-2.3.5/liquid/context.py +0 -615
- python_liquid-2.3.5/liquid/environment.py +0 -611
- python_liquid-2.3.5/liquid/exceptions.py +0 -289
- python_liquid-2.3.5/liquid/expression.py +0 -41
- python_liquid-2.3.5/liquid/extra/__init__.py +0 -98
- python_liquid-2.3.5/liquid/extra/filters/__init__.py +0 -33
- python_liquid-2.3.5/liquid/extra/filters/_json.py +0 -33
- python_liquid-2.3.5/liquid/extra/filters/array.py +0 -60
- python_liquid-2.3.5/liquid/extra/filters/babel.py +0 -552
- python_liquid-2.3.5/liquid/extra/filters/html.py +0 -32
- python_liquid-2.3.5/liquid/extra/filters/translate.py +0 -448
- python_liquid-2.3.5/liquid/extra/tags/__init__.py +0 -17
- python_liquid-2.3.5/liquid/extra/tags/_with.py +0 -80
- python_liquid-2.3.5/liquid/extra/tags/extends_tag.py +0 -576
- python_liquid-2.3.5/liquid/extra/tags/macro_tag.py +0 -270
- python_liquid-2.3.5/liquid/extra/tags/snippet_tag.py +0 -107
- python_liquid-2.3.5/liquid/extra/tags/translate_tag.py +0 -388
- python_liquid-2.3.5/liquid/filter.py +0 -230
- python_liquid-2.3.5/liquid/future/__init__.py +0 -3
- python_liquid-2.3.5/liquid/future/environment.py +0 -30
- python_liquid-2.3.5/liquid/future/filters/__init__.py +0 -1
- python_liquid-2.3.5/liquid/future/tags/__init__.py +0 -1
- python_liquid-2.3.5/liquid/lex.py +0 -260
- python_liquid-2.3.5/liquid/limits.py +0 -66
- python_liquid-2.3.5/liquid/loader.py +0 -141
- python_liquid-2.3.5/liquid/messages.py +0 -357
- python_liquid-2.3.5/liquid/mode.py +0 -12
- python_liquid-2.3.5/liquid/output.py +0 -35
- python_liquid-2.3.5/liquid/parser.py +0 -119
- python_liquid-2.3.5/liquid/span.py +0 -35
- python_liquid-2.3.5/liquid/static_analysis.py +0 -443
- python_liquid-2.3.5/liquid/stream.py +0 -148
- python_liquid-2.3.5/liquid/stringify.py +0 -31
- python_liquid-2.3.5/liquid/tag.py +0 -47
- python_liquid-2.3.5/liquid/template.py +0 -658
- python_liquid-2.3.5/liquid/token.py +0 -145
- python_liquid-2.3.5/liquid/undefined.py +0 -218
- python_liquid-2.3.5/liquid/utils/__init__.py +0 -15
- python_liquid-2.3.5/liquid/utils/html.py +0 -57
- python_liquid-2.3.5/liquid/utils/text.py +0 -28
- python_liquid-2.3.5/pyproject.toml +0 -234
- {python_liquid-2.3.5 → python_liquid-3.0.0}/liquid/py.typed +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: python-liquid
|
|
3
|
-
Version:
|
|
3
|
+
Version: 3.0.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/
|
|
@@ -13,22 +13,18 @@ License-File: LICENSE
|
|
|
13
13
|
Classifier: Development Status :: 5 - Production/Stable
|
|
14
14
|
Classifier: Intended Audience :: Developers
|
|
15
15
|
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
-
Classifier: Programming Language :: Python
|
|
17
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
18
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python
|
|
20
17
|
Classifier: Programming Language :: Python :: 3.12
|
|
21
18
|
Classifier: Programming Language :: Python :: 3.13
|
|
22
19
|
Classifier: Programming Language :: Python :: 3.14
|
|
23
20
|
Classifier: Programming Language :: Python :: 3.15
|
|
24
21
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
25
22
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
26
|
-
Requires-Python: >=3.
|
|
23
|
+
Requires-Python: >=3.12
|
|
27
24
|
Requires-Dist: babel>=2
|
|
28
|
-
Requires-Dist: importlib-resources>=5.12
|
|
29
25
|
Requires-Dist: markupsafe>=3
|
|
30
|
-
Requires-Dist: python-dateutil
|
|
31
|
-
Requires-Dist:
|
|
26
|
+
Requires-Dist: python-dateutil
|
|
27
|
+
Requires-Dist: tzdata
|
|
32
28
|
Description-Content-Type: text/markdown
|
|
33
29
|
|
|
34
30
|
<h1 align="center">Python Liquid</h1>
|
|
@@ -77,28 +73,37 @@ We follow <a href="https://github.com/Shopify/liquid">Shopify/Liquid</a> closely
|
|
|
77
73
|
|
|
78
74
|
## Install
|
|
79
75
|
|
|
80
|
-
Install
|
|
76
|
+
Install `python-liquid` from [PyPi](https://pypi.org/project/python-liquid) using your favorite package manager.
|
|
77
|
+
|
|
78
|
+
**pip**
|
|
79
|
+
|
|
80
|
+
```shell
|
|
81
|
+
pip install python-liquid
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
**uv**
|
|
81
85
|
|
|
82
86
|
```shell
|
|
83
|
-
|
|
87
|
+
uv add python-liquid
|
|
84
88
|
```
|
|
85
89
|
|
|
86
|
-
|
|
90
|
+
**pipenv**
|
|
87
91
|
|
|
88
92
|
```shell
|
|
89
|
-
|
|
93
|
+
pipenv install -u python-liquid
|
|
90
94
|
```
|
|
91
95
|
|
|
92
|
-
|
|
96
|
+
**conda**
|
|
93
97
|
|
|
94
98
|
```shell
|
|
95
|
-
|
|
99
|
+
conda install -c conda-forge python-liquid
|
|
96
100
|
```
|
|
97
101
|
|
|
98
102
|
## Links
|
|
99
103
|
|
|
100
104
|
- Documentation: https://jg-rp.github.io/liquid/
|
|
101
105
|
- Documentation for Python Liquid version 1.x: https://jg-rp.github.io/python-liquid-docs-archive/
|
|
106
|
+
- Documentation for Python Liquid version 2.x: https://github.com/jg-rp/liquid/blob/v2.3.6/docs/index.md
|
|
102
107
|
- Change Log: https://github.com/jg-rp/liquid/blob/main/CHANGES.md
|
|
103
108
|
- PyPi: https://pypi.org/project/python-liquid/
|
|
104
109
|
- Source Code: https://github.com/jg-rp/liquid
|
|
@@ -115,18 +120,17 @@ $ conda install -c conda-forge python-liquid
|
|
|
115
120
|
|
|
116
121
|
### `render()`
|
|
117
122
|
|
|
118
|
-
|
|
123
|
+
Use the package-level `liquid.render()` function to render a template with Liquid's default configuration. The first argument is template source code and the second is a dictionary of template variables.
|
|
119
124
|
|
|
120
125
|
```python
|
|
121
|
-
|
|
126
|
+
import liquid
|
|
122
127
|
|
|
123
|
-
print(render("Hello, {{ you }}!", you
|
|
124
|
-
# Hello, World!
|
|
128
|
+
print(liquid.render("Hello, {{ you }}!", {"you": "World"})) # Hello, World!
|
|
125
129
|
```
|
|
126
130
|
|
|
127
131
|
### `parse()`
|
|
128
132
|
|
|
129
|
-
|
|
133
|
+
Use `liquid.parse()` to get an instance of `liquid.Template`, which can be rendered multiple times with different data.
|
|
130
134
|
|
|
131
135
|
```python
|
|
132
136
|
from liquid import parse
|
|
@@ -138,33 +142,22 @@ print(template.render(you="Liquid")) # Hello, Liquid!
|
|
|
138
142
|
|
|
139
143
|
### Configure
|
|
140
144
|
|
|
141
|
-
|
|
145
|
+
You'll need to create an instance of `liquid.Environment` to configure Liquid, then load and render templates from that.
|
|
142
146
|
|
|
143
147
|
```python
|
|
144
|
-
from liquid import CachingFileSystemLoader
|
|
145
|
-
from liquid import Environment
|
|
148
|
+
from liquid import Environment, CachingFileSystemLoader
|
|
146
149
|
|
|
147
150
|
env = Environment(
|
|
148
|
-
|
|
149
|
-
|
|
151
|
+
autoescape=True,
|
|
152
|
+
loader=CachingFileSystemLoader("./templates")
|
|
150
153
|
)
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
Then, using `env.parse()` or `env.get_template()`, we can create a `BoundTemplate` from a string or read from the file system, respectively.
|
|
154
|
-
|
|
155
|
-
```python
|
|
156
|
-
# ... continued from above
|
|
157
|
-
template = env.parse("Hello, {{ you }}!")
|
|
158
|
-
print(template.render(you="World")) # Hello, World!
|
|
159
154
|
|
|
160
|
-
|
|
161
|
-
another_template = env.
|
|
162
|
-
data = {"some": {"thing": [1, 2, 3]}}
|
|
163
|
-
result = another_template.render(**data)
|
|
155
|
+
template = env.get_template("index.liquid")
|
|
156
|
+
another_template = env.parse("{% render 'greeting' %}, World!")
|
|
164
157
|
```
|
|
165
158
|
|
|
166
|
-
|
|
159
|
+
See [docs](https://jg-rp.github.io/liquid/).
|
|
167
160
|
|
|
168
161
|
## Contributing
|
|
169
162
|
|
|
170
|
-
Please see [Contributing to Python Liquid](https://github.com/jg-rp/liquid/blob/main/
|
|
163
|
+
Please see [Contributing to Python Liquid](https://github.com/jg-rp/liquid/blob/main/CONTRIBUTING.md).
|
|
@@ -44,28 +44,37 @@ We follow <a href="https://github.com/Shopify/liquid">Shopify/Liquid</a> closely
|
|
|
44
44
|
|
|
45
45
|
## Install
|
|
46
46
|
|
|
47
|
-
Install
|
|
47
|
+
Install `python-liquid` from [PyPi](https://pypi.org/project/python-liquid) using your favorite package manager.
|
|
48
|
+
|
|
49
|
+
**pip**
|
|
50
|
+
|
|
51
|
+
```shell
|
|
52
|
+
pip install python-liquid
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
**uv**
|
|
48
56
|
|
|
49
57
|
```shell
|
|
50
|
-
|
|
58
|
+
uv add python-liquid
|
|
51
59
|
```
|
|
52
60
|
|
|
53
|
-
|
|
61
|
+
**pipenv**
|
|
54
62
|
|
|
55
63
|
```shell
|
|
56
|
-
|
|
64
|
+
pipenv install -u python-liquid
|
|
57
65
|
```
|
|
58
66
|
|
|
59
|
-
|
|
67
|
+
**conda**
|
|
60
68
|
|
|
61
69
|
```shell
|
|
62
|
-
|
|
70
|
+
conda install -c conda-forge python-liquid
|
|
63
71
|
```
|
|
64
72
|
|
|
65
73
|
## Links
|
|
66
74
|
|
|
67
75
|
- Documentation: https://jg-rp.github.io/liquid/
|
|
68
76
|
- Documentation for Python Liquid version 1.x: https://jg-rp.github.io/python-liquid-docs-archive/
|
|
77
|
+
- Documentation for Python Liquid version 2.x: https://github.com/jg-rp/liquid/blob/v2.3.6/docs/index.md
|
|
69
78
|
- Change Log: https://github.com/jg-rp/liquid/blob/main/CHANGES.md
|
|
70
79
|
- PyPi: https://pypi.org/project/python-liquid/
|
|
71
80
|
- Source Code: https://github.com/jg-rp/liquid
|
|
@@ -82,18 +91,17 @@ $ conda install -c conda-forge python-liquid
|
|
|
82
91
|
|
|
83
92
|
### `render()`
|
|
84
93
|
|
|
85
|
-
|
|
94
|
+
Use the package-level `liquid.render()` function to render a template with Liquid's default configuration. The first argument is template source code and the second is a dictionary of template variables.
|
|
86
95
|
|
|
87
96
|
```python
|
|
88
|
-
|
|
97
|
+
import liquid
|
|
89
98
|
|
|
90
|
-
print(render("Hello, {{ you }}!", you
|
|
91
|
-
# Hello, World!
|
|
99
|
+
print(liquid.render("Hello, {{ you }}!", {"you": "World"})) # Hello, World!
|
|
92
100
|
```
|
|
93
101
|
|
|
94
102
|
### `parse()`
|
|
95
103
|
|
|
96
|
-
|
|
104
|
+
Use `liquid.parse()` to get an instance of `liquid.Template`, which can be rendered multiple times with different data.
|
|
97
105
|
|
|
98
106
|
```python
|
|
99
107
|
from liquid import parse
|
|
@@ -105,33 +113,22 @@ print(template.render(you="Liquid")) # Hello, Liquid!
|
|
|
105
113
|
|
|
106
114
|
### Configure
|
|
107
115
|
|
|
108
|
-
|
|
116
|
+
You'll need to create an instance of `liquid.Environment` to configure Liquid, then load and render templates from that.
|
|
109
117
|
|
|
110
118
|
```python
|
|
111
|
-
from liquid import CachingFileSystemLoader
|
|
112
|
-
from liquid import Environment
|
|
119
|
+
from liquid import Environment, CachingFileSystemLoader
|
|
113
120
|
|
|
114
121
|
env = Environment(
|
|
115
|
-
|
|
116
|
-
|
|
122
|
+
autoescape=True,
|
|
123
|
+
loader=CachingFileSystemLoader("./templates")
|
|
117
124
|
)
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
Then, using `env.parse()` or `env.get_template()`, we can create a `BoundTemplate` from a string or read from the file system, respectively.
|
|
121
|
-
|
|
122
|
-
```python
|
|
123
|
-
# ... continued from above
|
|
124
|
-
template = env.parse("Hello, {{ you }}!")
|
|
125
|
-
print(template.render(you="World")) # Hello, World!
|
|
126
125
|
|
|
127
|
-
|
|
128
|
-
another_template = env.
|
|
129
|
-
data = {"some": {"thing": [1, 2, 3]}}
|
|
130
|
-
result = another_template.render(**data)
|
|
126
|
+
template = env.get_template("index.liquid")
|
|
127
|
+
another_template = env.parse("{% render 'greeting' %}, World!")
|
|
131
128
|
```
|
|
132
129
|
|
|
133
|
-
|
|
130
|
+
See [docs](https://jg-rp.github.io/liquid/).
|
|
134
131
|
|
|
135
132
|
## Contributing
|
|
136
133
|
|
|
137
|
-
Please see [Contributing to Python Liquid](https://github.com/jg-rp/liquid/blob/main/
|
|
134
|
+
Please see [Contributing to Python Liquid](https://github.com/jg-rp/liquid/blob/main/CONTRIBUTING.md).
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "3.0.0"
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
from collections.abc import Iterator, Mapping
|
|
2
|
+
from typing import Any, TextIO
|
|
3
|
+
|
|
4
|
+
from ._base_tag import AbstractTag
|
|
5
|
+
from ._context import RenderContext
|
|
6
|
+
from ._drop import (
|
|
7
|
+
ContextHint,
|
|
8
|
+
LiquidAsyncIterable,
|
|
9
|
+
LiquidAsyncObject,
|
|
10
|
+
LiquidIterable,
|
|
11
|
+
LiquidObject,
|
|
12
|
+
LiquidPrimitive,
|
|
13
|
+
)
|
|
14
|
+
from ._filter import Filter, FilterContext
|
|
15
|
+
from ._io import StringBuffer
|
|
16
|
+
from ._lax_parser_mixin import LaxParserMixin
|
|
17
|
+
from ._lexer import Lexer
|
|
18
|
+
from ._lexer_extended import ExtendedLexer
|
|
19
|
+
from ._lexer_legacy import LegacyLexer
|
|
20
|
+
from ._loader import Loader, TemplateSource
|
|
21
|
+
from ._markup import (
|
|
22
|
+
Block,
|
|
23
|
+
Expression,
|
|
24
|
+
Markup,
|
|
25
|
+
Node,
|
|
26
|
+
Partial,
|
|
27
|
+
Scope,
|
|
28
|
+
Tag,
|
|
29
|
+
render_block,
|
|
30
|
+
render_block_async,
|
|
31
|
+
)
|
|
32
|
+
from ._messages import (
|
|
33
|
+
MessageTuple,
|
|
34
|
+
Translations,
|
|
35
|
+
extract_from_template,
|
|
36
|
+
extract_from_templates,
|
|
37
|
+
)
|
|
38
|
+
from ._nothing import NOTHING
|
|
39
|
+
from ._parser import Parser
|
|
40
|
+
from ._parser_extended import ExtendedParser
|
|
41
|
+
from ._parser_legacy import LegacyParser
|
|
42
|
+
from ._resource_limits import ResourceLimits
|
|
43
|
+
from ._slice import slice_range, slice_sequence
|
|
44
|
+
from ._static_analysis import Segments, TemplateAnalysis
|
|
45
|
+
from ._template import Template
|
|
46
|
+
from .drops import (
|
|
47
|
+
AsyncIterableDrop,
|
|
48
|
+
FalsyStrictUndefined,
|
|
49
|
+
IterableDrop,
|
|
50
|
+
StrictUndefined,
|
|
51
|
+
Undefined,
|
|
52
|
+
)
|
|
53
|
+
from .environment import Environment
|
|
54
|
+
from .loaders import (
|
|
55
|
+
CachingChoiceLoader,
|
|
56
|
+
CachingDictLoader,
|
|
57
|
+
CachingFileSystemLoader,
|
|
58
|
+
CachingLoaderMixin,
|
|
59
|
+
ChoiceLoader,
|
|
60
|
+
DictLoader,
|
|
61
|
+
FileSystemLoader,
|
|
62
|
+
PackageLoader,
|
|
63
|
+
)
|
|
64
|
+
from .tokens import TOKEN_NAMES, Token, TokenKind, span, token_value
|
|
65
|
+
|
|
66
|
+
__all__ = (
|
|
67
|
+
"NOTHING",
|
|
68
|
+
"TOKEN_NAMES",
|
|
69
|
+
"AbstractTag",
|
|
70
|
+
"AsyncIterableDrop",
|
|
71
|
+
"Block",
|
|
72
|
+
"CachingChoiceLoader",
|
|
73
|
+
"CachingDictLoader",
|
|
74
|
+
"CachingFileSystemLoader",
|
|
75
|
+
"CachingLoaderMixin",
|
|
76
|
+
"ChoiceLoader",
|
|
77
|
+
"ContextHint",
|
|
78
|
+
"DictLoader",
|
|
79
|
+
"Environment",
|
|
80
|
+
"Expression",
|
|
81
|
+
"ExtendedLexer",
|
|
82
|
+
"ExtendedParser",
|
|
83
|
+
"FalsyStrictUndefined",
|
|
84
|
+
"FileSystemLoader",
|
|
85
|
+
"Filter",
|
|
86
|
+
"FilterContext",
|
|
87
|
+
"IterableDrop",
|
|
88
|
+
"LaxExtendedParser",
|
|
89
|
+
"LaxLegacyParser",
|
|
90
|
+
"LaxParserMixin",
|
|
91
|
+
"LegacyLexer",
|
|
92
|
+
"LegacyParser",
|
|
93
|
+
"Lexer",
|
|
94
|
+
"LiquidAsyncIterable",
|
|
95
|
+
"LiquidAsyncObject",
|
|
96
|
+
"LiquidIterable",
|
|
97
|
+
"LiquidObject",
|
|
98
|
+
"LiquidPrimitive",
|
|
99
|
+
"Loader",
|
|
100
|
+
"Markup",
|
|
101
|
+
"Node",
|
|
102
|
+
"PackageLoader",
|
|
103
|
+
"Parser",
|
|
104
|
+
"Partial",
|
|
105
|
+
"RenderContext",
|
|
106
|
+
"ResourceLimits",
|
|
107
|
+
"Scope",
|
|
108
|
+
"Segments",
|
|
109
|
+
"StrictUndefined",
|
|
110
|
+
"StringBuffer",
|
|
111
|
+
"Tag",
|
|
112
|
+
"Template",
|
|
113
|
+
"TemplateAnalysis",
|
|
114
|
+
"TemplateSource",
|
|
115
|
+
"Token",
|
|
116
|
+
"TokenKind",
|
|
117
|
+
"Translations",
|
|
118
|
+
"Undefined",
|
|
119
|
+
"extract_from_templates",
|
|
120
|
+
"render_block",
|
|
121
|
+
"render_block_async",
|
|
122
|
+
"slice_range",
|
|
123
|
+
"slice_sequence",
|
|
124
|
+
"span",
|
|
125
|
+
"token_value",
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
DEFAULT_ENVIRONMENT = Environment()
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def parse(
|
|
133
|
+
source: str,
|
|
134
|
+
*,
|
|
135
|
+
name: str = "",
|
|
136
|
+
globals: Mapping[str, Any] | None = None,
|
|
137
|
+
) -> Template:
|
|
138
|
+
"""Parse template source code `source` using the default Liquid environment.
|
|
139
|
+
|
|
140
|
+
Parameters
|
|
141
|
+
----------
|
|
142
|
+
source
|
|
143
|
+
Template source code.
|
|
144
|
+
name
|
|
145
|
+
A name for the template that will appear in error messages.
|
|
146
|
+
globals
|
|
147
|
+
Variables to pin to the resulting template.
|
|
148
|
+
"""
|
|
149
|
+
return DEFAULT_ENVIRONMENT.parse(source, name=name, globals=globals)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def render(source: str, data: Mapping[str, Any] | None = None) -> str:
|
|
153
|
+
"""Parse and render `source` with variables from `data` using the default environment.
|
|
154
|
+
|
|
155
|
+
Parameters
|
|
156
|
+
----------
|
|
157
|
+
source
|
|
158
|
+
Template source code.
|
|
159
|
+
data
|
|
160
|
+
Template variables.
|
|
161
|
+
"""
|
|
162
|
+
return DEFAULT_ENVIRONMENT.render(source, data)
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
async def render_async(source: str, data: Mapping[str, Any] | None = None) -> str:
|
|
166
|
+
"""Parse and render `source` asynchronously with variables from `data` using the
|
|
167
|
+
default environment.
|
|
168
|
+
|
|
169
|
+
Parameters
|
|
170
|
+
----------
|
|
171
|
+
source
|
|
172
|
+
Template source code.
|
|
173
|
+
data
|
|
174
|
+
Template variables.
|
|
175
|
+
"""
|
|
176
|
+
return await DEFAULT_ENVIRONMENT.render_async(source, data)
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
class LaxLegacyParser(LaxParserMixin, LegacyParser):
|
|
180
|
+
"""A legacy parser that suppresses Liquid syntax errors.
|
|
181
|
+
|
|
182
|
+
Use ``Template.errors()`` to get a list of available ``LiquidSyntaxError`` instances.
|
|
183
|
+
"""
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
class LaxExtendedParser(LaxParserMixin, ExtendedParser):
|
|
187
|
+
"""An extended parser that suppresses Liquid syntax errors.
|
|
188
|
+
|
|
189
|
+
Use ``Template.errors()`` to get a list of available ``LiquidSyntaxError`` instances.
|
|
190
|
+
"""
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def extract_liquid(
|
|
194
|
+
fileobj: TextIO,
|
|
195
|
+
keywords: list[str],
|
|
196
|
+
comment_tags: list[str] | None = None,
|
|
197
|
+
options: Mapping[str, Any] | None = None,
|
|
198
|
+
) -> Iterator[MessageTuple]:
|
|
199
|
+
"""A babel compatible translation message extraction method for Liquid templates.
|
|
200
|
+
|
|
201
|
+
See https://babel.pocoo.org/en/latest/messages.html
|
|
202
|
+
|
|
203
|
+
Keywords are the names of Liquid filters or tags operating on translatable strings.
|
|
204
|
+
For a filter to contribute to message extraction, it must also appear as a child of
|
|
205
|
+
a `FilteredExpression` and be a `TranslatableFilter`. Similarly, tags must produce a
|
|
206
|
+
node that is a `TranslatableTag`.
|
|
207
|
+
|
|
208
|
+
Where a Liquid comment contains a prefix in `comment_tags`, the comment will be
|
|
209
|
+
attached to the translatable filter or tag immediately following the comment. Python
|
|
210
|
+
Liquid's non-standard shorthand comments are not supported.
|
|
211
|
+
|
|
212
|
+
Use ``extract_from_template`` to extract messages from an existing template bound to
|
|
213
|
+
an existing environment.
|
|
214
|
+
"""
|
|
215
|
+
template = Environment(extra=True).parse(fileobj.read())
|
|
216
|
+
return extract_from_template(
|
|
217
|
+
template=template,
|
|
218
|
+
keywords=keywords,
|
|
219
|
+
comment_tags=comment_tags,
|
|
220
|
+
)
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from abc import ABC, abstractmethod
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
from ._context import RenderContext
|
|
8
|
+
from ._io import StringBuffer
|
|
9
|
+
from ._markup import Expression, Markup, Partial
|
|
10
|
+
from ._parser import Parser
|
|
11
|
+
from .expressions import Name
|
|
12
|
+
from .tokens import Token
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class AbstractTag(ABC):
|
|
16
|
+
"""An abstract class for implementing custom tags.
|
|
17
|
+
|
|
18
|
+
It is not necessary to inherit from `AbstractTag` when implementing custom tags, but
|
|
19
|
+
it can be convenient if you're not interested in methods supporting static template
|
|
20
|
+
analysis, saving you from writing several empty methods.
|
|
21
|
+
|
|
22
|
+
Internally we use the `Markup` and `Tag` protocols, without a required base class.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
@classmethod
|
|
26
|
+
@abstractmethod
|
|
27
|
+
def parse(cls, token: Token, parser: Parser) -> Markup:
|
|
28
|
+
"""Parse tokens or text from `parser` into a markup node."""
|
|
29
|
+
|
|
30
|
+
@abstractmethod
|
|
31
|
+
def render(self, context: RenderContext, buffer: StringBuffer) -> None:
|
|
32
|
+
"""Render this node to `buffer` using data from `context`."""
|
|
33
|
+
|
|
34
|
+
@abstractmethod
|
|
35
|
+
async def render_async(self, context: RenderContext, buffer: StringBuffer) -> None:
|
|
36
|
+
"""Render this node to `buffer` asynchronously using data from `context`."""
|
|
37
|
+
|
|
38
|
+
def children(self) -> list[Markup]:
|
|
39
|
+
"""Returns markup nodes that are direct children of this node in the syntax tree.
|
|
40
|
+
|
|
41
|
+
This is used to traverse template syntax trees during static analysis.
|
|
42
|
+
"""
|
|
43
|
+
return []
|
|
44
|
+
|
|
45
|
+
def expressions(self) -> list[Expression]:
|
|
46
|
+
"""Return expression owned by this node."""
|
|
47
|
+
return []
|
|
48
|
+
|
|
49
|
+
def block_scope(self) -> list[Name]:
|
|
50
|
+
"""Return variable names that are in scope for the duration of this node's block.
|
|
51
|
+
|
|
52
|
+
This is used during static analysis to isolate and report global variables.
|
|
53
|
+
"""
|
|
54
|
+
return []
|
|
55
|
+
|
|
56
|
+
def template_scope(self) -> list[Name]:
|
|
57
|
+
"""Return variable names that this tag adds to the template scope."""
|
|
58
|
+
return []
|
|
59
|
+
|
|
60
|
+
def partials(self, context: RenderContext) -> list[Partial]:
|
|
61
|
+
"""Return meta data about partial templates rendered from this node."""
|
|
62
|
+
return []
|
|
63
|
+
|
|
64
|
+
async def partials_async(self, context: RenderContext) -> list[Partial]:
|
|
65
|
+
"""Return meta data about partial templates rendered from this node."""
|
|
66
|
+
return []
|
|
@@ -3,26 +3,29 @@
|
|
|
3
3
|
Based on "A greatly simplified read-only version of Chainmap" by Raymond Hettinger.
|
|
4
4
|
https://code.activestate.com/recipes/305268/
|
|
5
5
|
"""
|
|
6
|
+
|
|
6
7
|
from collections import deque
|
|
8
|
+
from collections.abc import Iterator, Mapping
|
|
7
9
|
from itertools import chain
|
|
8
|
-
|
|
9
|
-
from
|
|
10
|
-
from typing import Mapping
|
|
10
|
+
|
|
11
|
+
from ._missing import MISSING
|
|
11
12
|
|
|
12
13
|
|
|
13
14
|
class ReadOnlyChainMap(Mapping[str, object]):
|
|
14
|
-
"""Combine multiple mappings for sequential lookup.
|
|
15
|
+
"""Combine multiple mappings for sequential lookup.
|
|
16
|
+
|
|
17
|
+
This chain map never raises a KeyError. It returns the MISSING sentinel
|
|
18
|
+
if a key does not exist in the chain.
|
|
19
|
+
"""
|
|
15
20
|
|
|
16
21
|
def __init__(self, *maps: Mapping[str, object]):
|
|
17
22
|
self._maps = deque(maps)
|
|
18
23
|
|
|
19
24
|
def __getitem__(self, key: str) -> object:
|
|
20
25
|
for mapping in self._maps:
|
|
21
|
-
|
|
26
|
+
if key in mapping:
|
|
22
27
|
return mapping[key]
|
|
23
|
-
|
|
24
|
-
pass
|
|
25
|
-
raise KeyError(key)
|
|
28
|
+
return MISSING
|
|
26
29
|
|
|
27
30
|
def __iter__(self) -> Iterator[str]:
|
|
28
31
|
return chain(*self._maps)
|
|
@@ -30,21 +33,17 @@ class ReadOnlyChainMap(Mapping[str, object]):
|
|
|
30
33
|
def __len__(self) -> int:
|
|
31
34
|
return sum(len(_map) for _map in self._maps)
|
|
32
35
|
|
|
36
|
+
def __contains__(self, key: object) -> bool:
|
|
37
|
+
return any(key in mapping for mapping in self._maps)
|
|
38
|
+
|
|
33
39
|
def size(self) -> int:
|
|
34
|
-
"""Return the number of maps in the chain."""
|
|
35
40
|
return len(self._maps)
|
|
36
41
|
|
|
37
|
-
def get(self, key: str, default: object =
|
|
38
|
-
|
|
39
|
-
try:
|
|
40
|
-
return self[key]
|
|
41
|
-
except KeyError:
|
|
42
|
-
return default
|
|
42
|
+
def get(self, key: str, default: object = MISSING) -> object:
|
|
43
|
+
return self[key]
|
|
43
44
|
|
|
44
|
-
def push(self, namespace: Mapping[
|
|
45
|
-
"""Add a mapping to the front of the chain map."""
|
|
45
|
+
def push(self, namespace: Mapping[str, object]) -> None:
|
|
46
46
|
self._maps.appendleft(namespace)
|
|
47
47
|
|
|
48
|
-
def pop(self) -> Mapping[
|
|
49
|
-
"""Remove a mapping from the front of the chain map."""
|
|
48
|
+
def pop(self) -> Mapping[str, object]:
|
|
50
49
|
return self._maps.popleft()
|