python-liquid 2.2.2__tar.gz → 2.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {python_liquid-2.2.2 → python_liquid-2.3.0}/PKG-INFO +1 -1
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/__init__.py +1 -1
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/builtin/expressions/loop.py +12 -18
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/builtin/expressions/primitive.py +14 -1
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/builtin/loaders/file_system_loader.py +5 -1
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/builtin/tags/liquid_tag.py +2 -1
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/environment.py +6 -1
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/exceptions.py +4 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/parser.py +6 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/stream.py +2 -4
- {python_liquid-2.2.2 → python_liquid-2.3.0}/pyproject.toml +1 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/.gitignore +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/LICENSE +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/README.md +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/analyze_tags.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/ast.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/builtin/__init__.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/builtin/content.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/builtin/drops/__init__.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/builtin/drops/drops.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/builtin/expressions/__init__.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/builtin/expressions/_tokenize.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/builtin/expressions/arguments.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/builtin/expressions/filtered.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/builtin/expressions/logical.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/builtin/expressions/path.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/builtin/filters/__init__.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/builtin/filters/array.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/builtin/filters/extra.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/builtin/filters/math.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/builtin/filters/misc.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/builtin/filters/string.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/builtin/illegal.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/builtin/loaders/__init__.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/builtin/loaders/caching_file_system_loader.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/builtin/loaders/choice_loader.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/builtin/loaders/dict_loader.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/builtin/loaders/mixins.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/builtin/loaders/package_loader.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/builtin/output.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/builtin/tags/__init__.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/builtin/tags/assign_tag.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/builtin/tags/capture_tag.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/builtin/tags/case_tag.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/builtin/tags/comment_tag.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/builtin/tags/cycle_tag.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/builtin/tags/decrement_tag.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/builtin/tags/doc_tag.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/builtin/tags/echo_tag.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/builtin/tags/for_tag.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/builtin/tags/if_tag.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/builtin/tags/ifchanged_tag.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/builtin/tags/include_tag.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/builtin/tags/increment_tag.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/builtin/tags/inline_comment_tag.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/builtin/tags/render_tag.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/builtin/tags/tablerow_tag.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/builtin/tags/unless_tag.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/context.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/expression.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/extra/__init__.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/extra/filters/__init__.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/extra/filters/_json.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/extra/filters/array.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/extra/filters/babel.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/extra/filters/html.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/extra/filters/translate.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/extra/tags/__init__.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/extra/tags/_with.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/extra/tags/extends_tag.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/extra/tags/macro_tag.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/extra/tags/snippet_tag.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/extra/tags/translate_tag.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/filter.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/future/__init__.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/future/environment.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/future/filters/__init__.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/future/tags/__init__.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/lex.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/limits.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/loader.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/messages.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/mode.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/output.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/py.typed +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/span.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/static_analysis.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/stringify.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/tag.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/template.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/token.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/undefined.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/utils/__init__.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/utils/chain_map.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/utils/html.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/utils/lru_cache.py +0 -0
- {python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/utils/text.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-liquid
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.3.0
|
|
4
4
|
Summary: A Python engine for the Liquid template language.
|
|
5
5
|
Project-URL: Change Log, https://github.com/jg-rp/liquid/blob/main/CHANGES.md
|
|
6
6
|
Project-URL: Documentation, https://jg-rp.github.io/liquid/
|
|
@@ -123,29 +123,23 @@ class LoopExpression(Expression):
|
|
|
123
123
|
) -> tuple[Iterator[object], int]:
|
|
124
124
|
offset_key = f"{self.identifier}-{self.iterable}"
|
|
125
125
|
|
|
126
|
-
if limit is None and offset is None:
|
|
127
|
-
context.stopindex(key=offset_key, index=length)
|
|
128
|
-
if self.reversed:
|
|
129
|
-
return reversed(list(it)), length
|
|
130
|
-
return it, length
|
|
131
|
-
|
|
132
126
|
if offset == "continue":
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
127
|
+
start = context.stopindex(offset_key)
|
|
128
|
+
else:
|
|
129
|
+
start = int(offset or 0)
|
|
130
|
+
|
|
131
|
+
stop = None if limit is None else limit + start
|
|
138
132
|
|
|
139
|
-
|
|
140
|
-
|
|
133
|
+
start_ = min(max(start, 0), length)
|
|
134
|
+
stop_ = min(stop or length, length)
|
|
135
|
+
length_ = max(stop_ - start_, 0)
|
|
141
136
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
it = islice(it, offset, stop)
|
|
137
|
+
context.stopindex(key=offset_key, index=stop_)
|
|
138
|
+
it = islice(it, start_, stop_)
|
|
145
139
|
|
|
146
140
|
if self.reversed:
|
|
147
|
-
return reversed(list(it)),
|
|
148
|
-
return it,
|
|
141
|
+
return reversed(list(it)), length_
|
|
142
|
+
return it, length_
|
|
149
143
|
|
|
150
144
|
def evaluate(self, context: RenderContext) -> tuple[Iterator[object], int]:
|
|
151
145
|
it, length = self._to_iter(self.iterable.evaluate(context), context)
|
|
@@ -39,6 +39,12 @@ if TYPE_CHECKING:
|
|
|
39
39
|
from liquid import TokenStream
|
|
40
40
|
|
|
41
41
|
|
|
42
|
+
# MAX_RANGE = (2**53) - 1
|
|
43
|
+
# MIN_RANGE = -(2**53) + 1
|
|
44
|
+
MAX_RANGE = 1024
|
|
45
|
+
MIN_RANGE = -1024
|
|
46
|
+
|
|
47
|
+
|
|
42
48
|
class Nil(Expression):
|
|
43
49
|
__slots__ = ()
|
|
44
50
|
|
|
@@ -249,7 +255,9 @@ class RangeLiteral(Expression):
|
|
|
249
255
|
if start > stop:
|
|
250
256
|
return range(0)
|
|
251
257
|
|
|
252
|
-
return range(
|
|
258
|
+
return range(
|
|
259
|
+
clamp(start, MIN_RANGE, MAX_RANGE), clamp(stop + 1, MIN_RANGE, MAX_RANGE)
|
|
260
|
+
)
|
|
253
261
|
|
|
254
262
|
def evaluate(self, context: RenderContext) -> range:
|
|
255
263
|
return self._make_range(
|
|
@@ -415,3 +423,8 @@ def parse_string_or_path(
|
|
|
415
423
|
def is_empty(obj: object) -> bool:
|
|
416
424
|
"""Return True if _obj_ is considered empty."""
|
|
417
425
|
return isinstance(obj, (list, dict, str)) and not obj
|
|
426
|
+
|
|
427
|
+
|
|
428
|
+
def clamp(n: int, min_value: int, max_value: int) -> int:
|
|
429
|
+
"""Clamp _n_ between _min_value_ and _max_value_."""
|
|
430
|
+
return max(min_value, min(n, max_value))
|
|
@@ -76,7 +76,11 @@ class FileSystemLoader(BaseLoader):
|
|
|
76
76
|
for base in self.search_path:
|
|
77
77
|
source_path = base.joinpath(template_path)
|
|
78
78
|
|
|
79
|
-
|
|
79
|
+
try:
|
|
80
|
+
if not source_path.exists() or not source_path.is_file():
|
|
81
|
+
continue
|
|
82
|
+
except OSError:
|
|
83
|
+
# "File name too long", for example
|
|
80
84
|
continue
|
|
81
85
|
|
|
82
86
|
if self.reject_symlinks:
|
|
@@ -18,6 +18,7 @@ from . import builtin
|
|
|
18
18
|
from .analyze_tags import InnerTagMap
|
|
19
19
|
from .analyze_tags import TagAnalysis
|
|
20
20
|
from .builtin import DictLoader
|
|
21
|
+
from .exceptions import BlockNestingError
|
|
21
22
|
from .exceptions import LiquidError
|
|
22
23
|
from .exceptions import LiquidSyntaxError
|
|
23
24
|
from .exceptions import TemplateInheritanceError
|
|
@@ -79,6 +80,10 @@ class Environment:
|
|
|
79
80
|
template loaded from this environment.
|
|
80
81
|
"""
|
|
81
82
|
|
|
83
|
+
block_nesting_limit: ClassVar[int] = 30
|
|
84
|
+
"""The maximum markup block nesting depth allowed before a `BlockNestingError`
|
|
85
|
+
exception is raised."""
|
|
86
|
+
|
|
82
87
|
context_depth_limit: ClassVar[int] = 30
|
|
83
88
|
"""The maximum number of times a render context can be extended or wrapped before
|
|
84
89
|
raising a `ContextDepthError`."""
|
|
@@ -275,7 +280,7 @@ class Environment:
|
|
|
275
280
|
"""
|
|
276
281
|
try:
|
|
277
282
|
nodes = self._parse(source)
|
|
278
|
-
except (LiquidSyntaxError, TemplateInheritanceError) as err:
|
|
283
|
+
except (LiquidSyntaxError, TemplateInheritanceError, BlockNestingError) as err:
|
|
279
284
|
err.template_name = path
|
|
280
285
|
raise err
|
|
281
286
|
except Exception as err: # noqa: BLE001
|
|
@@ -191,6 +191,10 @@ class ResourceLimitError(LiquidError):
|
|
|
191
191
|
"""Base class for exceptions relating to resource limits."""
|
|
192
192
|
|
|
193
193
|
|
|
194
|
+
class BlockNestingError(ResourceLimitError):
|
|
195
|
+
"""The exception raised when block nesting limit is reached."""
|
|
196
|
+
|
|
197
|
+
|
|
194
198
|
class ContextDepthError(ResourceLimitError):
|
|
195
199
|
"""Exception raised when the maximum context depth is reached.
|
|
196
200
|
|
|
@@ -9,6 +9,7 @@ from typing import Iterator
|
|
|
9
9
|
|
|
10
10
|
from .ast import BlockNode
|
|
11
11
|
from .ast import Node
|
|
12
|
+
from .exceptions import BlockNestingError
|
|
12
13
|
from .exceptions import LiquidError
|
|
13
14
|
from .token import TOKEN_COMMENT
|
|
14
15
|
from .token import TOKEN_CONTENT
|
|
@@ -69,6 +70,10 @@ class Parser:
|
|
|
69
70
|
output = tags[TOKEN_OUTPUT]
|
|
70
71
|
|
|
71
72
|
nodes: list[Node] = []
|
|
73
|
+
stream.block_depth += 1
|
|
74
|
+
|
|
75
|
+
if stream.block_depth > self.env.block_nesting_limit:
|
|
76
|
+
raise BlockNestingError("block nesting limit reached", token=None)
|
|
72
77
|
|
|
73
78
|
while stream.current.kind != TOKEN_EOF:
|
|
74
79
|
if stream.current.kind == TOKEN_TAG and stream.current.value in end:
|
|
@@ -92,6 +97,7 @@ class Parser:
|
|
|
92
97
|
|
|
93
98
|
next(stream)
|
|
94
99
|
|
|
100
|
+
stream.block_depth -= 1
|
|
95
101
|
return BlockNode(stream.current, nodes)
|
|
96
102
|
|
|
97
103
|
|
|
@@ -18,12 +18,10 @@ class TokenStream:
|
|
|
18
18
|
|
|
19
19
|
eof = Token(TOKEN_EOF, TOKEN_EOF, -1, "")
|
|
20
20
|
|
|
21
|
-
def __init__(
|
|
22
|
-
self,
|
|
23
|
-
tokens: Iterator[Token],
|
|
24
|
-
):
|
|
21
|
+
def __init__(self, tokens: Iterator[Token], block_depth_carry: int = 0):
|
|
25
22
|
self.tokens = list(tokens)
|
|
26
23
|
self.pos = 0
|
|
24
|
+
self.block_depth = block_depth_carry
|
|
27
25
|
|
|
28
26
|
def __next__(self) -> Token:
|
|
29
27
|
return self.next_token()
|
|
@@ -160,6 +160,7 @@ convention = "google"
|
|
|
160
160
|
"liquid/builtin/loaders/__init__.py" = ["D104", "I001"]
|
|
161
161
|
"liquid/builtin/tags/__init__.py" = ["D104", "I001"]
|
|
162
162
|
"tests/*" = ["D100", "D101", "D104", "D103", "D102", "D209", "D205", "SIM117"]
|
|
163
|
+
"tests/test_compliance.py" = ["E501"]
|
|
163
164
|
"performance/*" = ["D103", "PLR2004", "T201", "D100"]
|
|
164
165
|
"liquid/builtin/expressions/primitive.py" = ["D101", "D102"]
|
|
165
166
|
"liquid/builtin/expressions/path.py" = ["D101", "D102"]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_liquid-2.2.2 → python_liquid-2.3.0}/liquid/builtin/loaders/caching_file_system_loader.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|