python-liquid 2.3.6__py3-none-any.whl → 3.0.0__py3-none-any.whl
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.
- liquid/__about__.py +1 -0
- liquid/__init__.py +161 -187
- liquid/_base_tag.py +66 -0
- liquid/{utils/chain_map.py → _chain_map.py} +18 -19
- liquid/_context.py +465 -0
- liquid/_drop.py +108 -0
- liquid/_filter.py +174 -0
- liquid/_io.py +18 -0
- liquid/_lax_parser_mixin.py +100 -0
- liquid/_lexer.py +93 -0
- liquid/_lexer_extended.py +623 -0
- liquid/_lexer_legacy.py +536 -0
- liquid/_loader.py +84 -0
- liquid/{utils/lru_cache.py → _lru_cache.py} +28 -36
- liquid/_markup.py +253 -0
- liquid/_messages.py +292 -0
- liquid/_missing.py +3 -0
- liquid/_nothing.py +28 -0
- liquid/_parser.py +460 -0
- liquid/_parser_extended.py +293 -0
- liquid/_parser_legacy.py +819 -0
- liquid/_resource_limits.py +50 -0
- liquid/_slice.py +41 -0
- liquid/_static_analysis.py +503 -0
- liquid/_strftime.py +186 -0
- liquid/_template.py +536 -0
- liquid/drops/__init__.py +20 -0
- liquid/drops/forloop.py +78 -0
- liquid/drops/iterable.py +25 -0
- liquid/drops/range.py +76 -0
- liquid/drops/self_.py +45 -0
- liquid/drops/tablerowloop.py +142 -0
- liquid/drops/undefined.py +228 -0
- liquid/environment.py +717 -551
- liquid/exceptions.py +67 -214
- liquid/expressions.py +1184 -0
- liquid/filters/__init__.py +134 -0
- liquid/filters/abs.py +7 -0
- liquid/filters/append.py +5 -0
- liquid/filters/at_least.py +9 -0
- liquid/filters/at_most.py +9 -0
- liquid/filters/babel.py +560 -0
- liquid/filters/base64.py +26 -0
- liquid/filters/capitalize.py +5 -0
- liquid/filters/ceil.py +8 -0
- liquid/filters/compact.py +25 -0
- liquid/filters/concat.py +11 -0
- liquid/filters/date.py +27 -0
- liquid/filters/default.py +25 -0
- liquid/filters/divided_by.py +21 -0
- liquid/filters/downcase.py +5 -0
- liquid/filters/escape.py +56 -0
- liquid/filters/find.py +56 -0
- liquid/filters/first.py +19 -0
- liquid/filters/floor.py +8 -0
- liquid/filters/html.py +23 -0
- liquid/filters/index.py +12 -0
- liquid/filters/join.py +13 -0
- liquid/filters/json_.py +30 -0
- liquid/filters/last.py +17 -0
- liquid/filters/map.py +5 -0
- liquid/filters/minus.py +13 -0
- liquid/filters/modulo.py +18 -0
- liquid/filters/newline_to_br.py +16 -0
- liquid/filters/plus.py +13 -0
- liquid/filters/prepend.py +5 -0
- liquid/filters/reject.py +19 -0
- liquid/filters/remove.py +36 -0
- liquid/filters/replace.py +32 -0
- liquid/filters/reverse.py +5 -0
- liquid/filters/round.py +35 -0
- liquid/filters/size.py +25 -0
- liquid/filters/slice.py +39 -0
- liquid/filters/sort.py +148 -0
- liquid/filters/split.py +34 -0
- liquid/filters/squish.py +9 -0
- liquid/filters/strip.py +13 -0
- liquid/filters/strip_html.py +19 -0
- liquid/filters/strip_newlines.py +17 -0
- liquid/filters/sum.py +21 -0
- liquid/filters/times.py +13 -0
- liquid/filters/translate.py +380 -0
- liquid/filters/truncate.py +39 -0
- liquid/filters/uniq.py +11 -0
- liquid/filters/upcase.py +5 -0
- liquid/filters/url.py +18 -0
- liquid/filters/where.py +18 -0
- liquid/loaders/__init__.py +17 -0
- liquid/loaders/caching_file_system_loader.py +64 -0
- liquid/loaders/choice_loader.py +93 -0
- liquid/loaders/dict_loader.py +56 -0
- liquid/{builtin/loaders → loaders}/file_system_loader.py +51 -55
- liquid/{builtin/loaders → loaders}/mixins.py +39 -51
- liquid/loaders/package_loader.py +110 -0
- liquid/tags/__init__.py +61 -0
- liquid/tags/assign.py +68 -0
- liquid/tags/capture.py +83 -0
- liquid/tags/case.py +199 -0
- liquid/tags/comment.py +56 -0
- liquid/tags/cycle.py +131 -0
- liquid/tags/decrement.py +55 -0
- liquid/tags/doc.py +56 -0
- liquid/tags/echo.py +65 -0
- liquid/tags/else_.py +53 -0
- liquid/tags/error.py +51 -0
- liquid/tags/extends.py +448 -0
- liquid/tags/for_.py +421 -0
- liquid/tags/if_.py +156 -0
- liquid/tags/ifchanged.py +69 -0
- liquid/tags/include.py +223 -0
- liquid/tags/increment.py +55 -0
- liquid/tags/inline_comment.py +70 -0
- liquid/tags/liquid.py +56 -0
- liquid/tags/macro.py +281 -0
- liquid/tags/output.py +58 -0
- liquid/tags/raw.py +60 -0
- liquid/tags/render.py +245 -0
- liquid/tags/tablerow.py +254 -0
- liquid/tags/template_comment.py +56 -0
- liquid/tags/translate.py +316 -0
- liquid/tags/unless.py +121 -0
- liquid/tags/with_.py +83 -0
- liquid/tokens.py +370 -0
- {python_liquid-2.3.6.dist-info → python_liquid-3.0.0.dist-info}/METADATA +32 -39
- python_liquid-3.0.0.dist-info/RECORD +128 -0
- {python_liquid-2.3.6.dist-info → python_liquid-3.0.0.dist-info}/WHEEL +1 -1
- {python_liquid-2.3.6.dist-info → python_liquid-3.0.0.dist-info}/licenses/LICENSE +1 -1
- liquid/analyze_tags.py +0 -214
- liquid/ast.py +0 -252
- liquid/builtin/__init__.py +0 -203
- liquid/builtin/content.py +0 -41
- liquid/builtin/drops/__init__.py +0 -3
- liquid/builtin/drops/drops.py +0 -13
- liquid/builtin/expressions/__init__.py +0 -47
- liquid/builtin/expressions/_tokenize.py +0 -186
- liquid/builtin/expressions/arguments.py +0 -207
- liquid/builtin/expressions/filtered.py +0 -387
- liquid/builtin/expressions/logical.py +0 -672
- liquid/builtin/expressions/loop.py +0 -275
- liquid/builtin/expressions/path.py +0 -163
- liquid/builtin/expressions/primitive.py +0 -417
- liquid/builtin/filters/__init__.py +0 -0
- liquid/builtin/filters/array.py +0 -329
- liquid/builtin/filters/extra.py +0 -83
- liquid/builtin/filters/math.py +0 -129
- liquid/builtin/filters/misc.py +0 -137
- liquid/builtin/filters/string.py +0 -416
- liquid/builtin/illegal.py +0 -28
- liquid/builtin/loaders/__init__.py +0 -0
- liquid/builtin/loaders/caching_file_system_loader.py +0 -61
- liquid/builtin/loaders/choice_loader.py +0 -94
- liquid/builtin/loaders/dict_loader.py +0 -64
- liquid/builtin/loaders/package_loader.py +0 -132
- liquid/builtin/output.py +0 -74
- liquid/builtin/tags/__init__.py +0 -0
- liquid/builtin/tags/assign_tag.py +0 -75
- liquid/builtin/tags/capture_tag.py +0 -98
- liquid/builtin/tags/case_tag.py +0 -287
- liquid/builtin/tags/comment_tag.py +0 -77
- liquid/builtin/tags/cycle_tag.py +0 -132
- liquid/builtin/tags/decrement_tag.py +0 -59
- liquid/builtin/tags/doc_tag.py +0 -68
- liquid/builtin/tags/echo_tag.py +0 -45
- liquid/builtin/tags/for_tag.py +0 -337
- liquid/builtin/tags/if_tag.py +0 -209
- liquid/builtin/tags/ifchanged_tag.py +0 -94
- liquid/builtin/tags/include_tag.py +0 -251
- liquid/builtin/tags/increment_tag.py +0 -60
- liquid/builtin/tags/inline_comment_tag.py +0 -47
- liquid/builtin/tags/liquid_tag.py +0 -183
- liquid/builtin/tags/render_tag.py +0 -371
- liquid/builtin/tags/tablerow_tag.py +0 -320
- liquid/builtin/tags/unless_tag.py +0 -218
- liquid/context.py +0 -615
- liquid/expression.py +0 -41
- liquid/extra/__init__.py +0 -98
- liquid/extra/filters/__init__.py +0 -33
- liquid/extra/filters/_json.py +0 -33
- liquid/extra/filters/array.py +0 -60
- liquid/extra/filters/babel.py +0 -552
- liquid/extra/filters/html.py +0 -32
- liquid/extra/filters/translate.py +0 -448
- liquid/extra/tags/__init__.py +0 -17
- liquid/extra/tags/_with.py +0 -80
- liquid/extra/tags/extends_tag.py +0 -576
- liquid/extra/tags/macro_tag.py +0 -270
- liquid/extra/tags/snippet_tag.py +0 -107
- liquid/extra/tags/translate_tag.py +0 -388
- liquid/filter.py +0 -230
- liquid/future/__init__.py +0 -3
- liquid/future/environment.py +0 -30
- liquid/future/filters/__init__.py +0 -1
- liquid/future/tags/__init__.py +0 -1
- liquid/lex.py +0 -260
- liquid/limits.py +0 -66
- liquid/loader.py +0 -141
- liquid/messages.py +0 -357
- liquid/mode.py +0 -12
- liquid/output.py +0 -35
- liquid/parser.py +0 -119
- liquid/span.py +0 -35
- liquid/static_analysis.py +0 -443
- liquid/stream.py +0 -148
- liquid/stringify.py +0 -31
- liquid/tag.py +0 -47
- liquid/template.py +0 -658
- liquid/token.py +0 -145
- liquid/undefined.py +0 -218
- liquid/utils/__init__.py +0 -15
- liquid/utils/html.py +0 -57
- liquid/utils/text.py +0 -28
- python_liquid-2.3.6.dist-info/RECORD +0 -96
liquid/analyze_tags.py
DELETED
|
@@ -1,214 +0,0 @@
|
|
|
1
|
-
"""Analyze template tags from tokenized source text."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
from collections import defaultdict
|
|
6
|
-
from typing import TYPE_CHECKING
|
|
7
|
-
from typing import DefaultDict
|
|
8
|
-
from typing import Iterable
|
|
9
|
-
from typing import Mapping
|
|
10
|
-
from typing import Optional
|
|
11
|
-
|
|
12
|
-
from .span import Span
|
|
13
|
-
from .token import TOKEN_TAG
|
|
14
|
-
|
|
15
|
-
if TYPE_CHECKING:
|
|
16
|
-
from .environment import Environment
|
|
17
|
-
from .token import Token
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
DEFAULT_INNER_TAG_MAP = {
|
|
21
|
-
"for": ["break", "continue"],
|
|
22
|
-
"if": ["else", "elsif"],
|
|
23
|
-
"case": ["when"],
|
|
24
|
-
"unless": ["else", "elsif"],
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
InnerTagMap = Mapping[str, Iterable[str]]
|
|
29
|
-
TagMap = dict[str, list[Span]]
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
class TagAnalysis:
|
|
33
|
-
"""The result of analyzing a template's tags with `Environment.analyze_tags()`.
|
|
34
|
-
|
|
35
|
-
Each of the following properties maps tag names to a list of their locations.
|
|
36
|
-
Locations are (template_name, start_index) tuples.
|
|
37
|
-
|
|
38
|
-
Note that `raw` tags are not included at all. The lexer converts them to text
|
|
39
|
-
tokens before we get a chance to analyze them.
|
|
40
|
-
|
|
41
|
-
Also be aware that reported `unexpected_tags` don't handle the possibility of an
|
|
42
|
-
"inner" tag appearing in a partial template (using `{% include %}`), where
|
|
43
|
-
appropriate enclosing block tags are in the parent template.
|
|
44
|
-
|
|
45
|
-
Attributes:
|
|
46
|
-
all_tags: A mapping of all tags to their locations. Includes "end", "inner"
|
|
47
|
-
and unknown tags.
|
|
48
|
-
tags: A mapping of tag names to their locations. Excludes "end" and "inner"
|
|
49
|
-
tags.
|
|
50
|
-
unclosed_tags: Block tags that don't have a matching "end" tag.
|
|
51
|
-
unexpected_tags: Inner tags that are not properly enclosed by appropriate
|
|
52
|
-
block tags. For example, an `{% else %}` that is not enclosed by a
|
|
53
|
-
`{% for %}` or `{% unless %}` block.
|
|
54
|
-
unknown_tags: Tags that are unknown to the environment.
|
|
55
|
-
"""
|
|
56
|
-
|
|
57
|
-
def __init__(
|
|
58
|
-
self,
|
|
59
|
-
*,
|
|
60
|
-
env: Environment,
|
|
61
|
-
name: str,
|
|
62
|
-
tokens: list[Token],
|
|
63
|
-
inner_tags: Optional[InnerTagMap] = None,
|
|
64
|
-
) -> None:
|
|
65
|
-
self.template_name = name
|
|
66
|
-
|
|
67
|
-
# A mapping of all tags to their locations. Includes "end" and inner tags.
|
|
68
|
-
self.all_tags = self._all_tags(tokens)
|
|
69
|
-
|
|
70
|
-
# Reverse map of inner tags to possible enclosing block tags.
|
|
71
|
-
inner_tags = inner_tags or DEFAULT_INNER_TAG_MAP
|
|
72
|
-
self._inner_tags = defaultdict(set)
|
|
73
|
-
for tag, inner in inner_tags.items():
|
|
74
|
-
for inner_tag in inner:
|
|
75
|
-
self._inner_tags[inner_tag].add(tag)
|
|
76
|
-
|
|
77
|
-
# A mapping of tag names to their locations. Excludes inner tags and "end" tags.
|
|
78
|
-
self.tags = {
|
|
79
|
-
tag: loc
|
|
80
|
-
for tag, loc in self.all_tags.items()
|
|
81
|
-
if not tag.startswith("end") and tag not in self._inner_tags
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
(
|
|
85
|
-
self.unclosed_tags,
|
|
86
|
-
self.unexpected_tags,
|
|
87
|
-
self.unknown_tags,
|
|
88
|
-
) = self._audit_tags(env, tokens)
|
|
89
|
-
|
|
90
|
-
def _all_tags(self, tokens: list[Token]) -> TagMap:
|
|
91
|
-
"""Map tag names to their locations, similar to `Template.analyze` etc."""
|
|
92
|
-
tags: DefaultDict[str, list[Span]] = defaultdict(list)
|
|
93
|
-
for token in tokens:
|
|
94
|
-
if token.kind == TOKEN_TAG:
|
|
95
|
-
tags[token.value].append(Span(self.template_name, token.start_index))
|
|
96
|
-
return dict(tags)
|
|
97
|
-
|
|
98
|
-
def _audit_tags( # noqa: PLR0912
|
|
99
|
-
self,
|
|
100
|
-
env: Environment,
|
|
101
|
-
tokens: list[Token],
|
|
102
|
-
) -> tuple[TagMap, TagMap, TagMap]:
|
|
103
|
-
block_stack: list[_BlockStackItem] = []
|
|
104
|
-
unclosed_tags: TagMap = defaultdict(list)
|
|
105
|
-
unexpected_tags: TagMap = defaultdict(list)
|
|
106
|
-
unknown_tags: TagMap = defaultdict(list)
|
|
107
|
-
|
|
108
|
-
# Relies on the "end" closing block tag convention.
|
|
109
|
-
end_tags = {
|
|
110
|
-
token.value
|
|
111
|
-
for token in tokens
|
|
112
|
-
if token.kind == TOKEN_TAG and token.value.startswith("end")
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
# Infer which tags are block tags. This may or may not match what the
|
|
116
|
-
# environment's tag register believes are block tags.
|
|
117
|
-
block_tags = {tag[3:] for tag in end_tags} | {
|
|
118
|
-
tag.name for tag in env.tags.values() if tag.block
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
# Registered tags. "break" and "continue" are a special case.
|
|
122
|
-
registered_tags = {
|
|
123
|
-
name for name in env.tags if name not in ("break", "continue")
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
# Registered inline tags. We use this to find erroneous "end" tags.
|
|
127
|
-
inline_tags = {tag.name for tag in env.tags.values() if not tag.block}
|
|
128
|
-
|
|
129
|
-
# We use this to find unknown "end" tags.
|
|
130
|
-
registered_end_blocks = {
|
|
131
|
-
tag.end for tag in env.tags.values() if tag.block and tag.end
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
for token in tokens:
|
|
135
|
-
if token.kind != TOKEN_TAG:
|
|
136
|
-
continue
|
|
137
|
-
|
|
138
|
-
tag_name = token.value
|
|
139
|
-
|
|
140
|
-
if tag_name in block_tags:
|
|
141
|
-
block_stack.append(_BlockStackItem(token))
|
|
142
|
-
elif tag_name in end_tags:
|
|
143
|
-
start_block_tag = block_stack.pop()
|
|
144
|
-
if start_block_tag != tag_name[3:]:
|
|
145
|
-
# if start_block_tag.name not in inline_tags:
|
|
146
|
-
unclosed_tags[start_block_tag.name].append(
|
|
147
|
-
Span(self.template_name, start_block_tag.token.start_index)
|
|
148
|
-
)
|
|
149
|
-
continue
|
|
150
|
-
|
|
151
|
-
if tag_name not in registered_tags:
|
|
152
|
-
# Possible enclosing tags for an inner tag.
|
|
153
|
-
enclosing_tags: Iterable[str] = self._inner_tags.get(tag_name, [])
|
|
154
|
-
if not enclosing_tags:
|
|
155
|
-
# Not an inner tag for any block.
|
|
156
|
-
unknown_tags[tag_name].append(
|
|
157
|
-
Span(self.template_name, token.start_index)
|
|
158
|
-
)
|
|
159
|
-
elif not self._valid_inner_tag(
|
|
160
|
-
self._inner_tags.get(tag_name, []), block_stack
|
|
161
|
-
):
|
|
162
|
-
# An inner tag, but not valid for any blocks currently on the stack.
|
|
163
|
-
unexpected_tags[tag_name].append(
|
|
164
|
-
Span(self.template_name, token.start_index)
|
|
165
|
-
)
|
|
166
|
-
|
|
167
|
-
# Catch any unclosed tags.
|
|
168
|
-
for block in block_stack:
|
|
169
|
-
unclosed_tags[block.name].append(
|
|
170
|
-
Span(self.template_name, block.token.start_index)
|
|
171
|
-
)
|
|
172
|
-
|
|
173
|
-
# Catch bad "end" tags.
|
|
174
|
-
for tag_name, locations in self.all_tags.items():
|
|
175
|
-
if tag_name.startswith("end"):
|
|
176
|
-
start_tag_name = tag_name[3:]
|
|
177
|
-
if (
|
|
178
|
-
start_tag_name in inline_tags
|
|
179
|
-
and start_tag_name not in unknown_tags
|
|
180
|
-
or (
|
|
181
|
-
tag_name not in registered_end_blocks
|
|
182
|
-
and start_tag_name not in unknown_tags
|
|
183
|
-
)
|
|
184
|
-
):
|
|
185
|
-
unknown_tags[tag_name].extend(locations)
|
|
186
|
-
|
|
187
|
-
return dict(unclosed_tags), dict(unexpected_tags), dict(unknown_tags)
|
|
188
|
-
|
|
189
|
-
def _valid_inner_tag(
|
|
190
|
-
self,
|
|
191
|
-
tag_names: Iterable[str],
|
|
192
|
-
block_stack: list[_BlockStackItem],
|
|
193
|
-
) -> bool:
|
|
194
|
-
return any(tag_name in block_stack for tag_name in tag_names)
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
class _BlockStackItem:
|
|
198
|
-
def __init__(self, token: Token) -> None:
|
|
199
|
-
self.token = token
|
|
200
|
-
self.name = token.value
|
|
201
|
-
|
|
202
|
-
def __eq__(self, __o: object) -> bool:
|
|
203
|
-
return __o == self.name or (
|
|
204
|
-
isinstance(__o, _BlockStackItem) and self.name == __o.name
|
|
205
|
-
)
|
|
206
|
-
|
|
207
|
-
def __hash__(self) -> int: # pragma: no cover
|
|
208
|
-
return hash(self.name)
|
|
209
|
-
|
|
210
|
-
def __str__(self) -> str:
|
|
211
|
-
return self.name
|
|
212
|
-
|
|
213
|
-
def __repr__(self) -> str:
|
|
214
|
-
return f"_BlockStackItem({self.name})"
|
liquid/ast.py
DELETED
|
@@ -1,252 +0,0 @@
|
|
|
1
|
-
"""Base class for all template nodes."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
from abc import ABC
|
|
6
|
-
from abc import abstractmethod
|
|
7
|
-
from enum import Enum
|
|
8
|
-
from enum import auto
|
|
9
|
-
from typing import TYPE_CHECKING
|
|
10
|
-
from typing import Collection
|
|
11
|
-
from typing import Iterable
|
|
12
|
-
from typing import Optional
|
|
13
|
-
from typing import TextIO
|
|
14
|
-
from typing import Union
|
|
15
|
-
|
|
16
|
-
from .exceptions import DisabledTagError
|
|
17
|
-
from .output import NullIO
|
|
18
|
-
from .token import TOKEN_TAG
|
|
19
|
-
from .token import Token
|
|
20
|
-
|
|
21
|
-
if TYPE_CHECKING:
|
|
22
|
-
from .builtin.expressions import Identifier
|
|
23
|
-
from .context import RenderContext
|
|
24
|
-
from .expression import Expression
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
class Node(ABC):
|
|
28
|
-
"""Base class for all nodes in a parse tree."""
|
|
29
|
-
|
|
30
|
-
__slots__ = ("token", "blank")
|
|
31
|
-
|
|
32
|
-
def __init__(self, token: Token) -> None:
|
|
33
|
-
self.token = token
|
|
34
|
-
|
|
35
|
-
self.blank = True
|
|
36
|
-
"""If True, indicates that the node, when rendered, produces no output text
|
|
37
|
-
or only whitespace.
|
|
38
|
-
|
|
39
|
-
The output node (`{{ something }}`) and echo tag are exception. Even if they
|
|
40
|
-
evaluate to an empty or blank string, they are not considered "blank".
|
|
41
|
-
"""
|
|
42
|
-
|
|
43
|
-
def raise_for_disabled(self, disabled_tags: Collection[str]) -> None:
|
|
44
|
-
"""Raise a DisabledTagError if this node's type is in the given list."""
|
|
45
|
-
if self.token.kind == TOKEN_TAG and self.token.value in disabled_tags:
|
|
46
|
-
raise DisabledTagError(
|
|
47
|
-
f"{self.token.value} usage is not allowed in this context",
|
|
48
|
-
token=self.token,
|
|
49
|
-
)
|
|
50
|
-
|
|
51
|
-
def render(self, context: RenderContext, buffer: TextIO) -> int:
|
|
52
|
-
"""Check disabled tags before delegating to `render_to_output`."""
|
|
53
|
-
if context.disabled_tags:
|
|
54
|
-
self.raise_for_disabled(context.disabled_tags)
|
|
55
|
-
return self.render_to_output(context, buffer)
|
|
56
|
-
|
|
57
|
-
async def render_async(self, context: RenderContext, buffer: TextIO) -> int:
|
|
58
|
-
"""An async version of `liquid.ast.Node.render`."""
|
|
59
|
-
if context.disabled_tags:
|
|
60
|
-
self.raise_for_disabled(context.disabled_tags)
|
|
61
|
-
return await self.render_to_output_async(context, buffer)
|
|
62
|
-
|
|
63
|
-
@abstractmethod
|
|
64
|
-
def render_to_output(
|
|
65
|
-
self,
|
|
66
|
-
context: RenderContext,
|
|
67
|
-
buffer: TextIO,
|
|
68
|
-
) -> int:
|
|
69
|
-
"""Render this node to the output buffer."""
|
|
70
|
-
|
|
71
|
-
async def render_to_output_async(
|
|
72
|
-
self,
|
|
73
|
-
context: RenderContext,
|
|
74
|
-
buffer: TextIO,
|
|
75
|
-
) -> int:
|
|
76
|
-
"""An async version of `liquid.ast.Node.render_to_output`."""
|
|
77
|
-
return self.render_to_output(context, buffer)
|
|
78
|
-
|
|
79
|
-
def children(
|
|
80
|
-
self,
|
|
81
|
-
static_context: RenderContext, # noqa: ARG002
|
|
82
|
-
*,
|
|
83
|
-
include_partials: bool = True, # noqa: ARG002
|
|
84
|
-
) -> Iterable[Node]:
|
|
85
|
-
"""Return this node's children."""
|
|
86
|
-
return []
|
|
87
|
-
|
|
88
|
-
async def children_async(
|
|
89
|
-
self,
|
|
90
|
-
static_context: RenderContext,
|
|
91
|
-
*,
|
|
92
|
-
include_partials: bool = True,
|
|
93
|
-
) -> Iterable[Node]:
|
|
94
|
-
"""An async version of `children()`."""
|
|
95
|
-
return self.children(static_context, include_partials=include_partials)
|
|
96
|
-
|
|
97
|
-
def expressions(self) -> Iterable[Expression]:
|
|
98
|
-
"""Return this node's expressions."""
|
|
99
|
-
return []
|
|
100
|
-
|
|
101
|
-
def template_scope(self) -> Iterable[Identifier]:
|
|
102
|
-
"""Return variables this node adds to the template local scope."""
|
|
103
|
-
return []
|
|
104
|
-
|
|
105
|
-
def block_scope(self) -> Iterable[Identifier]:
|
|
106
|
-
"""Return variables this node adds to the node's block scope."""
|
|
107
|
-
return []
|
|
108
|
-
|
|
109
|
-
def partial_scope(self) -> Optional[Partial]:
|
|
110
|
-
"""Return information about a partial template loaded by this node."""
|
|
111
|
-
return None
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
class PartialScope(Enum):
|
|
115
|
-
"""The kind of scope a partial template should have when loaded."""
|
|
116
|
-
|
|
117
|
-
SHARED = auto()
|
|
118
|
-
ISOLATED = auto()
|
|
119
|
-
INHERITED = auto()
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
class Partial:
|
|
123
|
-
"""Partial template meta data.
|
|
124
|
-
|
|
125
|
-
Args:
|
|
126
|
-
name: The name of the partial or an expression resolving to the name
|
|
127
|
-
associated with the partial template.
|
|
128
|
-
scope: The kind of scope the partial template should have when loaded.
|
|
129
|
-
in_scope: Names that will be added to the partial template scope.
|
|
130
|
-
key: A hash of the partial template name and any arguments the partial
|
|
131
|
-
template will be rendered with that might affect its scope. If a
|
|
132
|
-
key is provided, static analysis helpers will visit a partial
|
|
133
|
-
template once for each distinct key.
|
|
134
|
-
"""
|
|
135
|
-
|
|
136
|
-
__slots__ = ("name", "scope", "in_scope", "key")
|
|
137
|
-
|
|
138
|
-
def __init__(
|
|
139
|
-
self,
|
|
140
|
-
name: Union[Expression, str],
|
|
141
|
-
scope: PartialScope,
|
|
142
|
-
in_scope: Iterable[Identifier],
|
|
143
|
-
*,
|
|
144
|
-
key: Optional[int] = None,
|
|
145
|
-
) -> None:
|
|
146
|
-
self.name = name
|
|
147
|
-
self.scope = scope
|
|
148
|
-
self.in_scope = in_scope
|
|
149
|
-
self.key = key
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
class IllegalNode(Node):
|
|
153
|
-
"""Parse tree node representing an illegal or unregistered tag.
|
|
154
|
-
|
|
155
|
-
Illegal nodes are necessary when running in "warn" or "lax" mode. In
|
|
156
|
-
strict mode, an exception should be raised as soon as an illegal token
|
|
157
|
-
is found.
|
|
158
|
-
"""
|
|
159
|
-
|
|
160
|
-
__slots__ = ()
|
|
161
|
-
|
|
162
|
-
def __str__(self) -> str:
|
|
163
|
-
return ""
|
|
164
|
-
|
|
165
|
-
def render_to_output(self, _context: RenderContext, _buffer: TextIO) -> int:
|
|
166
|
-
"""Render the node to the output buffer."""
|
|
167
|
-
return 0
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
class BlockNode(Node):
|
|
171
|
-
"""A parse tree node representing a sequence of statements."""
|
|
172
|
-
|
|
173
|
-
__slots__ = ("nodes", "blank")
|
|
174
|
-
|
|
175
|
-
def __init__(self, token: Token, nodes: list[Node]):
|
|
176
|
-
super().__init__(token)
|
|
177
|
-
self.nodes = nodes
|
|
178
|
-
self.blank = all(node.blank for node in nodes)
|
|
179
|
-
|
|
180
|
-
def __str__(self) -> str:
|
|
181
|
-
return "".join(str(s) for s in self.nodes)
|
|
182
|
-
|
|
183
|
-
def render_to_output(self, context: RenderContext, buffer: TextIO) -> int:
|
|
184
|
-
"""Render the node to the output buffer."""
|
|
185
|
-
if context.env.suppress_blank_control_flow_blocks and self.blank:
|
|
186
|
-
buf = NullIO()
|
|
187
|
-
for node in self.nodes:
|
|
188
|
-
node.render(context, buf)
|
|
189
|
-
return 0
|
|
190
|
-
return sum(node.render(context, buffer) for node in self.nodes)
|
|
191
|
-
|
|
192
|
-
async def render_to_output_async(
|
|
193
|
-
self, context: RenderContext, buffer: TextIO
|
|
194
|
-
) -> int:
|
|
195
|
-
"""Render the node to the output buffer."""
|
|
196
|
-
if context.env.suppress_blank_control_flow_blocks and self.blank:
|
|
197
|
-
buf = NullIO()
|
|
198
|
-
for node in self.nodes:
|
|
199
|
-
await node.render_async(context, buf)
|
|
200
|
-
return 0
|
|
201
|
-
return sum([await node.render_async(context, buffer) for node in self.nodes])
|
|
202
|
-
|
|
203
|
-
def children(
|
|
204
|
-
self,
|
|
205
|
-
static_context: RenderContext, # noqa: ARG002
|
|
206
|
-
*,
|
|
207
|
-
include_partials: bool = True, # noqa: ARG002
|
|
208
|
-
) -> Iterable[Node]:
|
|
209
|
-
"""Return this node's children."""
|
|
210
|
-
return self.nodes
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
class ConditionalBlockNode(Node):
|
|
214
|
-
"""A node containing a sequence of statements and a conditional expression."""
|
|
215
|
-
|
|
216
|
-
__slots__ = ("expression", "block")
|
|
217
|
-
|
|
218
|
-
def __init__(self, token: Token, expression: Expression, block: BlockNode):
|
|
219
|
-
super().__init__(token)
|
|
220
|
-
self.expression = expression
|
|
221
|
-
self.block = block
|
|
222
|
-
self.blank = block.blank
|
|
223
|
-
|
|
224
|
-
def __str__(self) -> str:
|
|
225
|
-
return f"{{% elsif {self.expression} %}}{self.block}"
|
|
226
|
-
|
|
227
|
-
def render_to_output(self, context: RenderContext, buffer: TextIO) -> int:
|
|
228
|
-
"""Render the node to the output buffer."""
|
|
229
|
-
if self.expression.evaluate(context):
|
|
230
|
-
return self.block.render(context, buffer)
|
|
231
|
-
return 0
|
|
232
|
-
|
|
233
|
-
async def render_to_output_async(
|
|
234
|
-
self, context: RenderContext, buffer: TextIO
|
|
235
|
-
) -> int:
|
|
236
|
-
"""Render the node to the output buffer."""
|
|
237
|
-
if await self.expression.evaluate_async(context):
|
|
238
|
-
return await self.block.render_async(context, buffer)
|
|
239
|
-
return 0
|
|
240
|
-
|
|
241
|
-
def children(
|
|
242
|
-
self,
|
|
243
|
-
static_context: RenderContext, # noqa: ARG002
|
|
244
|
-
*,
|
|
245
|
-
include_partials: bool = True, # noqa: ARG002
|
|
246
|
-
) -> Iterable[Node]:
|
|
247
|
-
"""Return this node's children."""
|
|
248
|
-
yield self.block
|
|
249
|
-
|
|
250
|
-
def expressions(self) -> Iterable[Expression]:
|
|
251
|
-
"""Return this node's expressions."""
|
|
252
|
-
yield self.expression
|
liquid/builtin/__init__.py
DELETED
|
@@ -1,203 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations # noqa: D104
|
|
2
|
-
|
|
3
|
-
from typing import TYPE_CHECKING
|
|
4
|
-
|
|
5
|
-
from . import content
|
|
6
|
-
from . import illegal
|
|
7
|
-
from . import output
|
|
8
|
-
from .filters.array import compact
|
|
9
|
-
from .filters.array import concat
|
|
10
|
-
from .filters.array import find
|
|
11
|
-
from .filters.array import find_index
|
|
12
|
-
from .filters.array import first
|
|
13
|
-
from .filters.array import has
|
|
14
|
-
from .filters.array import join
|
|
15
|
-
from .filters.array import last
|
|
16
|
-
from .filters.array import map_
|
|
17
|
-
from .filters.array import reject
|
|
18
|
-
from .filters.array import reverse
|
|
19
|
-
from .filters.array import sort
|
|
20
|
-
from .filters.array import sort_natural
|
|
21
|
-
from .filters.array import sum_
|
|
22
|
-
from .filters.array import uniq
|
|
23
|
-
from .filters.array import where
|
|
24
|
-
from .filters.extra import escapejs
|
|
25
|
-
from .filters.extra import safe
|
|
26
|
-
from .filters.math import abs_
|
|
27
|
-
from .filters.math import at_least
|
|
28
|
-
from .filters.math import at_most
|
|
29
|
-
from .filters.math import ceil
|
|
30
|
-
from .filters.math import divided_by
|
|
31
|
-
from .filters.math import floor
|
|
32
|
-
from .filters.math import minus
|
|
33
|
-
from .filters.math import modulo
|
|
34
|
-
from .filters.math import plus
|
|
35
|
-
from .filters.math import round_
|
|
36
|
-
from .filters.math import times
|
|
37
|
-
from .filters.misc import date
|
|
38
|
-
from .filters.misc import default
|
|
39
|
-
from .filters.misc import size
|
|
40
|
-
from .filters.string import append
|
|
41
|
-
from .filters.string import base64_decode
|
|
42
|
-
from .filters.string import base64_encode
|
|
43
|
-
from .filters.string import base64_url_safe_decode
|
|
44
|
-
from .filters.string import base64_url_safe_encode
|
|
45
|
-
from .filters.string import capitalize
|
|
46
|
-
from .filters.string import downcase
|
|
47
|
-
from .filters.string import escape
|
|
48
|
-
from .filters.string import escape_once
|
|
49
|
-
from .filters.string import lstrip
|
|
50
|
-
from .filters.string import newline_to_br
|
|
51
|
-
from .filters.string import prepend
|
|
52
|
-
from .filters.string import remove
|
|
53
|
-
from .filters.string import remove_first
|
|
54
|
-
from .filters.string import remove_last
|
|
55
|
-
from .filters.string import replace
|
|
56
|
-
from .filters.string import replace_first
|
|
57
|
-
from .filters.string import replace_last
|
|
58
|
-
from .filters.string import rstrip
|
|
59
|
-
from .filters.string import slice_
|
|
60
|
-
from .filters.string import split
|
|
61
|
-
from .filters.string import squish
|
|
62
|
-
from .filters.string import strip
|
|
63
|
-
from .filters.string import strip_html
|
|
64
|
-
from .filters.string import strip_newlines
|
|
65
|
-
from .filters.string import truncate
|
|
66
|
-
from .filters.string import truncatewords
|
|
67
|
-
from .filters.string import upcase
|
|
68
|
-
from .filters.string import url_decode
|
|
69
|
-
from .filters.string import url_encode
|
|
70
|
-
from .loaders.caching_file_system_loader import CachingFileSystemLoader
|
|
71
|
-
from .loaders.choice_loader import CachingChoiceLoader
|
|
72
|
-
from .loaders.choice_loader import ChoiceLoader
|
|
73
|
-
from .loaders.dict_loader import CachingDictLoader
|
|
74
|
-
from .loaders.dict_loader import DictLoader
|
|
75
|
-
from .loaders.file_system_loader import FileSystemLoader
|
|
76
|
-
from .loaders.mixins import CachingLoaderMixin
|
|
77
|
-
from .loaders.package_loader import PackageLoader
|
|
78
|
-
from .tags import assign_tag
|
|
79
|
-
from .tags import capture_tag
|
|
80
|
-
from .tags import case_tag
|
|
81
|
-
from .tags import comment_tag
|
|
82
|
-
from .tags import cycle_tag
|
|
83
|
-
from .tags import decrement_tag
|
|
84
|
-
from .tags import doc_tag
|
|
85
|
-
from .tags import echo_tag
|
|
86
|
-
from .tags import for_tag
|
|
87
|
-
from .tags import if_tag
|
|
88
|
-
from .tags import ifchanged_tag
|
|
89
|
-
from .tags import include_tag
|
|
90
|
-
from .tags import increment_tag
|
|
91
|
-
from .tags import inline_comment_tag
|
|
92
|
-
from .tags import liquid_tag
|
|
93
|
-
from .tags import render_tag
|
|
94
|
-
from .tags import tablerow_tag
|
|
95
|
-
from .tags import unless_tag
|
|
96
|
-
|
|
97
|
-
if TYPE_CHECKING:
|
|
98
|
-
from liquid import Environment
|
|
99
|
-
|
|
100
|
-
__all__ = (
|
|
101
|
-
"CachingFileSystemLoader",
|
|
102
|
-
"CachingChoiceLoader",
|
|
103
|
-
"ChoiceLoader",
|
|
104
|
-
"CachingDictLoader",
|
|
105
|
-
"DictLoader",
|
|
106
|
-
"FileSystemLoader",
|
|
107
|
-
"CachingLoaderMixin",
|
|
108
|
-
"PackageLoader",
|
|
109
|
-
)
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
def register(env: Environment) -> None: # noqa: PLR0915
|
|
113
|
-
"""Register all built-in tags and filters with an environment."""
|
|
114
|
-
env.add_tag(content.Literal)
|
|
115
|
-
env.add_tag(output.Output)
|
|
116
|
-
env.add_tag(illegal.Illegal)
|
|
117
|
-
env.add_tag(if_tag.IfTag)
|
|
118
|
-
env.add_tag(comment_tag.CommentTag)
|
|
119
|
-
env.add_tag(unless_tag.UnlessTag)
|
|
120
|
-
env.add_tag(case_tag.CaseTag)
|
|
121
|
-
env.add_tag(for_tag.ForTag)
|
|
122
|
-
env.add_tag(for_tag.BreakTag)
|
|
123
|
-
env.add_tag(for_tag.ContinueTag)
|
|
124
|
-
env.add_tag(tablerow_tag.TablerowTag)
|
|
125
|
-
env.add_tag(capture_tag.CaptureTag)
|
|
126
|
-
env.add_tag(cycle_tag.CycleTag)
|
|
127
|
-
env.add_tag(assign_tag.AssignTag)
|
|
128
|
-
env.add_tag(increment_tag.IncrementTag)
|
|
129
|
-
env.add_tag(decrement_tag.DecrementTag)
|
|
130
|
-
env.add_tag(echo_tag.EchoTag)
|
|
131
|
-
env.add_tag(liquid_tag.LiquidTag)
|
|
132
|
-
env.add_tag(include_tag.IncludeTag)
|
|
133
|
-
env.add_tag(render_tag.RenderTag)
|
|
134
|
-
env.add_tag(ifchanged_tag.IfChangedTag)
|
|
135
|
-
env.add_tag(inline_comment_tag.InlineCommentTag)
|
|
136
|
-
env.add_tag(doc_tag.DocTag)
|
|
137
|
-
|
|
138
|
-
env.add_filter("abs", abs_)
|
|
139
|
-
env.add_filter("at_most", at_most)
|
|
140
|
-
env.add_filter("at_least", at_least)
|
|
141
|
-
env.add_filter("ceil", ceil)
|
|
142
|
-
env.add_filter("divided_by", divided_by)
|
|
143
|
-
env.add_filter("floor", floor)
|
|
144
|
-
env.add_filter("minus", minus)
|
|
145
|
-
env.add_filter("plus", plus)
|
|
146
|
-
env.add_filter("round", round_)
|
|
147
|
-
env.add_filter("times", times)
|
|
148
|
-
env.add_filter("modulo", modulo)
|
|
149
|
-
|
|
150
|
-
env.add_filter("capitalize", capitalize)
|
|
151
|
-
env.add_filter("append", append)
|
|
152
|
-
env.add_filter("downcase", downcase)
|
|
153
|
-
env.add_filter("escape", escape)
|
|
154
|
-
env.add_filter("escape_once", escape_once)
|
|
155
|
-
env.add_filter("lstrip", lstrip)
|
|
156
|
-
env.add_filter("newline_to_br", newline_to_br)
|
|
157
|
-
env.add_filter("prepend", prepend)
|
|
158
|
-
env.add_filter("remove", remove)
|
|
159
|
-
env.add_filter("remove_first", remove_first)
|
|
160
|
-
env.add_filter("remove_last", remove_last)
|
|
161
|
-
env.add_filter("replace", replace)
|
|
162
|
-
env.add_filter("replace_first", replace_first)
|
|
163
|
-
env.add_filter("replace_last", replace_last)
|
|
164
|
-
env.add_filter("slice", slice_)
|
|
165
|
-
env.add_filter("split", split)
|
|
166
|
-
env.add_filter("upcase", upcase)
|
|
167
|
-
env.add_filter("strip", strip)
|
|
168
|
-
env.add_filter("rstrip", rstrip)
|
|
169
|
-
env.add_filter("strip_html", strip_html)
|
|
170
|
-
env.add_filter("strip_newlines", strip_newlines)
|
|
171
|
-
env.add_filter("truncate", truncate)
|
|
172
|
-
env.add_filter("truncatewords", truncatewords)
|
|
173
|
-
env.add_filter("url_encode", url_encode)
|
|
174
|
-
env.add_filter("url_decode", url_decode)
|
|
175
|
-
env.add_filter("base64_encode", base64_encode)
|
|
176
|
-
env.add_filter("base64_decode", base64_decode)
|
|
177
|
-
env.add_filter("base64_url_safe_encode", base64_url_safe_encode)
|
|
178
|
-
env.add_filter("base64_url_safe_decode", base64_url_safe_decode)
|
|
179
|
-
env.add_filter("squish", squish)
|
|
180
|
-
|
|
181
|
-
env.add_filter("find", find)
|
|
182
|
-
env.add_filter("find_index", find_index)
|
|
183
|
-
env.add_filter("join", join)
|
|
184
|
-
env.add_filter("first", first)
|
|
185
|
-
env.add_filter("has", has)
|
|
186
|
-
env.add_filter("last", last)
|
|
187
|
-
env.add_filter("concat", concat)
|
|
188
|
-
env.add_filter("map", map_)
|
|
189
|
-
env.add_filter("reject", reject)
|
|
190
|
-
env.add_filter("reverse", reverse)
|
|
191
|
-
env.add_filter("sort", sort)
|
|
192
|
-
env.add_filter("sort_natural", sort_natural)
|
|
193
|
-
env.add_filter("sum", sum_)
|
|
194
|
-
env.add_filter("where", where)
|
|
195
|
-
env.add_filter("uniq", uniq)
|
|
196
|
-
env.add_filter("compact", compact)
|
|
197
|
-
|
|
198
|
-
env.add_filter("size", size)
|
|
199
|
-
env.add_filter("default", default)
|
|
200
|
-
env.add_filter("date", date)
|
|
201
|
-
|
|
202
|
-
env.add_filter("safe", safe)
|
|
203
|
-
env.add_filter("escapejs", escapejs)
|