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,275 +0,0 @@
1
- """Built-in loop expressions."""
2
-
3
- from __future__ import annotations
4
-
5
- from itertools import islice
6
- from typing import TYPE_CHECKING
7
- from typing import Any
8
- from typing import Iterator
9
- from typing import Mapping
10
- from typing import Sequence
11
- from typing import Union
12
-
13
- from liquid import Mode
14
- from liquid.exceptions import LiquidSyntaxError
15
- from liquid.exceptions import LiquidTypeError
16
- from liquid.exceptions import LiquidValueError
17
- from liquid.expression import Expression
18
- from liquid.limits import to_int
19
- from liquid.token import TOKEN_ASSIGN
20
- from liquid.token import TOKEN_COLON
21
- from liquid.token import TOKEN_COLS
22
- from liquid.token import TOKEN_COMMA
23
- from liquid.token import TOKEN_CONTINUE
24
- from liquid.token import TOKEN_EOF
25
- from liquid.token import TOKEN_IN
26
- from liquid.token import TOKEN_LIMIT
27
- from liquid.token import TOKEN_OFFSET
28
- from liquid.token import TOKEN_REVERSED
29
-
30
- from .primitive import StringLiteral
31
- from .primitive import parse_identifier
32
- from .primitive import parse_primitive
33
-
34
- if TYPE_CHECKING:
35
- from liquid import Environment
36
- from liquid import RenderContext
37
- from liquid import TokenStream
38
- from liquid.token import Token
39
-
40
-
41
- class LoopExpression(Expression):
42
- """An expression for the `for` and `tablerow` tag."""
43
-
44
- __slots__ = ("identifier", "iterable", "limit", "offset", "reversed", "cols")
45
-
46
- def __init__(
47
- self,
48
- token: Token,
49
- identifier: str,
50
- iterable: Expression,
51
- *,
52
- limit: Expression | None,
53
- offset: Expression | None,
54
- reversed_: bool,
55
- cols: Expression | None,
56
- ) -> None:
57
- super().__init__(token)
58
- self.identifier = identifier
59
- self.iterable = iterable
60
- self.limit = limit
61
- self.offset = offset
62
- self.reversed = reversed_
63
- self.cols = cols
64
-
65
- def __eq__(self, other: object) -> bool:
66
- return (
67
- isinstance(other, LoopExpression)
68
- and self.identifier == other.identifier
69
- and self.iterable == other.iterable
70
- and self.limit == other.limit
71
- and self.offset == other.offset
72
- and self.cols == other.cols
73
- and self.reversed == other.reversed
74
- )
75
-
76
- def __str__(self) -> str:
77
- buf = [f"{self.identifier} in", str(self.iterable)]
78
-
79
- if self.limit is not None:
80
- buf.append(f"limit:{self.limit}")
81
-
82
- if self.offset is not None:
83
- buf.append(f"offset:{self.offset}")
84
-
85
- if self.cols is not None:
86
- buf.append(f"cols:{self.cols}")
87
-
88
- if self.reversed:
89
- buf.append("reversed")
90
-
91
- return " ".join(buf)
92
-
93
- def _to_iter(
94
- self, obj: object, context: RenderContext
95
- ) -> tuple[Iterator[Any], int]:
96
- if isinstance(obj, Mapping):
97
- return iter(obj.items()), len(obj)
98
- if isinstance(obj, range):
99
- try:
100
- return iter(obj), len(obj)
101
- except OverflowError as err:
102
- raise LiquidValueError(
103
- "range literal length limit reached", token=None
104
- ) from err
105
- if isinstance(obj, str) and not context.env.string_sequences:
106
- return (iter([]), 0) if not obj else (iter([obj]), 1)
107
- if isinstance(obj, Sequence):
108
- return iter(obj), len(obj)
109
-
110
- return iter([]), 0
111
-
112
- def _to_int(self, obj: object, *, token: Token) -> int:
113
- try:
114
- return to_int(obj)
115
- except (ValueError, TypeError) as err:
116
- raise LiquidTypeError(
117
- f"expected an integer, found {obj.__class__.__name__}",
118
- token=token,
119
- ) from err
120
-
121
- def _slice(
122
- self,
123
- it: Iterator[object],
124
- length: int,
125
- context: RenderContext,
126
- *,
127
- limit: int | None,
128
- offset: int | str | None,
129
- ) -> tuple[Iterator[object], int]:
130
- offset_key = f"{self.identifier}-{self.iterable}"
131
-
132
- if offset == "continue":
133
- start = context.stopindex(offset_key)
134
- else:
135
- start = int(offset or 0)
136
-
137
- stop = None if limit is None else limit + start
138
-
139
- start_ = min(max(start, 0), length)
140
- stop_ = min(stop or length, length)
141
- length_ = max(stop_ - start_, 0)
142
-
143
- context.stopindex(key=offset_key, index=stop_)
144
- it = islice(it, start_, stop_)
145
-
146
- if self.reversed:
147
- return reversed(list(it)), length_
148
- return it, length_
149
-
150
- def evaluate(self, context: RenderContext) -> tuple[Iterator[object], int]:
151
- it, length = self._to_iter(self.iterable.evaluate(context), context)
152
- limit = (
153
- self._to_int(self.limit.evaluate(context), token=self.limit.token)
154
- if self.limit
155
- else None
156
- )
157
-
158
- if isinstance(self.offset, StringLiteral):
159
- offset: Union[str, int, None] = self.offset.value
160
- if offset != "continue":
161
- offset = self._to_int(offset, token=self.offset.token)
162
- elif self.offset is None:
163
- offset = None
164
- else:
165
- offset = self._to_int(
166
- self.offset.evaluate(context), token=self.offset.token
167
- )
168
-
169
- return self._slice(it, length, context, limit=limit, offset=offset)
170
-
171
- async def evaluate_async(
172
- self, context: RenderContext
173
- ) -> tuple[Iterator[object], int]:
174
- it, length = self._to_iter(await self.iterable.evaluate_async(context), context)
175
- limit = (
176
- self._to_int(
177
- await self.limit.evaluate_async(context), token=self.limit.token
178
- )
179
- if self.limit
180
- else None
181
- )
182
-
183
- if self.offset is None:
184
- offset: str | int | None = None
185
- elif isinstance(self.offset, StringLiteral):
186
- offset = self.offset.evaluate(context)
187
- if offset != "continue":
188
- offset = self._to_int(offset, token=self.offset.token)
189
- else:
190
- offset = self._to_int(
191
- await self.offset.evaluate_async(context), token=self.offset.token
192
- )
193
-
194
- return self._slice(it, length, context, limit=limit, offset=offset)
195
-
196
- def children(self) -> list[Expression]:
197
- children = [self.iterable]
198
-
199
- if self.limit is not None:
200
- children.append(self.limit)
201
-
202
- if self.offset is not None:
203
- children.append(self.offset)
204
-
205
- if self.cols is not None:
206
- children.append(self.cols)
207
-
208
- return children
209
-
210
- @staticmethod
211
- def parse(env: Environment, tokens: TokenStream) -> LoopExpression:
212
- """Parse a loop expression from _tokens_."""
213
- token = tokens.current
214
- identifier = parse_identifier(env, tokens)
215
- tokens.eat(TOKEN_IN)
216
- iterable = parse_primitive(env, tokens)
217
-
218
- reversed_ = False
219
- offset: Expression | None = None
220
- limit: Expression | None = None
221
- cols: Expression | None = None
222
-
223
- argument_separators = (
224
- (TOKEN_COLON, TOKEN_ASSIGN) if env.keyword_assignment else (TOKEN_COLON,)
225
- )
226
-
227
- # Leading commas are OK
228
- if tokens.current.kind == TOKEN_COMMA:
229
- next(tokens)
230
-
231
- while True:
232
- arg_token = next(tokens)
233
- kind = arg_token.kind
234
-
235
- if kind == TOKEN_LIMIT:
236
- tokens.eat_one_of(*argument_separators)
237
- limit = parse_primitive(env, tokens)
238
- elif kind == TOKEN_REVERSED:
239
- reversed_ = True
240
- elif kind == TOKEN_OFFSET:
241
- tokens.eat_one_of(*argument_separators)
242
- offset_token = tokens.current
243
- if offset_token.kind == TOKEN_CONTINUE:
244
- next(tokens)
245
- offset = StringLiteral(token=offset_token, value="continue")
246
- else:
247
- offset = parse_primitive(env, tokens)
248
- elif kind == TOKEN_COLS:
249
- tokens.eat_one_of(*argument_separators)
250
- cols = parse_primitive(env, tokens)
251
- elif kind == TOKEN_COMMA:
252
- if env.mode == Mode.STRICT and tokens.peek.kind == TOKEN_COMMA:
253
- raise LiquidSyntaxError(
254
- f"expected 'reversed', 'offset' or 'limit', found {kind}",
255
- token=tokens.peek,
256
- )
257
- continue
258
- elif kind == TOKEN_EOF:
259
- break
260
- else:
261
- raise LiquidSyntaxError(
262
- "expected 'reversed', 'offset' or 'limit'",
263
- token=arg_token,
264
- )
265
-
266
- tokens.eat(TOKEN_EOF)
267
- return LoopExpression(
268
- token,
269
- identifier,
270
- iterable,
271
- limit=limit,
272
- offset=offset,
273
- reversed_=reversed_,
274
- cols=cols,
275
- )
@@ -1,163 +0,0 @@
1
- """A built-in expression for paths to a value/variable.
2
-
3
- Note that a path might contain just one segment, in which case we might just
4
- call it a "variable".
5
- """
6
-
7
- from __future__ import annotations
8
-
9
- import re
10
- import sys
11
- from typing import TYPE_CHECKING
12
- from typing import Union
13
-
14
- from liquid import Mode
15
- from liquid.exceptions import LiquidSyntaxError
16
- from liquid.expression import Expression
17
- from liquid.limits import to_int
18
- from liquid.token import TOKEN_DOT
19
- from liquid.token import TOKEN_FLOAT
20
- from liquid.token import TOKEN_IDENTINDEX
21
- from liquid.token import TOKEN_IDENTSTRING
22
- from liquid.token import TOKEN_INTEGER
23
- from liquid.token import TOKEN_LBRACKET
24
- from liquid.token import TOKEN_RBRACKET
25
- from liquid.token import TOKEN_WORD
26
-
27
- if TYPE_CHECKING:
28
- from liquid import Environment
29
- from liquid import RenderContext
30
- from liquid import Token
31
- from liquid import TokenStream
32
-
33
- Segments = list[Union[str, int, "Path"]]
34
- Location = tuple[Union[str, int, "Location"], ...]
35
-
36
-
37
- # This is use for pretty printing paths with shorthand notation where possible.
38
- RE_PROPERTY = re.compile(r"[\u0080-\uFFFFa-zA-Z_][\u0080-\uFFFFa-zA-Z0-9_-]*")
39
-
40
-
41
- class Path(Expression):
42
- __slots__ = ("path",)
43
-
44
- def __init__(self, token: Token, path: Segments):
45
- super().__init__(token)
46
- self.path = path
47
-
48
- def __eq__(self, other: object) -> bool:
49
- return isinstance(other, Path) and self.path == other.path
50
-
51
- def __str__(self) -> str:
52
- it = iter(self.path)
53
- buf = [str(next(it))]
54
- for segment in it:
55
- if isinstance(segment, Path):
56
- buf.append(f"[{segment}]")
57
- elif isinstance(segment, str):
58
- if RE_PROPERTY.fullmatch(segment):
59
- buf.append(f".{segment}")
60
- else:
61
- buf.append(f"[{segment!r}]")
62
- else:
63
- buf.append(f"[{segment}]")
64
- return "".join(buf)
65
-
66
- def __hash__(self) -> int:
67
- return hash(self.path)
68
-
69
- def __sizeof__(self) -> int:
70
- return super().__sizeof__() + sys.getsizeof(self.path)
71
-
72
- def location(self) -> Location:
73
- """Return this path's segments as a tuple of strings and ints.
74
-
75
- Segments can also be nested tuples of strings, ints and tuples if the path
76
- contains nested paths.
77
- """
78
- return tuple([s.location() if isinstance(s, Path) else s for s in self.path])
79
-
80
- def head(self) -> int | str | Path:
81
- return self.path[0]
82
-
83
- def evaluate(self, context: RenderContext) -> object:
84
- return context.get(
85
- [p.evaluate(context) if isinstance(p, Path) else p for p in self.path],
86
- token=self.token,
87
- )
88
-
89
- async def evaluate_async(self, context: RenderContext) -> object:
90
- return await context.get_async(
91
- [
92
- await p.evaluate_async(context) if isinstance(p, Path) else p
93
- for p in self.path
94
- ],
95
- token=self.token,
96
- )
97
-
98
- def children(self) -> list[Expression]:
99
- return [p for p in self.path if isinstance(p, Expression)]
100
-
101
- @staticmethod
102
- def parse(env: Environment, tokens: TokenStream) -> Path: # noqa: PLR0912
103
- token = tokens.current
104
- segments: Segments = []
105
-
106
- while True:
107
- kind, value, _index, _source = tokens.current
108
-
109
- if kind == TOKEN_WORD:
110
- segments.append(value)
111
- if tokens.peek.kind == TOKEN_WORD:
112
- # Two consecutive words indicate end of path.
113
- next(tokens)
114
- break
115
- elif kind == TOKEN_IDENTSTRING:
116
- segments.append(value)
117
- if env.mode == Mode.STRICT and tokens.peek.kind == TOKEN_WORD:
118
- raise LiquidSyntaxError(
119
- f"expected a dot or bracket notation, found {tokens.peek.kind}",
120
- token=tokens.peek,
121
- )
122
- elif kind == TOKEN_IDENTINDEX:
123
- segments.append(to_int(value))
124
- if env.mode == Mode.STRICT and tokens.peek.kind == TOKEN_WORD:
125
- raise LiquidSyntaxError(
126
- f"expected a dot or bracket notation, found {tokens.peek.kind}",
127
- token=tokens.peek,
128
- )
129
- elif kind == TOKEN_LBRACKET:
130
- next(tokens)
131
- segments.append(Path.parse(env, tokens))
132
- tokens.expect(TOKEN_RBRACKET)
133
- if env.mode == Mode.STRICT and tokens.peek.kind == TOKEN_WORD:
134
- raise LiquidSyntaxError(
135
- f"expected a dot or bracket notation, found {tokens.peek.kind}",
136
- token=tokens.peek,
137
- )
138
- elif kind == TOKEN_DOT:
139
- if (
140
- not env.shorthand_indexes
141
- and env.mode == Mode.STRICT
142
- and tokens.peek.kind != TOKEN_WORD
143
- ):
144
- raise LiquidSyntaxError(
145
- f"expected an identifier, found {tokens.peek.kind}",
146
- token=tokens.peek,
147
- )
148
- elif kind == TOKEN_FLOAT and env.shorthand_indexes:
149
- segments.extend(to_int(i) for i in value.rstrip(".").split("."))
150
- elif kind == TOKEN_INTEGER and env.shorthand_indexes:
151
- segments.append(to_int(value))
152
- else:
153
- break
154
-
155
- next(tokens)
156
-
157
- if not segments:
158
- raise LiquidSyntaxError(
159
- "missing or unexpected path segment",
160
- token=tokens.current,
161
- )
162
-
163
- return Path(token, segments)