python-liquid 2.0.2__tar.gz → 2.1.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.
Files changed (97) hide show
  1. {python_liquid-2.0.2 → python_liquid-2.1.0}/PKG-INFO +2 -1
  2. {python_liquid-2.0.2 → python_liquid-2.1.0}/README.md +1 -0
  3. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/__init__.py +1 -1
  4. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/builtin/__init__.py +2 -0
  5. python_liquid-2.1.0/liquid/builtin/filters/extra.py +83 -0
  6. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/builtin/filters/string.py +36 -4
  7. {python_liquid-2.0.2 → python_liquid-2.1.0}/pyproject.toml +1 -0
  8. python_liquid-2.0.2/liquid/builtin/filters/extra.py +0 -21
  9. {python_liquid-2.0.2 → python_liquid-2.1.0}/.gitignore +0 -0
  10. {python_liquid-2.0.2 → python_liquid-2.1.0}/LICENSE +0 -0
  11. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/analyze_tags.py +0 -0
  12. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/ast.py +0 -0
  13. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/builtin/content.py +0 -0
  14. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/builtin/drops/__init__.py +0 -0
  15. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/builtin/drops/drops.py +0 -0
  16. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/builtin/expressions/__init__.py +0 -0
  17. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/builtin/expressions/_tokenize.py +0 -0
  18. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/builtin/expressions/arguments.py +0 -0
  19. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/builtin/expressions/filtered.py +0 -0
  20. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/builtin/expressions/logical.py +0 -0
  21. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/builtin/expressions/loop.py +0 -0
  22. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/builtin/expressions/path.py +0 -0
  23. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/builtin/expressions/primitive.py +0 -0
  24. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/builtin/filters/__init__.py +0 -0
  25. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/builtin/filters/array.py +0 -0
  26. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/builtin/filters/math.py +0 -0
  27. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/builtin/filters/misc.py +0 -0
  28. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/builtin/illegal.py +0 -0
  29. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/builtin/loaders/__init__.py +0 -0
  30. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/builtin/loaders/caching_file_system_loader.py +0 -0
  31. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/builtin/loaders/choice_loader.py +0 -0
  32. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/builtin/loaders/dict_loader.py +0 -0
  33. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/builtin/loaders/file_system_loader.py +0 -0
  34. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/builtin/loaders/mixins.py +0 -0
  35. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/builtin/loaders/package_loader.py +0 -0
  36. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/builtin/output.py +0 -0
  37. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/builtin/tags/__init__.py +0 -0
  38. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/builtin/tags/assign_tag.py +0 -0
  39. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/builtin/tags/capture_tag.py +0 -0
  40. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/builtin/tags/case_tag.py +0 -0
  41. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/builtin/tags/comment_tag.py +0 -0
  42. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/builtin/tags/cycle_tag.py +0 -0
  43. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/builtin/tags/decrement_tag.py +0 -0
  44. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/builtin/tags/doc_tag.py +0 -0
  45. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/builtin/tags/echo_tag.py +0 -0
  46. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/builtin/tags/for_tag.py +0 -0
  47. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/builtin/tags/if_tag.py +0 -0
  48. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/builtin/tags/ifchanged_tag.py +0 -0
  49. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/builtin/tags/include_tag.py +0 -0
  50. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/builtin/tags/increment_tag.py +0 -0
  51. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/builtin/tags/inline_comment_tag.py +0 -0
  52. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/builtin/tags/liquid_tag.py +0 -0
  53. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/builtin/tags/render_tag.py +0 -0
  54. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/builtin/tags/tablerow_tag.py +0 -0
  55. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/builtin/tags/unless_tag.py +0 -0
  56. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/context.py +0 -0
  57. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/environment.py +0 -0
  58. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/exceptions.py +0 -0
  59. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/expression.py +0 -0
  60. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/extra/__init__.py +0 -0
  61. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/extra/filters/__init__.py +0 -0
  62. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/extra/filters/_json.py +0 -0
  63. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/extra/filters/array.py +0 -0
  64. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/extra/filters/babel.py +0 -0
  65. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/extra/filters/html.py +0 -0
  66. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/extra/filters/translate.py +0 -0
  67. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/extra/tags/__init__.py +0 -0
  68. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/extra/tags/_with.py +0 -0
  69. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/extra/tags/extends_tag.py +0 -0
  70. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/extra/tags/macro_tag.py +0 -0
  71. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/extra/tags/translate_tag.py +0 -0
  72. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/filter.py +0 -0
  73. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/future/__init__.py +0 -0
  74. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/future/environment.py +0 -0
  75. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/future/filters/__init__.py +0 -0
  76. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/future/tags/__init__.py +0 -0
  77. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/lex.py +0 -0
  78. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/limits.py +0 -0
  79. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/loader.py +0 -0
  80. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/messages.py +0 -0
  81. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/mode.py +0 -0
  82. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/output.py +0 -0
  83. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/parser.py +0 -0
  84. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/py.typed +0 -0
  85. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/span.py +0 -0
  86. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/static_analysis.py +0 -0
  87. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/stream.py +0 -0
  88. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/stringify.py +0 -0
  89. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/tag.py +0 -0
  90. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/template.py +0 -0
  91. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/token.py +0 -0
  92. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/undefined.py +0 -0
  93. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/utils/__init__.py +0 -0
  94. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/utils/chain_map.py +0 -0
  95. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/utils/html.py +0 -0
  96. {python_liquid-2.0.2 → python_liquid-2.1.0}/liquid/utils/lru_cache.py +0 -0
  97. {python_liquid-2.0.2 → python_liquid-2.1.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.0.2
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/
@@ -105,6 +105,7 @@ $ conda install -c conda-forge python-liquid
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
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).
108
109
  - [LiquidScript](https://github.com/jg-rp/liquidscript): A JavaScript engine for Liquid with a similar high-level API to Python Liquid.
109
110
 
110
111
  ## Quick Start
@@ -75,6 +75,7 @@ $ conda install -c conda-forge python-liquid
75
75
 
76
76
  - [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).
77
77
  - [Ruby Liquid2](https://github.com/jg-rp/ruby-liquid2): Liquid2 templates for Ruby.
78
+ - [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).
78
79
  - [LiquidScript](https://github.com/jg-rp/liquidscript): A JavaScript engine for Liquid with a similar high-level API to Python Liquid.
79
80
 
80
81
  ## Quick Start
@@ -56,7 +56,7 @@ from .tag import Tag
56
56
 
57
57
  from . import future
58
58
 
59
- __version__ = "2.0.2"
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)
@@ -0,0 +1,83 @@
1
+ """Filters that don't exist in the reference implementation."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import re
6
+ from typing import TYPE_CHECKING
7
+
8
+ from liquid import Markup
9
+ from liquid.filter import string_filter
10
+ from liquid.filter import with_environment
11
+
12
+ if TYPE_CHECKING:
13
+ from liquid import Environment
14
+
15
+
16
+ @with_environment
17
+ @string_filter
18
+ def safe(val: str, *, environment: Environment) -> str:
19
+ """Return a copy of _val_ that will not be automatically HTML escaped on output."""
20
+ if environment.autoescape:
21
+ return Markup(val)
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()
@@ -214,6 +214,7 @@ ignore = [
214
214
  "PLR2004",
215
215
  "S704",
216
216
  "TC006",
217
+ "PLW1641",
217
218
  ]
218
219
 
219
220
  fixable = ["I", "SIM", "D202"]
@@ -1,21 +0,0 @@
1
- """Filters that don't exist in the reference implementation."""
2
-
3
- from __future__ import annotations
4
-
5
- from typing import TYPE_CHECKING
6
-
7
- from liquid import Markup
8
- from liquid.filter import string_filter
9
- from liquid.filter import with_environment
10
-
11
- if TYPE_CHECKING:
12
- from liquid import Environment
13
-
14
-
15
- @with_environment
16
- @string_filter
17
- def safe(val: str, *, environment: Environment) -> str:
18
- """Return a copy of _val_ that will not be automatically HTML escaped on output."""
19
- if environment.autoescape:
20
- return Markup(val)
21
- return val
File without changes
File without changes