python-liquid 2.2.1__py3-none-any.whl → 2.2.2__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/__init__.py CHANGED
@@ -56,7 +56,7 @@ from .tag import Tag
56
56
 
57
57
  from . import future
58
58
 
59
- __version__ = "2.2.1"
59
+ __version__ = "2.2.2"
60
60
 
61
61
  __all__ = (
62
62
  "AwareBoundTemplate",
@@ -29,6 +29,9 @@ class FileSystemLoader(BaseLoader):
29
29
  ext: A default file extension. Should include a leading period.
30
30
  reject_symlinks: When `True`, reject paths to symlinks that resolve to files
31
31
  outside the search path. Defaults to `False`.
32
+
33
+ Raise:
34
+ ValueError if `ext` is not a valid suffix.
32
35
  """
33
36
 
34
37
  def __init__(
@@ -48,6 +51,10 @@ class FileSystemLoader(BaseLoader):
48
51
  self.ext = ext
49
52
  self.reject_symlinks = reject_symlinks
50
53
 
54
+ # Raise a ValueError early if `ext` is invalid.
55
+ if ext:
56
+ Path("x").with_suffix(ext)
57
+
51
58
  def resolve_path(self, template_name: str) -> Path:
52
59
  """Return a path to the template identified by _template_name_.
53
60
 
@@ -57,6 +64,9 @@ class FileSystemLoader(BaseLoader):
57
64
  """
58
65
  template_path = Path(template_name)
59
66
 
67
+ if not template_path.name:
68
+ raise TemplateNotFoundError(template_name)
69
+
60
70
  if self.ext and not template_path.suffix:
61
71
  template_path = template_path.with_suffix(self.ext)
62
72
 
@@ -11,6 +11,7 @@ from typing import TextIO
11
11
  from liquid.ast import Node
12
12
  from liquid.builtin.expressions import PositionalArgument
13
13
  from liquid.builtin.expressions import parse_primitive
14
+ from liquid.exceptions import LiquidSyntaxError
14
15
  from liquid.stringify import to_liquid_string
15
16
  from liquid.tag import Tag
16
17
  from liquid.token import TOKEN_COLON
@@ -124,4 +125,8 @@ class CycleTag(Tag):
124
125
  tokens.eat(TOKEN_COLON)
125
126
 
126
127
  args = PositionalArgument.parse(self.env, tokens)
128
+
129
+ if not args:
130
+ raise LiquidSyntaxError("expected at least one argument", token=token)
131
+
127
132
  return self.node_class(token, group_name, [arg.value for arg in args])
liquid/context.py CHANGED
@@ -175,7 +175,12 @@ class RenderContext:
175
175
  """
176
176
  it = iter(path)
177
177
  root = next(it)
178
- assert isinstance(root, str)
178
+
179
+ if not isinstance(root, str):
180
+ if default == UNDEFINED:
181
+ hint = f"{root} is undefined"
182
+ return self.env.undefined(str(root), hint=hint, token=token)
183
+ return default
179
184
 
180
185
  try:
181
186
  obj = self.scope[root]
@@ -316,7 +321,7 @@ class RenderContext:
316
321
  """Return the index of the next item in the cycle."""
317
322
  namespace: dict[object, int] = self.tag_namespace["cycles"]
318
323
  idx = namespace.setdefault(key, 0)
319
- namespace[key] = (idx + 1) % length
324
+ namespace[key] = (idx + 1) % (length or 1) # Just in case.
320
325
  return idx
321
326
 
322
327
  def ifchanged(self, val: str) -> bool:
@@ -35,16 +35,20 @@ class WithNode(Node):
35
35
  self.block = block
36
36
  self.blank = self.block.blank
37
37
 
38
- def render_to_output(self, context: RenderContext, buffer: TextIO) -> int:
39
- namespace = dict(arg.evaluate(context) for arg in self.args)
40
-
41
- with context.extend(namespace):
38
+ def render_to_output(
39
+ self,
40
+ context: RenderContext,
41
+ buffer: TextIO,
42
+ ) -> int:
43
+ with context.extend({a.name: a.value.evaluate(context) for a in self.args}):
42
44
  return self.block.render(context, buffer)
43
45
 
44
46
  async def render_to_output_async(
45
- self, context: RenderContext, buffer: TextIO
47
+ self,
48
+ context: RenderContext,
49
+ buffer: TextIO,
46
50
  ) -> int:
47
- namespace = dict([await arg.evaluate_async(context) for arg in self.args])
51
+ namespace = {a.name: await a.value.evaluate_async(context) for a in self.args}
48
52
  with context.extend(namespace):
49
53
  return await self.block.render_async(context, buffer)
50
54
 
@@ -54,21 +58,16 @@ class WithNode(Node):
54
58
  *,
55
59
  include_partials: bool = True, # noqa: ARG002
56
60
  ) -> Iterable[Node]:
57
- """Return this node's children."""
58
61
  yield self.block
59
62
 
60
63
  def expressions(self) -> Iterable[Expression]:
61
- """Return this node's expressions."""
62
64
  yield from (arg.value for arg in self.args)
63
65
 
64
66
  def block_scope(self) -> Iterable[Identifier]:
65
- """Return variables this node adds to the node's block scope."""
66
67
  yield from (Identifier(p.name, token=p.token) for p in self.args)
67
68
 
68
69
 
69
70
  class WithTag(Tag):
70
- """The extra _with_ tag."""
71
-
72
71
  name = TAG_WITH
73
72
  end = TAG_ENDWITH
74
73
  node_class = WithNode
@@ -76,8 +75,6 @@ class WithTag(Tag):
76
75
  def parse(self, stream: TokenStream) -> Node:
77
76
  token = stream.eat(TOKEN_TAG)
78
77
  args = KeywordArgument.parse(self.env, stream.into_inner(tag=token))
79
-
80
- # Parse the block
81
78
  block = get_parser(self.env).parse_block(stream, (TAG_ENDWITH, TOKEN_EOF))
82
79
  stream.expect(TOKEN_TAG, value=TAG_ENDWITH)
83
80
  return self.node_class(token, args=args, block=block)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-liquid
3
- Version: 2.2.1
3
+ Version: 2.2.2
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/
@@ -1,7 +1,7 @@
1
- liquid/__init__.py,sha256=YIN6_DEfW6bv9bhNED8Pnl0Ryt3_uCPt1dvMIuw_Yfk,7696
1
+ liquid/__init__.py,sha256=n813bB2brzEFcknsntiYNf-sveMtXuZ4s29Dd2_1-fw,7696
2
2
  liquid/analyze_tags.py,sha256=Uc1nueKLRiIejs2JyQIC7u2pxp9l-5HJAMWlg-Qj1m8,7615
3
3
  liquid/ast.py,sha256=4ZqSbuW4mv9IvoIMPk3OICUaOI1vPh8P8uFCrXI_3XA,8140
4
- liquid/context.py,sha256=gSJI1mj7mdcUfiQ09_XCEj5JxAosCGEX85Uuzl9apeI,21505
4
+ liquid/context.py,sha256=fEuMsj9MVguX3Kzy9_k99TWekOwAToL0RtbGm9yZ71o,21718
5
5
  liquid/environment.py,sha256=1X5WsOHcFvKAjljQcG3F-cQ9sfxzaiD-N3jGJOG5yHU,23940
6
6
  liquid/exceptions.py,sha256=FOc4KAOijF4WHrBGepvi0ycAYT5hu0rhdpsVb2C-ZHs,8336
7
7
  liquid/expression.py,sha256=Ozgajah2R5eg1yWA4ITFGaMFoOLt8GIjkE1NKqbBEzk,1143
@@ -46,7 +46,7 @@ liquid/builtin/loaders/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3
46
46
  liquid/builtin/loaders/caching_file_system_loader.py,sha256=V4OLa6UGT-RELGiV4eu02TeLL4P_JIE2kMYMrO3qy8U,2158
47
47
  liquid/builtin/loaders/choice_loader.py,sha256=FE23RLMOiWmsRGZv9t6QmlG7bgMEUSblnucAv3j0SBM,2816
48
48
  liquid/builtin/loaders/dict_loader.py,sha256=8TdMJqaYPLwllmIiEmuZNXqH6UOOsi4HuJ2t5sztOOw,1785
49
- liquid/builtin/loaders/file_system_loader.py,sha256=6CzmJnktLE9n6y8YYEtUZFa4nDsZ6vsAWIDwCg6_vE0,4528
49
+ liquid/builtin/loaders/file_system_loader.py,sha256=zDX3NPFAKWEftMFCh10gFYfgncAlHkaO7IfpCxOnFSQ,4794
50
50
  liquid/builtin/loaders/mixins.py,sha256=4Hj5wWGMOi3LqA9ZJYsUb4LFbG0a5DDb9H975G8nn58,5209
51
51
  liquid/builtin/loaders/package_loader.py,sha256=XP7LT3aMClgfBlI8OMyHOERlXTXEWmqFH7HskCnY3cs,3659
52
52
  liquid/builtin/tags/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -54,7 +54,7 @@ liquid/builtin/tags/assign_tag.py,sha256=VTfkPbF-i0KLqMmaacBItFQHaBTP7ECWR-RvVh9
54
54
  liquid/builtin/tags/capture_tag.py,sha256=7bOG7qVwcqRx1eStb96AZKQ9tKLBjmzaYAe27LJTIm4,3037
55
55
  liquid/builtin/tags/case_tag.py,sha256=8ZN3pWP6axr-y7XAGIDjOkTDis0KSxpw7m1ITSElOVw,9040
56
56
  liquid/builtin/tags/comment_tag.py,sha256=BMvee7nVBim_iDScKWbcUBCxNXzbBvguYfQUG3GM1y8,2250
57
- liquid/builtin/tags/cycle_tag.py,sha256=tbgnEiwENXIfRAKRsVg18KRsZwaNLOLZeuLy-0Xm5c0,3789
57
+ liquid/builtin/tags/cycle_tag.py,sha256=Vl3DuDBkfpDKk2hxcLM99gFW1-OjWC2APHr23iGXkVE,3943
58
58
  liquid/builtin/tags/decrement_tag.py,sha256=WgkwWqjJgzjfEKffTKNw0ao6N0JxniadxGO_n1k8oZE,1660
59
59
  liquid/builtin/tags/doc_tag.py,sha256=luc2QI-4N7KF49vWak6dNm5Hs9jwlXTAfUlEsr6ZCNM,2055
60
60
  liquid/builtin/tags/echo_tag.py,sha256=VvYth9VuA-A9bsfGUOLlM4QxL_frsgWena3yBrrLKPI,1174
@@ -76,7 +76,7 @@ liquid/extra/filters/babel.py,sha256=K0kvw8r5Xy4NwvX4qv-lym14rZ25gB4fCnHqj-IVagI
76
76
  liquid/extra/filters/html.py,sha256=j6ghLorvxlVwAtyfVJlmB1tnroGJb8hD-uxUVALVSEQ,929
77
77
  liquid/extra/filters/translate.py,sha256=PDEgvmdOvg45ChAKLsaqtamOqaBWOFh4XzQC8igXIyE,13019
78
78
  liquid/extra/tags/__init__.py,sha256=iqB5oOPYhZey-dyljrgAjGeni4lK8Q9-rW2cGRHa4hw,383
79
- liquid/extra/tags/_with.py,sha256=QLlpY3oW8prCmutEXv1uUCMo_hloLd-sEbiMkMIbtXM,2627
79
+ liquid/extra/tags/_with.py,sha256=gZ3SjoQoSVFFsayMZQJimwwRpHK4c_tsuKU7wZvL0Hk,2432
80
80
  liquid/extra/tags/extends_tag.py,sha256=3PL1y1FHaeh6L4rA_Xz6wP6l5oHdiOY_u42ivS6c3xE,17893
81
81
  liquid/extra/tags/macro_tag.py,sha256=ErjPxOVB50KKn2qi7-2Icmrbx5Uldv2vUSj49TCs4bY,8749
82
82
  liquid/extra/tags/snippet_tag.py,sha256=8tFZWDvwhRId5IV0mNKhkFswJx3eTeAYs7-nAwiorNY,3155
@@ -90,7 +90,7 @@ liquid/utils/chain_map.py,sha256=nxkw3wwF6ddlGarIuL7Ii2elm4dU80LySgdQx1oift0,151
90
90
  liquid/utils/html.py,sha256=TmqOOpRMsy7fqZLj7X5ybd_XQnWW2YDAVDwTP1Gwf40,1706
91
91
  liquid/utils/lru_cache.py,sha256=p7bXOGaUwJpLsREI2lGSzK6lLna5W_k_zNXKWnPJdos,4022
92
92
  liquid/utils/text.py,sha256=1SwDECNMaqnnZ05je_AZZgxqzZd6U-mvq5jNU3W1-Qk,841
93
- python_liquid-2.2.1.dist-info/METADATA,sha256=ttOrZWxcSER0sxi5fw52WvjFIqb07SMBFMj18TLp2gk,6745
94
- python_liquid-2.2.1.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
95
- python_liquid-2.2.1.dist-info/licenses/LICENSE,sha256=yAFURzud5ERNHt1rZIPnTLJ92ep7q8y5yG9g5DUMR_E,1075
96
- python_liquid-2.2.1.dist-info/RECORD,,
93
+ python_liquid-2.2.2.dist-info/METADATA,sha256=5GvHUFzsPvOsuLdFLltRz94aEFa3dJ3gxg_21QBLDoc,6745
94
+ python_liquid-2.2.2.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
95
+ python_liquid-2.2.2.dist-info/licenses/LICENSE,sha256=yAFURzud5ERNHt1rZIPnTLJ92ep7q8y5yG9g5DUMR_E,1075
96
+ python_liquid-2.2.2.dist-info/RECORD,,