python-liquid 2.0.1__py3-none-any.whl → 2.1.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 (99) hide show
  1. liquid/__init__.py +1 -1
  2. liquid/builtin/__init__.py +2 -0
  3. liquid/builtin/expressions/loop.py +2 -5
  4. liquid/builtin/filters/extra.py +62 -0
  5. liquid/builtin/filters/string.py +36 -4
  6. liquid/extra/tags/macro_tag.py +2 -0
  7. liquid/static_analysis.py +16 -10
  8. {python_liquid-2.0.1.dist-info → python_liquid-2.1.0.dist-info}/METADATA +3 -1
  9. python_liquid-2.1.0.dist-info/RECORD +95 -0
  10. liquid/golden/__init__.py +0 -173
  11. liquid/golden/abs_filter.py +0 -73
  12. liquid/golden/append_filter.py +0 -43
  13. liquid/golden/assign_tag.py +0 -45
  14. liquid/golden/at_least_filter.py +0 -78
  15. liquid/golden/at_most_filter.py +0 -68
  16. liquid/golden/base64_decode_filter.py +0 -43
  17. liquid/golden/base64_encode_filter.py +0 -42
  18. liquid/golden/base64_url_safe_decode_filter.py +0 -43
  19. liquid/golden/base64_url_safe_encode_filter.py +0 -42
  20. liquid/golden/capitalize_filter.py +0 -27
  21. liquid/golden/capture_tag.py +0 -39
  22. liquid/golden/case.py +0 -28
  23. liquid/golden/case_tag.py +0 -226
  24. liquid/golden/ceil_filter.py +0 -63
  25. liquid/golden/comment_tag.py +0 -119
  26. liquid/golden/compact_filter.py +0 -54
  27. liquid/golden/concat_filter.py +0 -63
  28. liquid/golden/cycle_tag.py +0 -114
  29. liquid/golden/date_filter.py +0 -63
  30. liquid/golden/decrement_tag.py +0 -16
  31. liquid/golden/default_filter.py +0 -112
  32. liquid/golden/divided_by_filter.py +0 -101
  33. liquid/golden/doc_tag.py +0 -61
  34. liquid/golden/downcase_filter.py +0 -27
  35. liquid/golden/echo_tag.py +0 -116
  36. liquid/golden/escape_filter.py +0 -27
  37. liquid/golden/escape_once_filter.py +0 -32
  38. liquid/golden/find_filter.py +0 -90
  39. liquid/golden/find_index_filter.py +0 -96
  40. liquid/golden/first_filter.py +0 -51
  41. liquid/golden/floor_filter.py +0 -63
  42. liquid/golden/for_tag.py +0 -642
  43. liquid/golden/has_filter.py +0 -139
  44. liquid/golden/identifiers.py +0 -249
  45. liquid/golden/if_tag.py +0 -531
  46. liquid/golden/ifchanged_tag.py +0 -46
  47. liquid/golden/illegal.py +0 -34
  48. liquid/golden/include_tag.py +0 -196
  49. liquid/golden/increment_tag.py +0 -48
  50. liquid/golden/inline_comment_tag.py +0 -127
  51. liquid/golden/join_filter.py +0 -69
  52. liquid/golden/last_filter.py +0 -51
  53. liquid/golden/liquid_tag.py +0 -215
  54. liquid/golden/lstrip_filter.py +0 -37
  55. liquid/golden/map_filter.py +0 -50
  56. liquid/golden/minus_filter.py +0 -58
  57. liquid/golden/modulo_filter.py +0 -60
  58. liquid/golden/newline_to_br_filter.py +0 -37
  59. liquid/golden/not_liquid.py +0 -16
  60. liquid/golden/output_statement.py +0 -295
  61. liquid/golden/plus_filter.py +0 -63
  62. liquid/golden/prepend_filter.py +0 -43
  63. liquid/golden/range_objects.py +0 -79
  64. liquid/golden/raw_tag.py +0 -31
  65. liquid/golden/reject_filter.py +0 -268
  66. liquid/golden/remove_filter.py +0 -45
  67. liquid/golden/remove_first_filter.py +0 -46
  68. liquid/golden/remove_last_filter.py +0 -46
  69. liquid/golden/render_tag.py +0 -210
  70. liquid/golden/replace_filter.py +0 -65
  71. liquid/golden/replace_first_filter.py +0 -59
  72. liquid/golden/replace_last_filter.py +0 -60
  73. liquid/golden/reverse_filter.py +0 -42
  74. liquid/golden/round_filter.py +0 -87
  75. liquid/golden/rstrip_filter.py +0 -37
  76. liquid/golden/size_filter.py +0 -42
  77. liquid/golden/slice_filter.py +0 -119
  78. liquid/golden/sort_filter.py +0 -86
  79. liquid/golden/sort_natural_filter.py +0 -105
  80. liquid/golden/special.py +0 -91
  81. liquid/golden/split_filter.py +0 -128
  82. liquid/golden/strip_filter.py +0 -37
  83. liquid/golden/strip_html_filter.py +0 -74
  84. liquid/golden/strip_newlines_filter.py +0 -37
  85. liquid/golden/sum_filter.py +0 -97
  86. liquid/golden/tablerow_tag.py +0 -399
  87. liquid/golden/times_filter.py +0 -53
  88. liquid/golden/truncate_filter.py +0 -61
  89. liquid/golden/truncatewords_filter.py +0 -94
  90. liquid/golden/uniq_filter.py +0 -87
  91. liquid/golden/unless_tag.py +0 -101
  92. liquid/golden/upcase_filter.py +0 -27
  93. liquid/golden/url_decode_filter.py +0 -27
  94. liquid/golden/url_encode_filter.py +0 -27
  95. liquid/golden/where_filter.py +0 -122
  96. liquid/golden/whitespace_control.py +0 -281
  97. python_liquid-2.0.1.dist-info/RECORD +0 -182
  98. {python_liquid-2.0.1.dist-info → python_liquid-2.1.0.dist-info}/WHEEL +0 -0
  99. {python_liquid-2.0.1.dist-info → python_liquid-2.1.0.dist-info}/licenses/LICENSE +0 -0
liquid/__init__.py CHANGED
@@ -56,7 +56,7 @@ from .tag import Tag
56
56
 
57
57
  from . import future
58
58
 
59
- __version__ = "2.0.1"
59
+ __version__ = "2.1.0"
60
60
 
61
61
  __all__ = (
62
62
  "AwareBoundTemplate",
@@ -21,6 +21,7 @@ from .filters.array import sort_natural
21
21
  from .filters.array import sum_
22
22
  from .filters.array import uniq
23
23
  from .filters.array import where
24
+ from .filters.extra import escapejs
24
25
  from .filters.extra import safe
25
26
  from .filters.math import abs_
26
27
  from .filters.math import at_least
@@ -197,3 +198,4 @@ def register(env: Environment) -> None: # noqa: PLR0915
197
198
  env.add_filter("date", date)
198
199
 
199
200
  env.add_filter("safe", safe)
201
+ env.add_filter("escapejs", escapejs)
@@ -97,14 +97,11 @@ class LoopExpression(Expression):
97
97
  if isinstance(obj, range):
98
98
  return iter(obj), len(obj)
99
99
  if isinstance(obj, str) and not context.env.string_sequences:
100
- return iter([obj]), 1
100
+ return (iter([]), 0) if not obj else (iter([obj]), 1)
101
101
  if isinstance(obj, Sequence):
102
102
  return iter(obj), len(obj)
103
103
 
104
- raise LiquidTypeError(
105
- f"expected an iterable at '{self.iterable}', found '{obj}'",
106
- token=self.token,
107
- )
104
+ return iter([]), 0
108
105
 
109
106
  def _to_int(self, obj: object, *, token: Token) -> int:
110
107
  try:
@@ -2,6 +2,7 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ import re
5
6
  from typing import TYPE_CHECKING
6
7
 
7
8
  from liquid import Markup
@@ -19,3 +20,64 @@ def safe(val: str, *, environment: Environment) -> str:
19
20
  if environment.autoescape:
20
21
  return Markup(val)
21
22
  return val
23
+
24
+
25
+ # `escapejs` is inspired by https://github.com/salesforce/secure-filters and Django's
26
+ # escapejs filter, https://github.com/django/django/blob/485f483d49144a2ea5401442bc3b937a370b3ca6/django/utils/html.py#L63
27
+
28
+ _ESCAPE_MAP = {
29
+ "\\": "\\u005C",
30
+ "'": "\\u0027",
31
+ '"': "\\u0022",
32
+ ">": "\\u003E",
33
+ "<": "\\u003C",
34
+ "&": "\\u0026",
35
+ "=": "\\u003D",
36
+ "-": "\\u002D",
37
+ ";": "\\u003B",
38
+ "`": "\\u0060",
39
+ "\u2028": "\\u2028",
40
+ "\u2029": "\\u2029",
41
+ }
42
+
43
+ _ESCAPE_MAP.update({chr(c): f"\\u{c:04X}" for c in range(32)})
44
+ _ESCAPE_RE = re.compile("[" + re.escape("".join(_ESCAPE_MAP.keys())) + "]")
45
+
46
+
47
+ @with_environment
48
+ @string_filter
49
+ def escapejs(val: str, *, environment: Environment) -> str:
50
+ """Escape characters for safe use in JavaScript string literals.
51
+
52
+ This filter escapes a string for embedding inside **JavaScript string
53
+ literals**, using either single or double quotes (e.g. `'...'` or `"..."`).
54
+ It replaces control characters and potentially dangerous symbols with
55
+ their corresponding Unicode escape sequences.
56
+
57
+ **Important:** This filter does **not** make strings safe for use in
58
+ JavaScript template literals (backtick strings), or in raw JavaScript
59
+ expressions. Use it only when placing data inside quoted JS strings
60
+ within inline `<script>` blocks or event handlers.
61
+
62
+ **Recommended alternatives:**
63
+ - Pass data using HTML `data-*` attributes and read them in JS via
64
+ `element.dataset`.
65
+ - For structured data, prefer a JSON-serialization approach using the
66
+ JSON filter.
67
+
68
+ Escaped characters include:
69
+ - ASCII control characters (U+0000 to U+001F)
70
+ - Characters like quotes, angle brackets, ampersands, equals signs
71
+ - Line/paragraph separators (U+2028, U+2029)
72
+
73
+ Args:
74
+ val: The input string to escape.
75
+ environment: The active Liquid environment
76
+
77
+ Returns:
78
+ A JavaScript-safe string, with problematic characters escaped as Unicode.
79
+ """
80
+ escaped = _ESCAPE_RE.sub(lambda m: _ESCAPE_MAP[m.group()], val)
81
+ if environment.autoescape:
82
+ return Markup(escaped)
83
+ return escaped
@@ -56,7 +56,35 @@ def downcase(val: str) -> str:
56
56
  @with_environment
57
57
  @string_filter
58
58
  def escape(val: str, *, environment: Environment) -> str:
59
- """Return _val_ with the characters &, < and > converted to HTML-safe sequences."""
59
+ """Escape special characters in a string for safe use in HTML.
60
+
61
+ This filter replaces the characters `&`, `<`, `>`, `'`, and `"` with their
62
+ corresponding HTML-safe sequences:
63
+
64
+ - `&` -> `&amp;`
65
+ - `<` -> `&lt;`
66
+ - `>` -> `&gt;`
67
+ - `'` -> `&#39;`
68
+ - `"` -> `&#34;`
69
+
70
+ This helps prevent HTML injection (XSS) when rendering untrusted content in
71
+ HTML element bodies or attributes.
72
+
73
+ Important: This filter does **not** make strings safe for use in JavaScript,
74
+ including in `<script>` blocks, inline event handler attributes (e.g. `onerror`),
75
+ or other JavaScript contexts. For those cases, use the `escapejs` filter instead.
76
+
77
+ When `autoescape` is enabled in the environment, this filter uses the same
78
+ escaping logic as the environment (via `markupsafe.escape()`). Otherwise, it
79
+ falls back to Python's standard `html.escape()`.
80
+
81
+ Args:
82
+ val: The input string to escape.
83
+ environment: The current rendering environment.
84
+
85
+ Returns:
86
+ A string with HTML-special characters replaced by safe escape sequences.
87
+ """
60
88
  if environment.autoescape:
61
89
  return markupsafe_escape(str(val))
62
90
  return html.escape(val)
@@ -65,10 +93,14 @@ def escape(val: str, *, environment: Environment) -> str:
65
93
  @with_environment
66
94
  @string_filter
67
95
  def escape_once(val: str, *, environment: Environment) -> str:
68
- """Return _val_ with the characters &, < and > converted to HTML-safe sequences.
96
+ """Escape a string for HTML, but avoid double-escaping existing entities.
97
+
98
+ Converts characters like `&`, `<`, and `>` to their HTML-safe sequences,
99
+ but leaves existing HTML entities untouched (e.g., `&amp;` stays `&amp;`).
100
+
101
+ This is useful when escaping content that may already be partially escaped.
69
102
 
70
- It is safe to use `escape_one` on string values that already contain HTML escape
71
- sequences.
103
+ See the `escape` filter for details and limitations.
72
104
  """
73
105
  if environment.autoescape:
74
106
  return Markup(val).unescape()
@@ -94,6 +94,8 @@ class MacroNode(Node):
94
94
 
95
95
  def block_scope(self) -> Iterable[Identifier]:
96
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)
97
99
  yield from (Identifier(p.name, token=p.token) for p in self.args.values())
98
100
 
99
101
 
liquid/static_analysis.py CHANGED
@@ -301,19 +301,25 @@ async def _analyze_async(
301
301
  def _extract_filters(
302
302
  expression: Expression, template_name: str
303
303
  ) -> Iterable[tuple[str, Span]]:
304
- if (
305
- isinstance(expression, (FilteredExpression, TernaryFilteredExpression))
306
- and expression.filters
307
- ):
308
- yield from (
309
- (f.name, Span(template_name, f.token.start_index))
310
- for f in expression.filters
311
- )
304
+ if isinstance(expression, TernaryFilteredExpression):
305
+ yield from _extract_filters(expression.left, template_name)
312
306
 
313
- if isinstance(expression, TernaryFilteredExpression) and expression.tail_filters:
307
+ if expression.filters:
308
+ yield from (
309
+ (f.name, Span(template_name, f.token.start_index))
310
+ for f in expression.filters
311
+ )
312
+
313
+ if expression.tail_filters:
314
+ yield from (
315
+ (f.name, Span(template_name, f.token.start_index))
316
+ for f in expression.tail_filters
317
+ )
318
+
319
+ if isinstance(expression, FilteredExpression) and expression.filters:
314
320
  yield from (
315
321
  (f.name, Span(template_name, f.token.start_index))
316
- for f in expression.tail_filters
322
+ for f in expression.filters
317
323
  )
318
324
 
319
325
  for expr in expression.children():
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-liquid
3
- Version: 2.0.1
3
+ Version: 2.1.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/
@@ -104,6 +104,8 @@ $ conda install -c conda-forge python-liquid
104
104
  ## Related Projects
105
105
 
106
106
  - [Python Liquid2](https://github.com/jg-rp/python-liquid2): A new Python engine for Liquid with [extra features](https://jg-rp.github.io/python-liquid2/migration/#new-features).
107
+ - [Ruby Liquid2](https://github.com/jg-rp/ruby-liquid2): Liquid2 templates for Ruby.
108
+ - [Micro Liquid](https://github.com/jg-rp/micro-liquid): A stripped-down Liquid-like template engine for Python. You can think of it as a non-evaluating alternative to Python's [f-strings](https://docs.python.org/3/tutorial/inputoutput.html#formatted-string-literals) or [t-strings](https://docs.python.org/3.14/whatsnew/3.14.html#whatsnew314-pep750).
107
109
  - [LiquidScript](https://github.com/jg-rp/liquidscript): A JavaScript engine for Liquid with a similar high-level API to Python Liquid.
108
110
 
109
111
  ## Quick Start
@@ -0,0 +1,95 @@
1
+ liquid/__init__.py,sha256=gQBAgPnQURpFuvzPsHbB0XVy2LtBlofIRTVfl4fyvjs,7696
2
+ liquid/analyze_tags.py,sha256=Uc1nueKLRiIejs2JyQIC7u2pxp9l-5HJAMWlg-Qj1m8,7615
3
+ liquid/ast.py,sha256=ec-c8F7B2_yj2FmYiOFnnvu2JSd7c4mzTDGlYeztQ_8,7653
4
+ liquid/context.py,sha256=gSJI1mj7mdcUfiQ09_XCEj5JxAosCGEX85Uuzl9apeI,21505
5
+ liquid/environment.py,sha256=1X5WsOHcFvKAjljQcG3F-cQ9sfxzaiD-N3jGJOG5yHU,23940
6
+ liquid/exceptions.py,sha256=hG4SklVAOg-FOy2Y3husZmQdAzvn4bpB7FaunaLHTnU,8299
7
+ liquid/expression.py,sha256=Ozgajah2R5eg1yWA4ITFGaMFoOLt8GIjkE1NKqbBEzk,1143
8
+ liquid/filter.py,sha256=-Mbrtui9ELPMpprJJN97GrpWJF47pzYSWGNM__p_A_k,6687
9
+ liquid/lex.py,sha256=PrnnUWhXZO6novkO0KE-p4virh5cNJsg7m85sg2IUiw,8004
10
+ liquid/limits.py,sha256=BxqiC4Ax5iadmh6jDRcUNjFfOvbMkvZ1a046R1Cb8UA,1700
11
+ liquid/loader.py,sha256=R_RniSRszCXmRVZgXlu9WjV130cWvspVcC3vIVpf-qg,4381
12
+ liquid/messages.py,sha256=r6OcJG4-dLEULc9JtQ-mh3Jf6nNZ9Aa2reun7zYiUyc,11861
13
+ liquid/mode.py,sha256=pgMF9oEl5nT5Q3Poi1gfWG9ozSXX5B6f4sfzOQX_Gow,206
14
+ liquid/output.py,sha256=1rgPmXGWUTut-aBBbHs-TCCZ2UGUhmbJYRmCsnqIOCk,1000
15
+ liquid/parser.py,sha256=F8aC__UiUzz39lxhPr3sl67l-V-mrxkdn-4MAaCTWRE,3824
16
+ liquid/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
+ liquid/span.py,sha256=Z7Xb5V_h3WLvVmZUBebZeZkJFHKa33Bfcqq3S60SMSk,1122
18
+ liquid/static_analysis.py,sha256=4p6-xwzqE0WKmtjiKtjkMPbHIFqYo9yue3bOksjUqF8,11975
19
+ liquid/stream.py,sha256=nYBSjdgs5SkjAM7TTTkmZtc_DF1_KOvQrTGsjZXSrYE,4882
20
+ liquid/stringify.py,sha256=TkRO0KbZVCY3usNV6EXfG6CbtWhuLoI7joxcrEArSNE,892
21
+ liquid/tag.py,sha256=h5jexl6NjUQnM2py4s5db1ksh0s8vi31YHud5kHJt1E,1189
22
+ liquid/template.py,sha256=hLylYHSf9_nkLUymfn8o1hGMrHRhiRfU_QRFMjLPw_A,22376
23
+ liquid/token.py,sha256=gxqMGcGk1fWihz5gQ2BQJzqSEcY7tCAZiIjcdC34P1w,3995
24
+ liquid/undefined.py,sha256=Y57D69YR6yXSHV4x1rg1xtoTe-6M49h-mqlSO7pcRSE,5673
25
+ liquid/builtin/__init__.py,sha256=oEzqtKMvqvfoqzcN1Sq_Qbq094hySWNTCnE5Ga-CkcU,7018
26
+ liquid/builtin/content.py,sha256=HXo2ty2cQxsOkXJDhWmcAWC0ny73w9oABaer50zGp70,1122
27
+ liquid/builtin/illegal.py,sha256=RRzzlqo2_scdtbMt_hZq0pr-7khgbxrdub9XH-_goPs,844
28
+ liquid/builtin/output.py,sha256=4r_QJimFTbBdubhdIOG_nweROEOXiWHlp_xNmWXy564,2279
29
+ liquid/builtin/drops/__init__.py,sha256=ewOQFD_O5Wul9xWsTBzo-XuKSdvN6K3hbcQF8VdKmtM,75
30
+ liquid/builtin/drops/drops.py,sha256=WF5vWNnFj1-huldxYeSzEJcjabvxdODApf817ZaycaE,366
31
+ liquid/builtin/expressions/__init__.py,sha256=5scdgzOrMK9SxKpab3ebJnfO56Dl4bYLXO6xXgkCGrc,1256
32
+ liquid/builtin/expressions/_tokenize.py,sha256=p7RbeOg8iwXDnW0fIL4_7FSrBulkPYrCm3ialpEIsDE,5737
33
+ liquid/builtin/expressions/arguments.py,sha256=hlZh7LLFT5UismTo7mTlVjM87_ihUJo0BYuCxyTwKMI,6448
34
+ liquid/builtin/expressions/filtered.py,sha256=FqPNZLjwDdlCfivtBa7e0wuQYwcJdKUl3_UY9AS3zG4,13073
35
+ liquid/builtin/expressions/logical.py,sha256=S8T9IgsuWgv0s7GYcGvIJFOqYMiMFRpat7zF3nCZHR0,20388
36
+ liquid/builtin/expressions/loop.py,sha256=sRVq_KQjuEglBqSePIqtZu_7AVfMcK95PIgiBP8gniQ,8884
37
+ liquid/builtin/expressions/path.py,sha256=m1J33uIuEFlUaRXR_-G6qcsClOm0B5jbTZ0Pdt1P7Ak,5703
38
+ liquid/builtin/expressions/primitive.py,sha256=Gzaeb-dF84zsMn5ZYhe-FOosnSbkkM2C6JLqjLvK5ns,11352
39
+ liquid/builtin/filters/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
40
+ liquid/builtin/filters/array.py,sha256=dMuT15EASXU4ejmNBmawdi92u0f7y_JhqVaGoP48zlg,9843
41
+ liquid/builtin/filters/extra.py,sha256=m13_1nbZyRBl3CZV9WWGLlUZueRPt8cKPEHRAioqM_o,2710
42
+ liquid/builtin/filters/math.py,sha256=A_K2wg5gxm5Ncj9zMGDX_Lt7jjx4bRr3CywbCiCtqxo,3925
43
+ liquid/builtin/filters/misc.py,sha256=t2ZsaDLKRc1-8XxZaiEOh7oAMqFJ4N5-tzfbpLHbmIQ,3466
44
+ liquid/builtin/filters/string.py,sha256=3Ub1z0VeCeAT07FaDVAazw2J9vFmpqtehtEtujNZxdg,11963
45
+ liquid/builtin/loaders/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
46
+ liquid/builtin/loaders/caching_file_system_loader.py,sha256=-9riAxL8933u_w1Ppweia-WkfFlxVU3aCspdiNyD5xQ,1931
47
+ liquid/builtin/loaders/choice_loader.py,sha256=FE23RLMOiWmsRGZv9t6QmlG7bgMEUSblnucAv3j0SBM,2816
48
+ liquid/builtin/loaders/dict_loader.py,sha256=8TdMJqaYPLwllmIiEmuZNXqH6UOOsi4HuJ2t5sztOOw,1785
49
+ liquid/builtin/loaders/file_system_loader.py,sha256=VAS6C-oez9lvOq81Q8bPBb3JjHC2ltC2DvgPf32pdgE,3895
50
+ liquid/builtin/loaders/mixins.py,sha256=4Hj5wWGMOi3LqA9ZJYsUb4LFbG0a5DDb9H975G8nn58,5209
51
+ liquid/builtin/loaders/package_loader.py,sha256=XP7LT3aMClgfBlI8OMyHOERlXTXEWmqFH7HskCnY3cs,3659
52
+ liquid/builtin/tags/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
53
+ liquid/builtin/tags/assign_tag.py,sha256=VTfkPbF-i0KLqMmaacBItFQHaBTP7ECWR-RvVh9Q6lY,2374
54
+ liquid/builtin/tags/capture_tag.py,sha256=7bOG7qVwcqRx1eStb96AZKQ9tKLBjmzaYAe27LJTIm4,3037
55
+ liquid/builtin/tags/case_tag.py,sha256=OUKu_UiUeJ8Q9C3FePNSSkRiiM6w44Ze5HIzuZj4Pxo,9073
56
+ liquid/builtin/tags/comment_tag.py,sha256=KNM2heK7U9S7S9PiNjVilwS8kuABfILiVpgjAmLbb_8,2213
57
+ liquid/builtin/tags/cycle_tag.py,sha256=tbgnEiwENXIfRAKRsVg18KRsZwaNLOLZeuLy-0Xm5c0,3789
58
+ liquid/builtin/tags/decrement_tag.py,sha256=WgkwWqjJgzjfEKffTKNw0ao6N0JxniadxGO_n1k8oZE,1660
59
+ liquid/builtin/tags/doc_tag.py,sha256=2VjfL-todQK-ejjIdWIRP97jrKofb_eP8DVh6-q69NY,2044
60
+ liquid/builtin/tags/echo_tag.py,sha256=VvYth9VuA-A9bsfGUOLlM4QxL_frsgWena3yBrrLKPI,1174
61
+ liquid/builtin/tags/for_tag.py,sha256=vVSc9WJ0ZeLW8zgDwNs_dVr8qe9lrg92Ny90GmpO_Jo,9440
62
+ liquid/builtin/tags/if_tag.py,sha256=u8Jqk-HaT-bK5deaoDltdmrLpL_0m3UM8a1_r9OXsjc,6560
63
+ liquid/builtin/tags/ifchanged_tag.py,sha256=VpJNDhT7MFXcNmRrYiWcJ9whhaRXh81oe_phatS5_Kg,2734
64
+ liquid/builtin/tags/include_tag.py,sha256=eAnjcbJ2-e0382TkrV2WJ9dACFWi_UNUeKG-QRuiOig,9220
65
+ liquid/builtin/tags/increment_tag.py,sha256=SV2nrbE90l4iz36WCROqGE0RkkzztWUpU1_Pyp2DDQo,1662
66
+ liquid/builtin/tags/inline_comment_tag.py,sha256=hLLtvaI-VpJxzFeoLTwDTj46g13A1ke6blqVo2MP0Cs,1357
67
+ liquid/builtin/tags/liquid_tag.py,sha256=vQh2T8_3uBfTTgp6PNqi_bOhbRNv45eoo9yoOXcNyz8,5465
68
+ liquid/builtin/tags/render_tag.py,sha256=h2np1g8gK43Kind2Mw5Sr9bR7cQg2k2dTAOsH-w2ZOY,11787
69
+ liquid/builtin/tags/tablerow_tag.py,sha256=qE5hIrlJXdKiLJ0u1YLgjnqt6GedWujfcfIO0b9x0d8,8947
70
+ liquid/builtin/tags/unless_tag.py,sha256=udlHvVxILJsYfDaWRkj6Ynmnz2-2FF5RfkP0eizXt7k,6932
71
+ liquid/extra/__init__.py,sha256=DNS-k6uH7-IvYu_6InPk38CmjW1orggBaj0rkBkvy74,2855
72
+ liquid/extra/filters/__init__.py,sha256=tsEfSmaJvd6xN8DfKISPOm_KcHOmBVc4RSQqViD8NvY,733
73
+ liquid/extra/filters/_json.py,sha256=Od7iJWKCWQzf1eZiIqOG1LGwx2JTiHCe95GO5DqgHYY,844
74
+ liquid/extra/filters/array.py,sha256=QvuP2jPg0G4xgIGXOcCRvjpX0O5h7U-WpayAaYmYDdc,1590
75
+ liquid/extra/filters/babel.py,sha256=ofFSAaUfOyRYC94_LEVLvEeyzrrh7YssVXRcwKBWQPg,19188
76
+ liquid/extra/filters/html.py,sha256=j6ghLorvxlVwAtyfVJlmB1tnroGJb8hD-uxUVALVSEQ,929
77
+ liquid/extra/filters/translate.py,sha256=PDEgvmdOvg45ChAKLsaqtamOqaBWOFh4XzQC8igXIyE,13019
78
+ liquid/extra/tags/__init__.py,sha256=IGL2PPie0T73DQRNB-BY3hKOq710ZzMvlW31qulhtI0,329
79
+ liquid/extra/tags/_with.py,sha256=QLlpY3oW8prCmutEXv1uUCMo_hloLd-sEbiMkMIbtXM,2627
80
+ liquid/extra/tags/extends_tag.py,sha256=_X5wYKVtzSetuGlEUI9gl5nkUJmwEAS7sQIaZHBKexM,17978
81
+ liquid/extra/tags/macro_tag.py,sha256=ErjPxOVB50KKn2qi7-2Icmrbx5Uldv2vUSj49TCs4bY,8749
82
+ liquid/extra/tags/translate_tag.py,sha256=wv2uK9QtWDrArVeAWmH2QQ7fkM5EAM4gK2bWjlstcnE,12515
83
+ liquid/future/__init__.py,sha256=5BUZi58WyWjPQDflh2C3sQJmuSKAZgNG_286ERyYKFE,79
84
+ liquid/future/environment.py,sha256=Zx4RbgIOMmH5N_VH9poOGRLcSI9DAA5_EkUlP-L6ZlA,986
85
+ liquid/future/filters/__init__.py,sha256=0eVFfVd2aZXTZHFXcLZnFk8MftII4cMhRBBYt3Hm3LI,13
86
+ liquid/future/tags/__init__.py,sha256=0eVFfVd2aZXTZHFXcLZnFk8MftII4cMhRBBYt3Hm3LI,13
87
+ liquid/utils/__init__.py,sha256=xNdanW5X6qXphmzK8fSrBeR1h6AwCtEGHmEvcrmDxAc,366
88
+ liquid/utils/chain_map.py,sha256=nxkw3wwF6ddlGarIuL7Ii2elm4dU80LySgdQx1oift0,1517
89
+ liquid/utils/html.py,sha256=TmqOOpRMsy7fqZLj7X5ybd_XQnWW2YDAVDwTP1Gwf40,1706
90
+ liquid/utils/lru_cache.py,sha256=p7bXOGaUwJpLsREI2lGSzK6lLna5W_k_zNXKWnPJdos,4022
91
+ liquid/utils/text.py,sha256=1SwDECNMaqnnZ05je_AZZgxqzZd6U-mvq5jNU3W1-Qk,841
92
+ python_liquid-2.1.0.dist-info/METADATA,sha256=hWoZ7ptvnd2teO9UkGuQeDhpYCQxoTbhG42ndbWDwJ0,6694
93
+ python_liquid-2.1.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
94
+ python_liquid-2.1.0.dist-info/licenses/LICENSE,sha256=yAFURzud5ERNHt1rZIPnTLJ92ep7q8y5yG9g5DUMR_E,1075
95
+ python_liquid-2.1.0.dist-info/RECORD,,
liquid/golden/__init__.py DELETED
@@ -1,173 +0,0 @@
1
- from . import abs_filter # noqa: D104
2
- from . import append_filter
3
- from . import assign_tag
4
- from . import at_least_filter
5
- from . import at_most_filter
6
- from . import base64_decode_filter
7
- from . import base64_encode_filter
8
- from . import base64_url_safe_decode_filter
9
- from . import base64_url_safe_encode_filter
10
- from . import capitalize_filter
11
- from . import capture_tag
12
- from . import case_tag
13
- from . import ceil_filter
14
- from . import comment_tag
15
- from . import compact_filter
16
- from . import concat_filter
17
- from . import cycle_tag
18
- from . import date_filter
19
- from . import decrement_tag
20
- from . import default_filter
21
- from . import divided_by_filter
22
- from . import doc_tag
23
- from . import downcase_filter
24
- from . import echo_tag
25
- from . import escape_filter
26
- from . import escape_once_filter
27
- from . import find_filter
28
- from . import find_index_filter
29
- from . import first_filter
30
- from . import floor_filter
31
- from . import for_tag
32
- from . import has_filter
33
- from . import identifiers
34
- from . import if_tag
35
- from . import ifchanged_tag
36
- from . import illegal
37
- from . import include_tag
38
- from . import increment_tag
39
- from . import inline_comment_tag
40
- from . import join_filter
41
- from . import last_filter
42
- from . import liquid_tag
43
- from . import lstrip_filter
44
- from . import map_filter
45
- from . import minus_filter
46
- from . import modulo_filter
47
- from . import newline_to_br_filter
48
- from . import not_liquid
49
- from . import output_statement
50
- from . import plus_filter
51
- from . import prepend_filter
52
- from . import range_objects
53
- from . import raw_tag
54
- from . import reject_filter
55
- from . import remove_filter
56
- from . import remove_first_filter
57
- from . import remove_last_filter
58
- from . import render_tag
59
- from . import replace_filter
60
- from . import replace_first_filter
61
- from . import replace_last_filter
62
- from . import reverse_filter
63
- from . import round_filter
64
- from . import rstrip_filter
65
- from . import size_filter
66
- from . import slice_filter
67
- from . import sort_filter
68
- from . import sort_natural_filter
69
- from . import special
70
- from . import split_filter
71
- from . import strip_filter
72
- from . import strip_html_filter
73
- from . import strip_newlines_filter
74
- from . import sum_filter
75
- from . import tablerow_tag
76
- from . import times_filter
77
- from . import truncate_filter
78
- from . import truncatewords_filter
79
- from . import uniq_filter
80
- from . import unless_tag
81
- from . import upcase_filter
82
- from . import url_decode_filter
83
- from . import url_encode_filter
84
- from . import where_filter
85
- from . import whitespace_control
86
-
87
- test_cases = [
88
- abs_filter,
89
- append_filter,
90
- assign_tag,
91
- at_least_filter,
92
- at_most_filter,
93
- base64_decode_filter,
94
- base64_encode_filter,
95
- base64_url_safe_decode_filter,
96
- base64_url_safe_encode_filter,
97
- capitalize_filter,
98
- capture_tag,
99
- case_tag,
100
- ceil_filter,
101
- comment_tag,
102
- compact_filter,
103
- concat_filter,
104
- cycle_tag,
105
- date_filter,
106
- decrement_tag,
107
- default_filter,
108
- divided_by_filter,
109
- doc_tag,
110
- downcase_filter,
111
- echo_tag,
112
- escape_filter,
113
- escape_once_filter,
114
- find_filter,
115
- find_index_filter,
116
- first_filter,
117
- floor_filter,
118
- for_tag,
119
- has_filter,
120
- identifiers,
121
- if_tag,
122
- ifchanged_tag,
123
- illegal,
124
- include_tag,
125
- increment_tag,
126
- inline_comment_tag,
127
- join_filter,
128
- last_filter,
129
- liquid_tag,
130
- lstrip_filter,
131
- map_filter,
132
- minus_filter,
133
- modulo_filter,
134
- newline_to_br_filter,
135
- not_liquid,
136
- output_statement,
137
- plus_filter,
138
- prepend_filter,
139
- range_objects,
140
- raw_tag,
141
- reject_filter,
142
- remove_filter,
143
- remove_first_filter,
144
- remove_last_filter,
145
- render_tag,
146
- replace_filter,
147
- replace_first_filter,
148
- replace_last_filter,
149
- reverse_filter,
150
- round_filter,
151
- rstrip_filter,
152
- size_filter,
153
- slice_filter,
154
- sort_filter,
155
- sort_natural_filter,
156
- special,
157
- split_filter,
158
- strip_filter,
159
- strip_html_filter,
160
- strip_newlines_filter,
161
- sum_filter,
162
- tablerow_tag,
163
- times_filter,
164
- truncate_filter,
165
- truncatewords_filter,
166
- uniq_filter,
167
- unless_tag,
168
- upcase_filter,
169
- url_decode_filter,
170
- url_encode_filter,
171
- where_filter,
172
- whitespace_control,
173
- ]
@@ -1,73 +0,0 @@
1
- """Golden tests cases for testing liquid's built-in `abs` filter."""
2
-
3
- from liquid.golden.case import Case
4
-
5
- cases = [
6
- Case(
7
- description="positive integer",
8
- template=r"{{ 5 | abs }}",
9
- expect="5",
10
- ),
11
- Case(
12
- description="negative integer",
13
- template=r"{{ -5 | abs }}",
14
- expect="5",
15
- ),
16
- Case(
17
- description="positive float",
18
- template=r"{{ 5.4 | abs }}",
19
- expect="5.4",
20
- ),
21
- Case(
22
- description="negative float",
23
- template=r"{{ -5.4 | abs }}",
24
- expect="5.4",
25
- ),
26
- Case(
27
- description="zero",
28
- template=r"{{ 0 | abs }}",
29
- expect="0",
30
- ),
31
- Case(
32
- description="positive string integer",
33
- template=r"{{ '5' | abs }}",
34
- expect="5",
35
- ),
36
- Case(
37
- description="negative string integer",
38
- template=r"{{ '-5' | abs }}",
39
- expect="5",
40
- ),
41
- Case(
42
- description="positive string float",
43
- template=r"{{ '5.1' | abs }}",
44
- expect="5.1",
45
- ),
46
- Case(
47
- description="negative string float",
48
- template=r"{{ '-5.1' | abs }}",
49
- expect="5.1",
50
- ),
51
- Case(
52
- description="unexpected argument",
53
- template=r"{{ -3 | abs: 1 }}",
54
- expect="",
55
- error=True,
56
- ),
57
- Case(
58
- description="string not a number",
59
- template=r"{{ 'hello' | abs }}",
60
- expect="0",
61
- ),
62
- Case(
63
- description="not a string, int or float",
64
- template=r"{{ a | abs }}",
65
- expect="0",
66
- globals={"a": {}},
67
- ),
68
- Case(
69
- description="undefined left value",
70
- template=r"{{ nosuchthing | abs }}",
71
- expect="0",
72
- ),
73
- ]
@@ -1,43 +0,0 @@
1
- """Golden tests cases for testing liquid's built-in `append` filter."""
2
-
3
- from liquid.golden.case import Case
4
-
5
- cases = [
6
- Case(
7
- description="concat",
8
- template=r'{{ "hello" | append: "there" }}',
9
- expect="hellothere",
10
- ),
11
- Case(
12
- description="not a string",
13
- template=r"{{ 5 | append: 'there' }}",
14
- expect="5there",
15
- ),
16
- Case(
17
- description="argument not a string",
18
- template=r'{{ "hello" | append: 5 }}',
19
- expect="hello5",
20
- ),
21
- Case(
22
- description="missing argument",
23
- template=r'{{ "hello" | append }}',
24
- expect="",
25
- error=True,
26
- ),
27
- Case(
28
- description="too many arguments",
29
- template=r'{{ "hello" | append: "how", "are", "you" }}',
30
- expect="",
31
- error=True,
32
- ),
33
- Case(
34
- description="undefined left value",
35
- template=r'{{ nosuchthing | append: "hi" }}',
36
- expect="hi",
37
- ),
38
- Case(
39
- description="undefined argument",
40
- template=r'{{ "hi" | append: nosuchthing }}',
41
- expect="hi",
42
- ),
43
- ]
@@ -1,45 +0,0 @@
1
- """Golden tests cases for testing liquid's `assign` tag."""
2
-
3
- from liquid.golden.case import Case
4
-
5
- cases = [
6
- Case(
7
- description="assign a filtered literal",
8
- template=r"{% assign foo = 'foo' | upcase %}{{ foo }}",
9
- expect="FOO",
10
- ),
11
- Case(
12
- description="local variables shadow global variables",
13
- template=r"{{ foo }}{% assign foo = 'foo' | upcase %}{{ foo }}",
14
- expect="barFOO",
15
- globals={"foo": "bar"},
16
- ),
17
- Case(
18
- description="assign a range literal",
19
- template=r"{% assign foo = (1..3) %}{{ foo | join: '#' }}",
20
- expect="1#2#3",
21
- ),
22
- Case(
23
- description="assign to variable with a hyphen",
24
- template=r"{% assign some-thing = 'foo' %}{{ some-thing }}",
25
- expect="foo",
26
- ),
27
- Case(
28
- description="assign an existing array",
29
- template=r"{% assign foo = bar %}{{ foo[0] }}/{{ foo[1] }}",
30
- expect="a/b",
31
- globals={"bar": ["a", "b", "c"]},
32
- ),
33
- Case(
34
- description="assign an item from an existing object with quoted notation",
35
- template=r"{% assign foo = bar['baz'] %}{{ foo }}",
36
- expect="hello",
37
- globals={"bar": {"baz": "hello"}},
38
- ),
39
- Case(
40
- description="assign with quoted notation and extra whitespace",
41
- template=r"{% assign foo = bar[ 'baz' ] %}{{ foo }}",
42
- expect="hello",
43
- globals={"bar": {"baz": "hello"}},
44
- ),
45
- ]