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/builtin/content.py
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
"""Pseudo tag and node definition for template content."""
|
|
2
|
-
|
|
3
|
-
from typing import TextIO
|
|
4
|
-
|
|
5
|
-
from liquid.ast import Node
|
|
6
|
-
from liquid.context import RenderContext
|
|
7
|
-
from liquid.stream import TokenStream
|
|
8
|
-
from liquid.tag import Tag
|
|
9
|
-
from liquid.token import TOKEN_CONTENT
|
|
10
|
-
from liquid.token import Token
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
class ContentNode(Node):
|
|
14
|
-
"""Parse tree node for template content."""
|
|
15
|
-
|
|
16
|
-
__slots__ = ("text",)
|
|
17
|
-
|
|
18
|
-
def __init__(self, token: Token, text: str):
|
|
19
|
-
super().__init__(token)
|
|
20
|
-
self.blank = not text or text.isspace()
|
|
21
|
-
self.text = text
|
|
22
|
-
|
|
23
|
-
def __str__(self) -> str:
|
|
24
|
-
return self.text
|
|
25
|
-
|
|
26
|
-
def render_to_output(self, _: RenderContext, buffer: TextIO) -> int:
|
|
27
|
-
"""Render the node to the output buffer."""
|
|
28
|
-
return buffer.write(self.text)
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
class Literal(Tag):
|
|
32
|
-
"""Pseudo "tag" for template content."""
|
|
33
|
-
|
|
34
|
-
name = TOKEN_CONTENT
|
|
35
|
-
block = False
|
|
36
|
-
node_class = ContentNode
|
|
37
|
-
|
|
38
|
-
def parse(self, stream: TokenStream) -> ContentNode:
|
|
39
|
-
"""Parse tokens from _stream_ into an AST node."""
|
|
40
|
-
token = stream.expect(TOKEN_CONTENT)
|
|
41
|
-
return self.node_class(token, token.value)
|
liquid/builtin/drops/__init__.py
DELETED
liquid/builtin/drops/drops.py
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
"""Legacy iterable drop base class."""
|
|
2
|
-
from abc import ABC
|
|
3
|
-
from abc import abstractmethod
|
|
4
|
-
from typing import Any
|
|
5
|
-
from typing import Collection
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class IterableDrop(ABC, Collection[Any]):
|
|
9
|
-
"""Base class for drops that can be iterated with `include` and `render` tags."""
|
|
10
|
-
|
|
11
|
-
@abstractmethod
|
|
12
|
-
def step(self, item: Any) -> None:
|
|
13
|
-
"""Step the iterator."""
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
from ._tokenize import tokenize # noqa: D104
|
|
2
|
-
from .arguments import KeywordArgument # noqa: D104
|
|
3
|
-
from .arguments import Parameter
|
|
4
|
-
from .arguments import PositionalArgument
|
|
5
|
-
from .arguments import parse_arguments
|
|
6
|
-
from .filtered import Filter
|
|
7
|
-
from .filtered import FilteredExpression
|
|
8
|
-
from .filtered import TernaryFilteredExpression
|
|
9
|
-
from .logical import BooleanExpression
|
|
10
|
-
from .loop import LoopExpression
|
|
11
|
-
from .path import Location
|
|
12
|
-
from .path import Path
|
|
13
|
-
from .path import Segments
|
|
14
|
-
from .primitive import Identifier
|
|
15
|
-
from .primitive import Literal
|
|
16
|
-
from .primitive import Nil
|
|
17
|
-
from .primitive import StringLiteral
|
|
18
|
-
from .primitive import is_empty
|
|
19
|
-
from .primitive import parse_identifier
|
|
20
|
-
from .primitive import parse_name
|
|
21
|
-
from .primitive import parse_primitive
|
|
22
|
-
from .primitive import parse_string_or_path
|
|
23
|
-
|
|
24
|
-
__all__ = (
|
|
25
|
-
"BooleanExpression",
|
|
26
|
-
"FilteredExpression",
|
|
27
|
-
"Identifier",
|
|
28
|
-
"is_empty",
|
|
29
|
-
"KeywordArgument",
|
|
30
|
-
"Literal",
|
|
31
|
-
"Location",
|
|
32
|
-
"LoopExpression",
|
|
33
|
-
"Nil",
|
|
34
|
-
"parse_arguments",
|
|
35
|
-
"parse_identifier",
|
|
36
|
-
"parse_primitive",
|
|
37
|
-
"parse_string_or_path",
|
|
38
|
-
"Path",
|
|
39
|
-
"PositionalArgument",
|
|
40
|
-
"Segments",
|
|
41
|
-
"StringLiteral",
|
|
42
|
-
"TernaryFilteredExpression",
|
|
43
|
-
"tokenize",
|
|
44
|
-
"parse_name",
|
|
45
|
-
"Parameter",
|
|
46
|
-
"Filter",
|
|
47
|
-
)
|
|
@@ -1,186 +0,0 @@
|
|
|
1
|
-
"""Tokenize a liquid expression."""
|
|
2
|
-
|
|
3
|
-
import re
|
|
4
|
-
import sys
|
|
5
|
-
from typing import Iterator
|
|
6
|
-
|
|
7
|
-
from liquid.exceptions import LiquidSyntaxError
|
|
8
|
-
from liquid.token import TOKEN_AND
|
|
9
|
-
from liquid.token import TOKEN_AS
|
|
10
|
-
from liquid.token import TOKEN_BLANK
|
|
11
|
-
from liquid.token import TOKEN_COLON
|
|
12
|
-
from liquid.token import TOKEN_COLS
|
|
13
|
-
from liquid.token import TOKEN_COMMA
|
|
14
|
-
from liquid.token import TOKEN_CONTAINS
|
|
15
|
-
from liquid.token import TOKEN_CONTINUE
|
|
16
|
-
from liquid.token import TOKEN_DOT
|
|
17
|
-
from liquid.token import TOKEN_DPIPE
|
|
18
|
-
from liquid.token import TOKEN_ELSE
|
|
19
|
-
from liquid.token import TOKEN_EMPTY
|
|
20
|
-
from liquid.token import TOKEN_FALSE
|
|
21
|
-
from liquid.token import TOKEN_FLOAT
|
|
22
|
-
from liquid.token import TOKEN_FOR
|
|
23
|
-
from liquid.token import TOKEN_IDENTINDEX
|
|
24
|
-
from liquid.token import TOKEN_IDENTSTRING
|
|
25
|
-
from liquid.token import TOKEN_IF
|
|
26
|
-
from liquid.token import TOKEN_ILLEGAL
|
|
27
|
-
from liquid.token import TOKEN_IN
|
|
28
|
-
from liquid.token import TOKEN_INTEGER
|
|
29
|
-
from liquid.token import TOKEN_LBRACKET
|
|
30
|
-
from liquid.token import TOKEN_LIMIT
|
|
31
|
-
from liquid.token import TOKEN_LPAREN
|
|
32
|
-
from liquid.token import TOKEN_NIL
|
|
33
|
-
from liquid.token import TOKEN_NOT
|
|
34
|
-
from liquid.token import TOKEN_NULL
|
|
35
|
-
from liquid.token import TOKEN_OFFSET
|
|
36
|
-
from liquid.token import TOKEN_OR
|
|
37
|
-
from liquid.token import TOKEN_PIPE
|
|
38
|
-
from liquid.token import TOKEN_RANGE
|
|
39
|
-
from liquid.token import TOKEN_RANGE_LITERAL
|
|
40
|
-
from liquid.token import TOKEN_RBRACKET
|
|
41
|
-
from liquid.token import TOKEN_REQUIRED
|
|
42
|
-
from liquid.token import TOKEN_REVERSED
|
|
43
|
-
from liquid.token import TOKEN_RPAREN
|
|
44
|
-
from liquid.token import TOKEN_SKIP
|
|
45
|
-
from liquid.token import TOKEN_STRING
|
|
46
|
-
from liquid.token import TOKEN_TRUE
|
|
47
|
-
from liquid.token import TOKEN_WITH
|
|
48
|
-
from liquid.token import TOKEN_WORD
|
|
49
|
-
from liquid.token import Token
|
|
50
|
-
from liquid.token import operators
|
|
51
|
-
|
|
52
|
-
GROUP_QUOTE = sys.intern("quote")
|
|
53
|
-
GROUP_QUOTED = sys.intern("quoted")
|
|
54
|
-
GROUP_IDENTINDEX = sys.intern("path_index")
|
|
55
|
-
GROUP_IDENTQUOTE = sys.intern("identquote")
|
|
56
|
-
GROUP_IDENTQUOTED = sys.intern("identquoted")
|
|
57
|
-
|
|
58
|
-
# The reference implementation will accept identifiers that start with an integer or
|
|
59
|
-
# hyphen when in lax mode, but will raise a syntax error in strict mode. For historic
|
|
60
|
-
# reasons we'll stick the following pattern until at least version 2 of Python Liquid.
|
|
61
|
-
IDENTIFIER_PATTERN = r"\w[\w\-]*\??"
|
|
62
|
-
|
|
63
|
-
# Trailing ? is not allowed in assignment names
|
|
64
|
-
ASSIGN_IDENTIFIER_PATTERN = r"\w[\w\-]*"
|
|
65
|
-
|
|
66
|
-
# ["ident"] or ['ident']
|
|
67
|
-
IDENTSTRING_PATTERN = (
|
|
68
|
-
rf"\[\s*(?P<{GROUP_IDENTQUOTE}>[\"'])"
|
|
69
|
-
rf"(?P<{GROUP_IDENTQUOTED}>.*?)"
|
|
70
|
-
rf"(?P={GROUP_IDENTQUOTE})\s*]"
|
|
71
|
-
)
|
|
72
|
-
|
|
73
|
-
# [0] or [-1]
|
|
74
|
-
IDENTINDEX_PATTERN = rf"\[\s*(?P<{GROUP_IDENTINDEX}>\-?\d+)\s*]"
|
|
75
|
-
|
|
76
|
-
# 'something' or "something"
|
|
77
|
-
STRING_PATTERN = rf"(?P<{GROUP_QUOTE}>[\"'])(?P<{GROUP_QUOTED}>.*?)(?P={GROUP_QUOTE})"
|
|
78
|
-
|
|
79
|
-
# Rules for the standard boolean expression.
|
|
80
|
-
# Does not support grouping with parentheses.
|
|
81
|
-
_rules = (
|
|
82
|
-
(TOKEN_RANGE_LITERAL, r"\((?=.+?\.\.)"),
|
|
83
|
-
(TOKEN_IDENTINDEX, IDENTINDEX_PATTERN),
|
|
84
|
-
(TOKEN_IDENTSTRING, IDENTSTRING_PATTERN),
|
|
85
|
-
(TOKEN_STRING, STRING_PATTERN),
|
|
86
|
-
(TOKEN_RANGE, r"\.\."),
|
|
87
|
-
(TOKEN_FLOAT, r"-?\d+\.(?!\.)\d*"),
|
|
88
|
-
(TOKEN_INTEGER, r"-?\d+\b"),
|
|
89
|
-
(TOKEN_DOT, r"\."),
|
|
90
|
-
(TOKEN_WORD, IDENTIFIER_PATTERN),
|
|
91
|
-
(TOKEN_LPAREN, r"\("),
|
|
92
|
-
(TOKEN_RPAREN, r"\)"),
|
|
93
|
-
(TOKEN_LBRACKET, r"\["),
|
|
94
|
-
(TOKEN_RBRACKET, r"]"),
|
|
95
|
-
(TOKEN_COLON, r":"),
|
|
96
|
-
(TOKEN_COMMA, r","),
|
|
97
|
-
(TOKEN_DPIPE, r"\|\|"),
|
|
98
|
-
(TOKEN_PIPE, r"\|"),
|
|
99
|
-
("OP", r"[!=<>]{1,2}"),
|
|
100
|
-
(TOKEN_SKIP, r"[ \n\t\r]+"),
|
|
101
|
-
(TOKEN_ILLEGAL, r"."),
|
|
102
|
-
)
|
|
103
|
-
|
|
104
|
-
# Keywords for the standard boolean expression.
|
|
105
|
-
# Excludes `not`.
|
|
106
|
-
_keywords = frozenset(
|
|
107
|
-
[
|
|
108
|
-
TOKEN_TRUE,
|
|
109
|
-
TOKEN_FALSE,
|
|
110
|
-
TOKEN_NIL,
|
|
111
|
-
TOKEN_NULL,
|
|
112
|
-
TOKEN_EMPTY,
|
|
113
|
-
TOKEN_BLANK,
|
|
114
|
-
TOKEN_AND,
|
|
115
|
-
TOKEN_OR,
|
|
116
|
-
TOKEN_CONTAINS,
|
|
117
|
-
TOKEN_NOT,
|
|
118
|
-
TOKEN_IN,
|
|
119
|
-
TOKEN_OFFSET,
|
|
120
|
-
TOKEN_LIMIT,
|
|
121
|
-
TOKEN_REVERSED,
|
|
122
|
-
TOKEN_COLS,
|
|
123
|
-
TOKEN_CONTINUE,
|
|
124
|
-
TOKEN_WITH,
|
|
125
|
-
TOKEN_FOR,
|
|
126
|
-
TOKEN_AS,
|
|
127
|
-
TOKEN_IF,
|
|
128
|
-
TOKEN_ELSE,
|
|
129
|
-
TOKEN_REQUIRED,
|
|
130
|
-
]
|
|
131
|
-
)
|
|
132
|
-
|
|
133
|
-
_RE = re.compile(
|
|
134
|
-
"|".join(f"(?P<{name}>{pattern})" for name, pattern in _rules),
|
|
135
|
-
re.DOTALL,
|
|
136
|
-
)
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
def tokenize(source: str, parent_token: Token) -> Iterator[Token]:
|
|
140
|
-
"""Tokenize a liquid expression."""
|
|
141
|
-
for match in _RE.finditer(source):
|
|
142
|
-
kind = match.lastgroup
|
|
143
|
-
assert kind is not None
|
|
144
|
-
|
|
145
|
-
value = match.group()
|
|
146
|
-
|
|
147
|
-
if kind == TOKEN_WORD and value in _keywords:
|
|
148
|
-
kind = value
|
|
149
|
-
elif kind == TOKEN_IDENTINDEX:
|
|
150
|
-
value = match.group(GROUP_IDENTINDEX)
|
|
151
|
-
elif kind == TOKEN_IDENTSTRING:
|
|
152
|
-
value = match.group(GROUP_IDENTQUOTED)
|
|
153
|
-
elif kind == TOKEN_STRING:
|
|
154
|
-
value = match.group(GROUP_QUOTED)
|
|
155
|
-
elif kind == "OP":
|
|
156
|
-
try:
|
|
157
|
-
kind = operators[value]
|
|
158
|
-
except KeyError as err:
|
|
159
|
-
raise LiquidSyntaxError(
|
|
160
|
-
f"unknown operator {value!r}",
|
|
161
|
-
token=Token(
|
|
162
|
-
kind,
|
|
163
|
-
value,
|
|
164
|
-
start_index=parent_token.start_index + match.start(),
|
|
165
|
-
source=parent_token.source,
|
|
166
|
-
),
|
|
167
|
-
) from err
|
|
168
|
-
elif kind == TOKEN_SKIP:
|
|
169
|
-
continue
|
|
170
|
-
elif kind == TOKEN_ILLEGAL:
|
|
171
|
-
raise LiquidSyntaxError(
|
|
172
|
-
f"unexpected {value!r}",
|
|
173
|
-
token=Token(
|
|
174
|
-
kind,
|
|
175
|
-
value,
|
|
176
|
-
start_index=parent_token.start_index + match.start(),
|
|
177
|
-
source=parent_token.source,
|
|
178
|
-
),
|
|
179
|
-
)
|
|
180
|
-
|
|
181
|
-
yield Token(
|
|
182
|
-
kind,
|
|
183
|
-
value,
|
|
184
|
-
start_index=parent_token.start_index + match.start(),
|
|
185
|
-
source=parent_token.source,
|
|
186
|
-
)
|
|
@@ -1,207 +0,0 @@
|
|
|
1
|
-
"""Tag expression argument helpers."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
from typing import TYPE_CHECKING
|
|
6
|
-
|
|
7
|
-
from liquid import Mode
|
|
8
|
-
from liquid.exceptions import LiquidSyntaxError
|
|
9
|
-
from liquid.token import TOKEN_ASSIGN
|
|
10
|
-
from liquid.token import TOKEN_COLON
|
|
11
|
-
from liquid.token import TOKEN_COMMA
|
|
12
|
-
from liquid.token import TOKEN_EOF
|
|
13
|
-
from liquid.token import TOKEN_WORD
|
|
14
|
-
|
|
15
|
-
from .primitive import parse_primitive
|
|
16
|
-
|
|
17
|
-
if TYPE_CHECKING:
|
|
18
|
-
from liquid import Environment
|
|
19
|
-
from liquid import RenderContext
|
|
20
|
-
from liquid import Token
|
|
21
|
-
from liquid import TokenStream
|
|
22
|
-
from liquid.expression import Expression
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
class KeywordArgument:
|
|
26
|
-
"""A name/value pair."""
|
|
27
|
-
|
|
28
|
-
__slots__ = ("token", "name", "value")
|
|
29
|
-
|
|
30
|
-
def __init__(self, token: Token, name: str, value: Expression) -> None:
|
|
31
|
-
self.token = token
|
|
32
|
-
self.name = name
|
|
33
|
-
self.value = value
|
|
34
|
-
|
|
35
|
-
def __str__(self) -> str:
|
|
36
|
-
return f"{self.name}:{self.value}"
|
|
37
|
-
|
|
38
|
-
def evaluate(self, context: RenderContext) -> tuple[str, object]:
|
|
39
|
-
return (self.name, self.value.evaluate(context))
|
|
40
|
-
|
|
41
|
-
async def evaluate_async(self, context: RenderContext) -> tuple[str, object]:
|
|
42
|
-
return (self.name, await self.value.evaluate_async(context))
|
|
43
|
-
|
|
44
|
-
@staticmethod
|
|
45
|
-
def parse(env: Environment, tokens: TokenStream) -> list[KeywordArgument]:
|
|
46
|
-
"""Parse a keyword arguments from _tokens_."""
|
|
47
|
-
argument_separators = (
|
|
48
|
-
(TOKEN_COLON, TOKEN_ASSIGN) if env.keyword_assignment else (TOKEN_COLON,)
|
|
49
|
-
)
|
|
50
|
-
|
|
51
|
-
args: list[KeywordArgument] = []
|
|
52
|
-
|
|
53
|
-
# Leading commas are OK
|
|
54
|
-
if tokens.current.kind == TOKEN_COMMA:
|
|
55
|
-
next(tokens)
|
|
56
|
-
|
|
57
|
-
while True:
|
|
58
|
-
token = next(tokens)
|
|
59
|
-
|
|
60
|
-
if token.kind == TOKEN_COMMA:
|
|
61
|
-
token = next(tokens)
|
|
62
|
-
|
|
63
|
-
if token.kind == TOKEN_EOF:
|
|
64
|
-
break
|
|
65
|
-
|
|
66
|
-
if token.kind == TOKEN_WORD:
|
|
67
|
-
tokens.eat_one_of(*argument_separators)
|
|
68
|
-
value = parse_primitive(env, tokens)
|
|
69
|
-
args.append(KeywordArgument(token, token.value, value))
|
|
70
|
-
if env.mode == Mode.STRICT and tokens.current.kind == TOKEN_WORD:
|
|
71
|
-
raise LiquidSyntaxError(
|
|
72
|
-
"expected a comma separated list of arguments, "
|
|
73
|
-
f"found {tokens.current.kind}",
|
|
74
|
-
token=tokens.current,
|
|
75
|
-
)
|
|
76
|
-
else:
|
|
77
|
-
raise LiquidSyntaxError(
|
|
78
|
-
f"expected an argument name, found {token.kind}", token=token
|
|
79
|
-
)
|
|
80
|
-
|
|
81
|
-
return args
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
class PositionalArgument:
|
|
85
|
-
"""Just a value."""
|
|
86
|
-
|
|
87
|
-
__slots__ = (
|
|
88
|
-
"token",
|
|
89
|
-
"value",
|
|
90
|
-
)
|
|
91
|
-
|
|
92
|
-
def __init__(self, value: Expression) -> None:
|
|
93
|
-
self.token = value.token
|
|
94
|
-
self.value = value
|
|
95
|
-
|
|
96
|
-
def __str__(self) -> str:
|
|
97
|
-
return str(self.value)
|
|
98
|
-
|
|
99
|
-
def evaluate(self, context: RenderContext) -> tuple[None, object]:
|
|
100
|
-
return (None, self.value.evaluate(context))
|
|
101
|
-
|
|
102
|
-
async def evaluate_async(self, context: RenderContext) -> tuple[None, object]:
|
|
103
|
-
return (None, await self.value.evaluate_async(context))
|
|
104
|
-
|
|
105
|
-
@staticmethod
|
|
106
|
-
def parse(env: Environment, tokens: TokenStream) -> list[PositionalArgument]:
|
|
107
|
-
"""Parse a positional arguments from _tokens_."""
|
|
108
|
-
args: list[PositionalArgument] = []
|
|
109
|
-
|
|
110
|
-
while True:
|
|
111
|
-
if tokens.current.kind == TOKEN_COMMA:
|
|
112
|
-
next(tokens)
|
|
113
|
-
|
|
114
|
-
if tokens.current.kind == TOKEN_EOF:
|
|
115
|
-
break
|
|
116
|
-
|
|
117
|
-
args.append(PositionalArgument(parse_primitive(env, tokens)))
|
|
118
|
-
|
|
119
|
-
return args
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
class Parameter:
|
|
123
|
-
"""A name, possibly with a default value."""
|
|
124
|
-
|
|
125
|
-
__slots__ = ("token", "name", "value")
|
|
126
|
-
|
|
127
|
-
def __init__(self, token: Token, name: str, value: Expression | None) -> None:
|
|
128
|
-
self.token = token
|
|
129
|
-
self.name = name
|
|
130
|
-
self.value = value
|
|
131
|
-
|
|
132
|
-
def __str__(self) -> str:
|
|
133
|
-
return f"{self.name}:{self.value}" if self.value else self.name
|
|
134
|
-
|
|
135
|
-
@staticmethod
|
|
136
|
-
def parse(env: Environment, tokens: TokenStream) -> dict[str, Parameter]:
|
|
137
|
-
"""Parse macro tag parameters from _tokens_."""
|
|
138
|
-
params: dict[str, Parameter] = {}
|
|
139
|
-
argument_separators = (
|
|
140
|
-
(TOKEN_COLON, TOKEN_ASSIGN) if env.keyword_assignment else (TOKEN_COLON,)
|
|
141
|
-
)
|
|
142
|
-
|
|
143
|
-
while True:
|
|
144
|
-
token = next(tokens)
|
|
145
|
-
|
|
146
|
-
if token.kind == TOKEN_COMMA:
|
|
147
|
-
# Leading and/or trailing commas are OK.
|
|
148
|
-
token = next(tokens)
|
|
149
|
-
|
|
150
|
-
if token.kind == TOKEN_EOF:
|
|
151
|
-
break
|
|
152
|
-
|
|
153
|
-
if token.kind == TOKEN_WORD:
|
|
154
|
-
if tokens.current.kind in argument_separators:
|
|
155
|
-
# A parameter with a default value
|
|
156
|
-
next(tokens) # Move past ":" or "="
|
|
157
|
-
value = parse_primitive(env, tokens)
|
|
158
|
-
params[token.value] = Parameter(token, token.value, value)
|
|
159
|
-
else:
|
|
160
|
-
params[token.value] = Parameter(token, token.value, None)
|
|
161
|
-
else:
|
|
162
|
-
raise LiquidSyntaxError(
|
|
163
|
-
f"expected a parameter list, found {token.kind}",
|
|
164
|
-
token=token,
|
|
165
|
-
)
|
|
166
|
-
|
|
167
|
-
return params
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
def parse_arguments(
|
|
171
|
-
env: Environment, tokens: TokenStream
|
|
172
|
-
) -> tuple[list[PositionalArgument], list[KeywordArgument]]:
|
|
173
|
-
"""Parse arguments from _tokens_ until end of input."""
|
|
174
|
-
args: list[PositionalArgument] = []
|
|
175
|
-
kwargs: list[KeywordArgument] = []
|
|
176
|
-
argument_separators = (
|
|
177
|
-
(TOKEN_COLON, TOKEN_ASSIGN) if env.keyword_assignment else (TOKEN_COLON,)
|
|
178
|
-
)
|
|
179
|
-
|
|
180
|
-
# Leading commas are OK
|
|
181
|
-
if tokens.current.kind == TOKEN_COMMA:
|
|
182
|
-
next(tokens)
|
|
183
|
-
|
|
184
|
-
while True:
|
|
185
|
-
token = tokens.current
|
|
186
|
-
|
|
187
|
-
if token.kind == TOKEN_EOF:
|
|
188
|
-
break
|
|
189
|
-
|
|
190
|
-
if token.kind == TOKEN_WORD:
|
|
191
|
-
if tokens.peek.kind in argument_separators:
|
|
192
|
-
name_token = next(tokens)
|
|
193
|
-
next(tokens) # = or :
|
|
194
|
-
value = parse_primitive(env, tokens)
|
|
195
|
-
kwargs.append(KeywordArgument(name_token, token.value, value))
|
|
196
|
-
else:
|
|
197
|
-
args.append(PositionalArgument(parse_primitive(env, tokens)))
|
|
198
|
-
else:
|
|
199
|
-
# A primitive as a positional argument
|
|
200
|
-
args.append(PositionalArgument(parse_primitive(env, tokens)))
|
|
201
|
-
|
|
202
|
-
if tokens.current.kind != TOKEN_COMMA:
|
|
203
|
-
break
|
|
204
|
-
|
|
205
|
-
tokens.eat(TOKEN_COMMA)
|
|
206
|
-
|
|
207
|
-
return args, kwargs
|