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.
Files changed (212) hide show
  1. liquid/__about__.py +1 -0
  2. liquid/__init__.py +161 -187
  3. liquid/_base_tag.py +66 -0
  4. liquid/{utils/chain_map.py → _chain_map.py} +18 -19
  5. liquid/_context.py +465 -0
  6. liquid/_drop.py +108 -0
  7. liquid/_filter.py +174 -0
  8. liquid/_io.py +18 -0
  9. liquid/_lax_parser_mixin.py +100 -0
  10. liquid/_lexer.py +93 -0
  11. liquid/_lexer_extended.py +623 -0
  12. liquid/_lexer_legacy.py +536 -0
  13. liquid/_loader.py +84 -0
  14. liquid/{utils/lru_cache.py → _lru_cache.py} +28 -36
  15. liquid/_markup.py +253 -0
  16. liquid/_messages.py +292 -0
  17. liquid/_missing.py +3 -0
  18. liquid/_nothing.py +28 -0
  19. liquid/_parser.py +460 -0
  20. liquid/_parser_extended.py +293 -0
  21. liquid/_parser_legacy.py +819 -0
  22. liquid/_resource_limits.py +50 -0
  23. liquid/_slice.py +41 -0
  24. liquid/_static_analysis.py +503 -0
  25. liquid/_strftime.py +186 -0
  26. liquid/_template.py +536 -0
  27. liquid/drops/__init__.py +20 -0
  28. liquid/drops/forloop.py +78 -0
  29. liquid/drops/iterable.py +25 -0
  30. liquid/drops/range.py +76 -0
  31. liquid/drops/self_.py +45 -0
  32. liquid/drops/tablerowloop.py +142 -0
  33. liquid/drops/undefined.py +228 -0
  34. liquid/environment.py +717 -551
  35. liquid/exceptions.py +67 -214
  36. liquid/expressions.py +1184 -0
  37. liquid/filters/__init__.py +134 -0
  38. liquid/filters/abs.py +7 -0
  39. liquid/filters/append.py +5 -0
  40. liquid/filters/at_least.py +9 -0
  41. liquid/filters/at_most.py +9 -0
  42. liquid/filters/babel.py +560 -0
  43. liquid/filters/base64.py +26 -0
  44. liquid/filters/capitalize.py +5 -0
  45. liquid/filters/ceil.py +8 -0
  46. liquid/filters/compact.py +25 -0
  47. liquid/filters/concat.py +11 -0
  48. liquid/filters/date.py +27 -0
  49. liquid/filters/default.py +25 -0
  50. liquid/filters/divided_by.py +21 -0
  51. liquid/filters/downcase.py +5 -0
  52. liquid/filters/escape.py +56 -0
  53. liquid/filters/find.py +56 -0
  54. liquid/filters/first.py +19 -0
  55. liquid/filters/floor.py +8 -0
  56. liquid/filters/html.py +23 -0
  57. liquid/filters/index.py +12 -0
  58. liquid/filters/join.py +13 -0
  59. liquid/filters/json_.py +30 -0
  60. liquid/filters/last.py +17 -0
  61. liquid/filters/map.py +5 -0
  62. liquid/filters/minus.py +13 -0
  63. liquid/filters/modulo.py +18 -0
  64. liquid/filters/newline_to_br.py +16 -0
  65. liquid/filters/plus.py +13 -0
  66. liquid/filters/prepend.py +5 -0
  67. liquid/filters/reject.py +19 -0
  68. liquid/filters/remove.py +36 -0
  69. liquid/filters/replace.py +32 -0
  70. liquid/filters/reverse.py +5 -0
  71. liquid/filters/round.py +35 -0
  72. liquid/filters/size.py +25 -0
  73. liquid/filters/slice.py +39 -0
  74. liquid/filters/sort.py +148 -0
  75. liquid/filters/split.py +34 -0
  76. liquid/filters/squish.py +9 -0
  77. liquid/filters/strip.py +13 -0
  78. liquid/filters/strip_html.py +19 -0
  79. liquid/filters/strip_newlines.py +17 -0
  80. liquid/filters/sum.py +21 -0
  81. liquid/filters/times.py +13 -0
  82. liquid/filters/translate.py +380 -0
  83. liquid/filters/truncate.py +39 -0
  84. liquid/filters/uniq.py +11 -0
  85. liquid/filters/upcase.py +5 -0
  86. liquid/filters/url.py +18 -0
  87. liquid/filters/where.py +18 -0
  88. liquid/loaders/__init__.py +17 -0
  89. liquid/loaders/caching_file_system_loader.py +64 -0
  90. liquid/loaders/choice_loader.py +93 -0
  91. liquid/loaders/dict_loader.py +56 -0
  92. liquid/{builtin/loaders → loaders}/file_system_loader.py +51 -55
  93. liquid/{builtin/loaders → loaders}/mixins.py +39 -51
  94. liquid/loaders/package_loader.py +110 -0
  95. liquid/tags/__init__.py +61 -0
  96. liquid/tags/assign.py +68 -0
  97. liquid/tags/capture.py +83 -0
  98. liquid/tags/case.py +199 -0
  99. liquid/tags/comment.py +56 -0
  100. liquid/tags/cycle.py +131 -0
  101. liquid/tags/decrement.py +55 -0
  102. liquid/tags/doc.py +56 -0
  103. liquid/tags/echo.py +65 -0
  104. liquid/tags/else_.py +53 -0
  105. liquid/tags/error.py +51 -0
  106. liquid/tags/extends.py +448 -0
  107. liquid/tags/for_.py +421 -0
  108. liquid/tags/if_.py +156 -0
  109. liquid/tags/ifchanged.py +69 -0
  110. liquid/tags/include.py +223 -0
  111. liquid/tags/increment.py +55 -0
  112. liquid/tags/inline_comment.py +70 -0
  113. liquid/tags/liquid.py +56 -0
  114. liquid/tags/macro.py +281 -0
  115. liquid/tags/output.py +58 -0
  116. liquid/tags/raw.py +60 -0
  117. liquid/tags/render.py +245 -0
  118. liquid/tags/tablerow.py +254 -0
  119. liquid/tags/template_comment.py +56 -0
  120. liquid/tags/translate.py +316 -0
  121. liquid/tags/unless.py +121 -0
  122. liquid/tags/with_.py +83 -0
  123. liquid/tokens.py +370 -0
  124. {python_liquid-2.3.6.dist-info → python_liquid-3.0.0.dist-info}/METADATA +32 -39
  125. python_liquid-3.0.0.dist-info/RECORD +128 -0
  126. {python_liquid-2.3.6.dist-info → python_liquid-3.0.0.dist-info}/WHEEL +1 -1
  127. {python_liquid-2.3.6.dist-info → python_liquid-3.0.0.dist-info}/licenses/LICENSE +1 -1
  128. liquid/analyze_tags.py +0 -214
  129. liquid/ast.py +0 -252
  130. liquid/builtin/__init__.py +0 -203
  131. liquid/builtin/content.py +0 -41
  132. liquid/builtin/drops/__init__.py +0 -3
  133. liquid/builtin/drops/drops.py +0 -13
  134. liquid/builtin/expressions/__init__.py +0 -47
  135. liquid/builtin/expressions/_tokenize.py +0 -186
  136. liquid/builtin/expressions/arguments.py +0 -207
  137. liquid/builtin/expressions/filtered.py +0 -387
  138. liquid/builtin/expressions/logical.py +0 -672
  139. liquid/builtin/expressions/loop.py +0 -275
  140. liquid/builtin/expressions/path.py +0 -163
  141. liquid/builtin/expressions/primitive.py +0 -417
  142. liquid/builtin/filters/__init__.py +0 -0
  143. liquid/builtin/filters/array.py +0 -329
  144. liquid/builtin/filters/extra.py +0 -83
  145. liquid/builtin/filters/math.py +0 -129
  146. liquid/builtin/filters/misc.py +0 -137
  147. liquid/builtin/filters/string.py +0 -416
  148. liquid/builtin/illegal.py +0 -28
  149. liquid/builtin/loaders/__init__.py +0 -0
  150. liquid/builtin/loaders/caching_file_system_loader.py +0 -61
  151. liquid/builtin/loaders/choice_loader.py +0 -94
  152. liquid/builtin/loaders/dict_loader.py +0 -64
  153. liquid/builtin/loaders/package_loader.py +0 -132
  154. liquid/builtin/output.py +0 -74
  155. liquid/builtin/tags/__init__.py +0 -0
  156. liquid/builtin/tags/assign_tag.py +0 -75
  157. liquid/builtin/tags/capture_tag.py +0 -98
  158. liquid/builtin/tags/case_tag.py +0 -287
  159. liquid/builtin/tags/comment_tag.py +0 -77
  160. liquid/builtin/tags/cycle_tag.py +0 -132
  161. liquid/builtin/tags/decrement_tag.py +0 -59
  162. liquid/builtin/tags/doc_tag.py +0 -68
  163. liquid/builtin/tags/echo_tag.py +0 -45
  164. liquid/builtin/tags/for_tag.py +0 -337
  165. liquid/builtin/tags/if_tag.py +0 -209
  166. liquid/builtin/tags/ifchanged_tag.py +0 -94
  167. liquid/builtin/tags/include_tag.py +0 -251
  168. liquid/builtin/tags/increment_tag.py +0 -60
  169. liquid/builtin/tags/inline_comment_tag.py +0 -47
  170. liquid/builtin/tags/liquid_tag.py +0 -183
  171. liquid/builtin/tags/render_tag.py +0 -371
  172. liquid/builtin/tags/tablerow_tag.py +0 -320
  173. liquid/builtin/tags/unless_tag.py +0 -218
  174. liquid/context.py +0 -615
  175. liquid/expression.py +0 -41
  176. liquid/extra/__init__.py +0 -98
  177. liquid/extra/filters/__init__.py +0 -33
  178. liquid/extra/filters/_json.py +0 -33
  179. liquid/extra/filters/array.py +0 -60
  180. liquid/extra/filters/babel.py +0 -552
  181. liquid/extra/filters/html.py +0 -32
  182. liquid/extra/filters/translate.py +0 -448
  183. liquid/extra/tags/__init__.py +0 -17
  184. liquid/extra/tags/_with.py +0 -80
  185. liquid/extra/tags/extends_tag.py +0 -576
  186. liquid/extra/tags/macro_tag.py +0 -270
  187. liquid/extra/tags/snippet_tag.py +0 -107
  188. liquid/extra/tags/translate_tag.py +0 -388
  189. liquid/filter.py +0 -230
  190. liquid/future/__init__.py +0 -3
  191. liquid/future/environment.py +0 -30
  192. liquid/future/filters/__init__.py +0 -1
  193. liquid/future/tags/__init__.py +0 -1
  194. liquid/lex.py +0 -260
  195. liquid/limits.py +0 -66
  196. liquid/loader.py +0 -141
  197. liquid/messages.py +0 -357
  198. liquid/mode.py +0 -12
  199. liquid/output.py +0 -35
  200. liquid/parser.py +0 -119
  201. liquid/span.py +0 -35
  202. liquid/static_analysis.py +0 -443
  203. liquid/stream.py +0 -148
  204. liquid/stringify.py +0 -31
  205. liquid/tag.py +0 -47
  206. liquid/template.py +0 -658
  207. liquid/token.py +0 -145
  208. liquid/undefined.py +0 -218
  209. liquid/utils/__init__.py +0 -15
  210. liquid/utils/html.py +0 -57
  211. liquid/utils/text.py +0 -28
  212. python_liquid-2.3.6.dist-info/RECORD +0 -96
@@ -1,270 +0,0 @@
1
- """The built-in `macro` and `call` tags."""
2
-
3
- from __future__ import annotations
4
-
5
- import itertools
6
- from dataclasses import dataclass
7
- from typing import TYPE_CHECKING
8
- from typing import Iterable
9
- from typing import Optional
10
- from typing import TextIO
11
- from typing import Union
12
-
13
- from liquid.ast import BlockNode
14
- from liquid.ast import Node
15
- from liquid.builtin.expressions import Identifier
16
- from liquid.builtin.expressions import KeywordArgument
17
- from liquid.builtin.expressions import Parameter
18
- from liquid.builtin.expressions import parse_arguments
19
- from liquid.builtin.expressions import parse_name
20
- from liquid.parser import get_parser
21
- from liquid.tag import Tag
22
- from liquid.token import TOKEN_TAG
23
- from liquid.undefined import Undefined
24
- from liquid.undefined import is_undefined
25
-
26
- if TYPE_CHECKING:
27
- from liquid import Expression
28
- from liquid import RenderContext
29
- from liquid import Token
30
- from liquid import TokenStream
31
- from liquid.builtin.expressions import PositionalArgument
32
-
33
-
34
- @dataclass
35
- class Macro:
36
- """A macro's arguments and associated block."""
37
-
38
- args: dict[str, Parameter]
39
- block: BlockNode
40
-
41
-
42
- @dataclass
43
- class BoundArgs:
44
- """Expressions bound to the evaluation of a `call` tag."""
45
-
46
- args: dict[str, Optional[Expression]]
47
- excess_args: list[Expression]
48
- excess_kwargs: dict[str, Expression]
49
-
50
-
51
- class MacroNode(Node):
52
- """The built-in _macro_ tag."""
53
-
54
- __slots__ = ("name", "args", "block")
55
-
56
- def __init__(
57
- self,
58
- token: Token,
59
- name: str,
60
- args: dict[str, Parameter],
61
- block: BlockNode,
62
- ):
63
- super().__init__(token)
64
- self.name = name
65
- self.args = args
66
- self.block = block
67
- self.blank = True
68
-
69
- def __str__(self) -> str:
70
- args = " " + ", ".join(str(p) for p in self.args.values()) if self.args else ""
71
- return f"{{% macro {self.name}{args} %}}{self.block}{{% endmacro %}}"
72
-
73
- def render_to_output(self, context: RenderContext, _buffer: TextIO) -> int:
74
- """Render the node to the output buffer."""
75
- # Macro tags don't render or evaluate anything, just store their arguments list
76
- # and block on the render context so it can be called later by a `call` tag.
77
- context.tag_namespace["macros"][self.name] = Macro(
78
- args=self.args, block=self.block
79
- )
80
- return 0
81
-
82
- def expressions(self) -> Iterable[Expression]:
83
- """Return this node's expressions."""
84
- yield from (arg.value for arg in self.args.values() if arg.value)
85
-
86
- def children(
87
- self,
88
- static_context: RenderContext, # noqa: ARG002
89
- *,
90
- include_partials: bool = True, # noqa: ARG002
91
- ) -> Iterable[Node]:
92
- """Return this node's children."""
93
- yield self.block
94
-
95
- def block_scope(self) -> Iterable[Identifier]:
96
- """Return variables this node adds to the node's block scope."""
97
- yield Identifier("args", token=self.token)
98
- yield Identifier("kwargs", token=self.token)
99
- yield from (Identifier(p.name, token=p.token) for p in self.args.values())
100
-
101
-
102
- class MacroTag(Tag):
103
- """The built-in _macro_ tag."""
104
-
105
- name = "macro"
106
- node_class = MacroNode
107
-
108
- def parse(self, stream: TokenStream) -> Node:
109
- """Parse tokens from _stream_ into an AST node."""
110
- token = stream.eat(TOKEN_TAG)
111
- tokens = stream.into_inner(tag=token)
112
- name = parse_name(self.env, tokens)
113
- args = Parameter.parse(self.env, tokens)
114
- block = get_parser(self.env).parse_block(stream, ("endmacro",))
115
- stream.expect(TOKEN_TAG, "endmacro")
116
- return self.node_class(token, name, args, block)
117
-
118
-
119
- class CallNode(Node):
120
- """The built-in _call_ tag."""
121
-
122
- __slots__ = ("name", "args", "kwargs")
123
- disabled_tags = ["include", "block"]
124
-
125
- def __init__(
126
- self,
127
- token: Token,
128
- name: str,
129
- args: list[PositionalArgument],
130
- kwargs: list[KeywordArgument],
131
- ) -> None:
132
- super().__init__(token)
133
- self.name = name
134
- self.args = args
135
- self.kwargs = kwargs
136
- self.blank = False
137
-
138
- def __str__(self) -> str:
139
- args = " " + ", ".join(
140
- [*(str(arg) for arg in self.args), *(str(arg) for arg in self.kwargs)]
141
- )
142
- return f"{{% call {self.name}{args} %}}"
143
-
144
- def render_to_output(self, context: RenderContext, buffer: TextIO) -> int:
145
- """Render the node to the output buffer."""
146
- macro: Union[Macro, Undefined] = context.tag_namespace["macros"].get(
147
- self.name, context.env.undefined(self.name, token=self.token)
148
- )
149
-
150
- if isinstance(macro, Undefined):
151
- return buffer.write(str(macro))
152
-
153
- args = self.macro_args(macro)
154
-
155
- namespace: dict[str, object] = {
156
- "args": [expr.evaluate(context) for expr in args.excess_args],
157
- "kwargs": {
158
- name: expr.evaluate(context)
159
- for name, expr in args.excess_kwargs.items()
160
- },
161
- }
162
-
163
- for name, expr in args.args.items():
164
- if expr is None:
165
- namespace[name] = context.env.undefined(name, token=self.token)
166
- else:
167
- namespace[name] = expr.evaluate(context)
168
-
169
- macro_context = context.copy(
170
- namespace=namespace,
171
- disabled_tags=self.disabled_tags,
172
- carry_loop_iterations=True,
173
- )
174
-
175
- return macro.block.render(macro_context, buffer)
176
-
177
- async def render_to_output_async(
178
- self,
179
- context: RenderContext,
180
- buffer: TextIO,
181
- ) -> int:
182
- """Render the node to the output buffer."""
183
- macro: Union[Macro, Undefined] = context.tag_namespace["macros"].get(
184
- self.name, context.env.undefined(self.name, token=self.token)
185
- )
186
-
187
- if is_undefined(macro):
188
- return buffer.write(str(macro))
189
-
190
- assert isinstance(macro, Macro)
191
- args = self.macro_args(macro)
192
-
193
- namespace: dict[str, object] = {
194
- "args": [await expr.evaluate_async(context) for expr in args.excess_args],
195
- "kwargs": {
196
- name: await expr.evaluate_async(context)
197
- for name, expr in args.excess_kwargs.items()
198
- },
199
- }
200
-
201
- for name, expr in args.args.items():
202
- if expr is None:
203
- namespace[name] = context.env.undefined(name, token=self.token)
204
- else:
205
- namespace[name] = await expr.evaluate_async(context)
206
-
207
- macro_context = context.copy(
208
- namespace=namespace,
209
- disabled_tags=self.disabled_tags,
210
- carry_loop_iterations=True,
211
- )
212
-
213
- return await macro.block.render_async(macro_context, buffer)
214
-
215
- def macro_args(self, macro: Macro) -> BoundArgs:
216
- """Bind this call's arguments to macro parameter names."""
217
- args: dict[str, Optional[Expression]] = {
218
- name: param.value for name, param in macro.args.items()
219
- }
220
-
221
- excess_args: list[Expression] = []
222
- excess_kwargs: dict[str, Expression] = {}
223
-
224
- # Bind positional arguments to names. If there are more positional arguments
225
- # than names defined in the macro, they'll be stored in `excess_args`.
226
- #
227
- # We're effectively pushing kwargs to the end if they appear before positional
228
- # arguments.
229
- for name, expr in itertools.zip_longest(macro.args, self.args, fillvalue=None):
230
- if name is None:
231
- assert expr is not None
232
- excess_args.append(expr.value)
233
- continue
234
-
235
- if expr is None:
236
- break
237
-
238
- args[name] = expr.value
239
-
240
- for arg in self.kwargs:
241
- if arg.name in macro.args:
242
- # This has the potential to override a positional argument.
243
- args[arg.name] = arg.value
244
- else:
245
- excess_kwargs[arg.name] = arg.value
246
-
247
- return BoundArgs(
248
- args=args, excess_args=excess_args, excess_kwargs=excess_kwargs
249
- )
250
-
251
- def expressions(self) -> Iterable[Expression]:
252
- """Return this node's expressions."""
253
- yield from (arg.value for arg in self.args if arg.value)
254
- yield from (arg.value for arg in self.kwargs if arg.value)
255
-
256
-
257
- class CallTag(Tag):
258
- """The built-in _call_ tag."""
259
-
260
- name = "call"
261
- node_class = CallNode
262
- block = False
263
-
264
- def parse(self, stream: TokenStream) -> Node:
265
- """Parse tokens from _stream_ into an AST node."""
266
- token = stream.eat(TOKEN_TAG)
267
- tokens = stream.into_inner(tag=token, eat=False)
268
- name = parse_name(self.env, tokens)
269
- args, kwargs = parse_arguments(self.env, tokens)
270
- return self.node_class(token, name, args, kwargs)
@@ -1,107 +0,0 @@
1
- """The built-in _snippet_ tag.
2
-
3
- New in Python Liquid version 2.2.0.
4
- New in Shopify/liquid version 5.10.0.
5
- """
6
-
7
- from __future__ import annotations
8
-
9
- from typing import TYPE_CHECKING
10
- from typing import TextIO
11
-
12
- from liquid.ast import BlockNode
13
- from liquid.ast import Node
14
- from liquid.builtin.expressions import parse_identifier
15
- from liquid.parser import get_parser
16
- from liquid.tag import Tag
17
- from liquid.template import BoundTemplate
18
- from liquid.token import TOKEN_EOF
19
- from liquid.token import TOKEN_TAG
20
- from liquid.token import Token
21
-
22
- if TYPE_CHECKING:
23
- from collections.abc import Iterable
24
-
25
- from liquid.builtin.expressions import Identifier
26
- from liquid.context import RenderContext
27
- from liquid.stream import TokenStream
28
-
29
-
30
- class SnippetNode(Node):
31
- """The built-in _snippet_ tag."""
32
-
33
- __slots__ = ("name", "block")
34
-
35
- def __init__(self, token: Token, name: Identifier, block: BlockNode):
36
- super().__init__(token)
37
- self.name = name
38
- self.block = block
39
-
40
- def __str__(self) -> str:
41
- return f"{{% snippet {self.name} %}}{self.block}{{% endsnippet %}}"
42
-
43
- def render_to_output(self, context: RenderContext, buffer: TextIO) -> int: # noqa: ARG002
44
- """Render the node to the output buffer."""
45
- # Don't render anything, just bind the block to its name.
46
- context.assign(
47
- self.name,
48
- SnippetDrop(
49
- context.env,
50
- self.block.nodes,
51
- context.template.name,
52
- context.template.path,
53
- ),
54
- )
55
- return 0
56
-
57
- def children(
58
- self,
59
- static_context: RenderContext, # noqa: ARG002
60
- *,
61
- include_partials: bool = True, # noqa: ARG002
62
- ) -> Iterable[Node]:
63
- """Return this node's children."""
64
- # Snippets are only visited when rendered so we get accurate variable
65
- # scope analysis.
66
- static_context.assign(
67
- self.name,
68
- SnippetDrop(
69
- static_context.env,
70
- self.block.nodes,
71
- static_context.template.name,
72
- static_context.template.path,
73
- ),
74
- )
75
- return []
76
-
77
- def template_scope(self) -> Iterable[Identifier]:
78
- """Return variables this node adds to the template local scope."""
79
- yield self.name
80
-
81
-
82
- class SnippetTag(Tag):
83
- """The built-in _snippet_ tag."""
84
-
85
- block = True
86
- name = "snippet"
87
- end = "endsnippet"
88
- node_class = SnippetNode
89
-
90
- ENDSNIPPETBLOCK = frozenset((end, TOKEN_EOF))
91
-
92
- def parse(self, stream: TokenStream) -> SnippetNode:
93
- """Parse tokens from _stream_ into an AST node."""
94
- token = stream.eat(TOKEN_TAG)
95
- tokens = stream.into_inner(tag=token)
96
- name = parse_identifier(self.env, tokens)
97
- tokens.expect_eos()
98
- block = get_parser(self.env).parse_block(stream, self.ENDSNIPPETBLOCK)
99
- stream.expect(TOKEN_TAG, value=self.end)
100
- return self.node_class(token, name, block)
101
-
102
-
103
- class SnippetDrop(BoundTemplate):
104
- """An template suitable for storing in a render context."""
105
-
106
- def __str__(self) -> str:
107
- return "SnippetDrop"