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
liquid/filters/uniq.py ADDED
@@ -0,0 +1,11 @@
1
+ from .._filter import FilterContext
2
+
3
+
4
+ def uniq(context: FilterContext, left: object, prop: object = None) -> list[object]:
5
+ left = context.input_array(left)
6
+
7
+ if context.is_nil(prop):
8
+ return [obj for i, obj in enumerate(left) if left.index(obj) == i]
9
+
10
+ keys = [context.get_item(obj, prop) for obj in left]
11
+ return [left[i] for i, key in enumerate(keys) if keys.index(key) == i]
@@ -0,0 +1,5 @@
1
+ from .._filter import FilterContext
2
+
3
+
4
+ def upcase(context: FilterContext, left: object) -> str:
5
+ return context.to_str(left, "").upper()
liquid/filters/url.py ADDED
@@ -0,0 +1,18 @@
1
+ import urllib.parse
2
+
3
+ import markupsafe
4
+
5
+ from .._filter import FilterContext
6
+
7
+
8
+ def url_encode(context: FilterContext, left: object) -> str:
9
+ left_ = context.to_str(left, "")
10
+
11
+ if context.env.autoescape:
12
+ return markupsafe.Markup(urllib.parse.quote_plus(left_))
13
+
14
+ return urllib.parse.quote_plus(left_)
15
+
16
+
17
+ def url_decode(context: FilterContext, left: object) -> str:
18
+ return urllib.parse.unquote_plus(context.to_str(left, ""), errors="strict")
@@ -0,0 +1,18 @@
1
+ from .._filter import FilterContext
2
+
3
+
4
+ def where(
5
+ context: FilterContext, left: object, prop: object, value: object = None
6
+ ) -> list[object]:
7
+ left = context.input_array(left)
8
+
9
+ if context.is_nil(prop):
10
+ return []
11
+
12
+ def _filter(obj: object) -> bool:
13
+ return context.truthy(context.get_item(obj, prop))
14
+
15
+ if context.is_nil(value):
16
+ return list(filter(_filter, left))
17
+
18
+ return [obj for obj in left if context.get_item(obj, prop) == value]
@@ -0,0 +1,17 @@
1
+ from .caching_file_system_loader import CachingFileSystemLoader
2
+ from .choice_loader import CachingChoiceLoader, ChoiceLoader
3
+ from .dict_loader import CachingDictLoader, DictLoader
4
+ from .file_system_loader import FileSystemLoader
5
+ from .mixins import CachingLoaderMixin
6
+ from .package_loader import PackageLoader
7
+
8
+ __all__ = (
9
+ "CachingChoiceLoader",
10
+ "CachingDictLoader",
11
+ "CachingFileSystemLoader",
12
+ "CachingLoaderMixin",
13
+ "ChoiceLoader",
14
+ "DictLoader",
15
+ "FileSystemLoader",
16
+ "PackageLoader",
17
+ )
@@ -0,0 +1,64 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING
4
+
5
+ from .file_system_loader import FileSystemLoader
6
+ from .mixins import CachingLoaderMixin
7
+
8
+ if TYPE_CHECKING:
9
+ from collections.abc import Iterable
10
+ from pathlib import Path
11
+
12
+
13
+ class CachingFileSystemLoader(CachingLoaderMixin, FileSystemLoader):
14
+ """A file system loader that caches parsed templates in memory.
15
+
16
+ Parameters
17
+ ----------
18
+ search_path
19
+ One or more paths to search.
20
+ encoding
21
+ Open template files with the given encoding.
22
+ ext
23
+ A default file extension. Should include a leading period.
24
+ reject_symlinks
25
+ When `True`, reject paths to symlinks that resolve to files outside the
26
+ search path. Defaults to `False`.
27
+ auto_reload
28
+ If `True`, automatically reload a cached template if it has been updated.
29
+ namespace_key
30
+ The name of a global render context variable or loader keyword argument
31
+ that resolves to the current loader "namespace" or "scope".
32
+
33
+ If you're developing a multi-user application, a good namespace might be
34
+ `uid`, where `uid` is a unique identifier for a user and templates are
35
+ arranged in folders named for each `uid` inside the search path.
36
+ capacity
37
+ The maximum number of templates to hold in the cache before removing the
38
+ least recently used template.
39
+ """
40
+
41
+ def __init__(
42
+ self,
43
+ search_path: str | Path | Iterable[str | Path],
44
+ encoding: str = "utf-8",
45
+ ext: str | None = None,
46
+ *,
47
+ reject_symlinks: bool = False,
48
+ auto_reload: bool = True,
49
+ namespace_key: str = "",
50
+ capacity: int = 300,
51
+ ):
52
+ super().__init__(
53
+ auto_reload=auto_reload,
54
+ namespace_key=namespace_key,
55
+ capacity=capacity,
56
+ )
57
+
58
+ FileSystemLoader.__init__(
59
+ self,
60
+ search_path=search_path,
61
+ encoding=encoding,
62
+ ext=ext,
63
+ reject_symlinks=reject_symlinks,
64
+ )
@@ -0,0 +1,93 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING
4
+
5
+ from .._loader import Loader, TemplateSource
6
+ from ..exceptions import TemplateNotFoundError
7
+ from .mixins import CachingLoaderMixin
8
+
9
+ if TYPE_CHECKING:
10
+ from .._context import RenderContext
11
+ from ..environment import Environment
12
+
13
+
14
+ class ChoiceLoader(Loader):
15
+ """A template loader that delegates to other template loaders.
16
+
17
+ Parameters
18
+ ----------
19
+ loaders
20
+ A list of loaders implementing `liquid.Loader`.
21
+ """
22
+
23
+ def __init__(self, loaders: list[Loader]):
24
+ super().__init__()
25
+ self.loaders = loaders
26
+
27
+ def get_source(
28
+ self,
29
+ env: Environment,
30
+ name: str,
31
+ context: RenderContext | None = None,
32
+ **kwargs: object,
33
+ ) -> TemplateSource:
34
+ """Get source information for a template."""
35
+ for loader in self.loaders:
36
+ try:
37
+ return loader.get_source(env, name, context=context, **kwargs)
38
+ except TemplateNotFoundError:
39
+ pass
40
+
41
+ raise TemplateNotFoundError(name)
42
+
43
+ async def get_source_async(
44
+ self,
45
+ env: Environment,
46
+ name: str,
47
+ context: RenderContext | None = None,
48
+ **kwargs: object,
49
+ ) -> TemplateSource:
50
+ """Get source information for a template."""
51
+ for loader in self.loaders:
52
+ try:
53
+ return await loader.get_source_async(
54
+ env, name, context=context, **kwargs
55
+ )
56
+ except TemplateNotFoundError:
57
+ pass
58
+
59
+ raise TemplateNotFoundError(name)
60
+
61
+
62
+ class CachingChoiceLoader(CachingLoaderMixin, ChoiceLoader):
63
+ """A `ChoiceLoader` that caches parsed templates in memory.
64
+
65
+ Parameters
66
+ ----------
67
+ loaders
68
+ A list of loaders implementing `liquid.Loader`.
69
+ auto_reload
70
+ If ``True``, automatically reload a cached template if it has been updated.
71
+ namespace_key
72
+ The name of a global render context variable or loader keyword argument
73
+ that resolves to the current loader "namespace" or "scope".
74
+ capacity
75
+ The maximum number of templates to hold in the cache before removing the
76
+ least recently used template.
77
+ """
78
+
79
+ def __init__(
80
+ self,
81
+ loaders: list[Loader],
82
+ *,
83
+ auto_reload: bool = True,
84
+ namespace_key: str = "",
85
+ capacity: int = 300,
86
+ ):
87
+ super().__init__(
88
+ auto_reload=auto_reload,
89
+ namespace_key=namespace_key,
90
+ capacity=capacity,
91
+ )
92
+
93
+ ChoiceLoader.__init__(self, loaders)
@@ -0,0 +1,56 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING
4
+
5
+ from .._loader import Loader, TemplateSource
6
+ from ..exceptions import TemplateNotFoundError
7
+ from .mixins import CachingLoaderMixin
8
+
9
+ if TYPE_CHECKING:
10
+ from .._context import RenderContext
11
+ from ..environment import Environment
12
+
13
+
14
+ class DictLoader(Loader):
15
+ """A template loader that reads source text from a dictionary.
16
+
17
+ Parameters
18
+ ----------
19
+ templates
20
+ A mapping of template names to template source code.
21
+ """
22
+
23
+ def __init__(self, templates: dict[str, str]) -> None:
24
+ super().__init__()
25
+ self.templates = templates
26
+
27
+ def get_source(
28
+ self,
29
+ env: Environment,
30
+ name: str,
31
+ context: RenderContext | None = None,
32
+ **kwargs: object,
33
+ ) -> TemplateSource:
34
+ if name not in self.templates:
35
+ raise TemplateNotFoundError(name)
36
+ return TemplateSource(name=name, text=self.templates[name])
37
+
38
+
39
+ class CachingDictLoader(CachingLoaderMixin, DictLoader):
40
+ """A ``DictLoader`` that caches parsed templates in memory."""
41
+
42
+ def __init__(
43
+ self,
44
+ templates: dict[str, str],
45
+ *,
46
+ auto_reload: bool = True,
47
+ namespace_key: str = "",
48
+ capacity: int = 300,
49
+ ):
50
+ super().__init__(
51
+ auto_reload=auto_reload,
52
+ namespace_key=namespace_key,
53
+ capacity=capacity,
54
+ )
55
+
56
+ DictLoader.__init__(self, templates)
@@ -1,46 +1,46 @@
1
- """Built-in file system loader."""
2
-
3
1
  from __future__ import annotations
4
2
 
5
3
  import asyncio
6
4
  import os
5
+ from collections.abc import Iterable
7
6
  from functools import partial
8
- from pathlib import Path
9
- from pathlib import PurePath
7
+ from pathlib import Path, PurePath
10
8
  from typing import TYPE_CHECKING
11
- from typing import Iterable
12
- from typing import Optional
13
- from typing import Union
14
9
 
15
- from liquid.exceptions import TemplateNotFoundError
16
- from liquid.loader import BaseLoader
17
- from liquid.loader import TemplateSource
10
+ from .._loader import Loader, TemplateSource
11
+ from ..exceptions import TemplateNotFoundError
18
12
 
19
13
  if TYPE_CHECKING:
20
- from liquid import Environment
21
- from liquid import RenderContext
22
-
23
-
24
- class FileSystemLoader(BaseLoader):
25
- """A loader that loads templates from one or more directories on the file system.
26
-
27
- Args:
28
- search_path: One or more paths to search.
29
- encoding: Encoding to use when opening files.
30
- ext: A default file extension. Should include a leading period.
31
- reject_symlinks: When `True`, reject paths to symlinks that resolve to files
32
- outside the search path. Defaults to `False`.
33
-
34
- Raise:
35
- ValueError if `ext` is not a valid suffix.
14
+ from liquid import Environment, RenderContext
15
+
16
+
17
+ class FileSystemLoader(Loader):
18
+ """A loader that loads templates from one or more directories on a file system.
19
+
20
+ Parameters
21
+ ----------
22
+ search_path
23
+ One or more paths to search.
24
+ encoding
25
+ Encoding to use when opening files.
26
+ ext
27
+ A default file extension. Should include a leading period.
28
+ reject_symlinks
29
+ When ``True``, reject paths to symlinks that resolve to files outside the
30
+ search path. Defaults to `False`.
31
+
32
+ Raises
33
+ ------
34
+ ValueError
35
+ If `ext` is not a valid suffix.
36
36
  """
37
37
 
38
38
  def __init__(
39
39
  self,
40
- search_path: Union[str, Path, Iterable[Union[str, Path]]],
40
+ search_path: str | Path | Iterable[str | Path],
41
41
  *,
42
42
  encoding: str = "utf-8",
43
- ext: Optional[str] = None,
43
+ ext: str | None = None,
44
44
  reject_symlinks: bool = False,
45
45
  ):
46
46
  super().__init__()
@@ -56,25 +56,19 @@ class FileSystemLoader(BaseLoader):
56
56
  if ext:
57
57
  Path("x").with_suffix(ext)
58
58
 
59
- def resolve_path(self, template_name: str) -> Path:
60
- """Return a path to the template identified by _template_name_.
61
-
62
- If the search path is a list of paths, returns the first path where
63
- _template_name_ exists. If none of the search paths contain _template_name_, a
64
- _TemplateNotFound_ exception is raised.
65
- """
66
- template_path = PurePath(template_name)
59
+ def resolve_path(self, name: str) -> Path:
60
+ template_path = PurePath(name)
67
61
  if template_path.anchor:
68
62
  template_path = PurePath(*template_path.parts[1:])
69
63
 
70
64
  if not template_path.name:
71
- raise TemplateNotFoundError(template_name)
65
+ raise TemplateNotFoundError(name)
72
66
 
73
67
  if self.ext and not template_path.suffix:
74
68
  template_path = template_path.with_suffix(self.ext)
75
69
 
76
70
  if os.path.pardir in template_path.parts or template_path.is_absolute():
77
- raise TemplateNotFoundError(template_name)
71
+ raise TemplateNotFoundError(name)
78
72
 
79
73
  for base in self.search_path:
80
74
  base_resolved = base.resolve()
@@ -96,7 +90,7 @@ class FileSystemLoader(BaseLoader):
96
90
  # We don't want to expose a fully qualified path in error messages.
97
91
  return base / template_path
98
92
 
99
- raise TemplateNotFoundError(template_name)
93
+ raise TemplateNotFoundError(name)
100
94
 
101
95
  def _read(self, source_path: Path) -> tuple[str, float]:
102
96
  with source_path.open(encoding=self.encoding) as fd:
@@ -105,19 +99,19 @@ class FileSystemLoader(BaseLoader):
105
99
 
106
100
  def get_source(
107
101
  self,
108
- env: Environment, # noqa: ARG002
109
- template_name: str,
110
- *,
111
- context: Optional[RenderContext] = None, # noqa: ARG002
112
- **kwargs: object, # noqa: ARG002
102
+ env: Environment,
103
+ name: str,
104
+ context: RenderContext | None = None,
105
+ **kwargs: object,
113
106
  ) -> TemplateSource:
114
107
  """Get source information for a template."""
115
- source_path = self.resolve_path(template_name)
108
+ source_path = self.resolve_path(name)
116
109
  source, mtime = self._read(source_path)
117
110
  return TemplateSource(
118
- source,
119
- str(source_path),
120
- partial(self._uptodate, source_path, mtime),
111
+ text=source,
112
+ name=source_path.name,
113
+ path=str(source_path),
114
+ up_to_date=partial(self._uptodate, source_path, mtime),
121
115
  )
122
116
 
123
117
  @staticmethod
@@ -132,16 +126,18 @@ class FileSystemLoader(BaseLoader):
132
126
 
133
127
  async def get_source_async(
134
128
  self,
135
- env: Environment, # noqa: ARG002
136
- template_name: str,
137
- *,
138
- context: Optional[RenderContext] = None, # noqa: ARG002
139
- **kwargs: object, # noqa: ARG002
129
+ env: Environment,
130
+ name: str,
131
+ context: RenderContext | None = None,
132
+ **kwargs: object,
140
133
  ) -> TemplateSource:
141
134
  """Get source information for a template."""
142
135
  loop = asyncio.get_running_loop()
143
- source_path = await loop.run_in_executor(None, self.resolve_path, template_name)
136
+ source_path = await loop.run_in_executor(None, self.resolve_path, name)
144
137
  source, mtime = await loop.run_in_executor(None, self._read, source_path)
145
138
  return TemplateSource(
146
- source, str(source_path), partial(self._uptodate_async, source_path, mtime)
139
+ text=source,
140
+ name=source_path.name,
141
+ path=str(source_path),
142
+ up_to_date=partial(self._uptodate_async, source_path, mtime),
147
143
  )
@@ -1,28 +1,18 @@
1
- """Mixin classes that can be used to add common functions to a template loader."""
2
-
3
1
  from __future__ import annotations
4
2
 
5
3
  from abc import ABC
6
4
  from contextlib import suppress
7
5
  from functools import partial
8
- from typing import TYPE_CHECKING
9
- from typing import Awaitable
10
- from typing import Callable
11
- from typing import Mapping
12
- from typing import Optional
13
- from typing import Protocol
6
+ from typing import TYPE_CHECKING, Protocol
14
7
 
15
- from liquid.utils import LRUCache
16
- from liquid.utils import ThreadSafeLRUCache
8
+ from .._lru_cache import LRUCache, ThreadSafeLRUCache
17
9
 
18
10
  if TYPE_CHECKING:
19
- from liquid import BoundTemplate
20
- from liquid import Environment
21
- from liquid import RenderContext
22
-
23
- # ruff: noqa: D102
11
+ from collections.abc import Awaitable, Callable, Mapping
24
12
 
25
- # ignoring "safe-super" type errors due to https://github.com/python/mypy/issues/14757
13
+ from .._context import RenderContext
14
+ from .._template import Template
15
+ from ..environment import Environment
26
16
 
27
17
 
28
18
  class _CachingLoaderProtocol(Protocol):
@@ -30,21 +20,19 @@ class _CachingLoaderProtocol(Protocol):
30
20
  self,
31
21
  env: Environment,
32
22
  name: str,
33
- *,
34
- globals: Optional[Mapping[str, object]] = None, # noqa: A002
35
- context: Optional[RenderContext] = None,
23
+ globals: Mapping[str, object] | None = None,
24
+ context: RenderContext | None = None,
36
25
  **kwargs: object,
37
- ) -> BoundTemplate: ...
26
+ ) -> Template: ...
38
27
 
39
28
  async def load_async( # pragma: no cover
40
29
  self,
41
30
  env: Environment,
42
31
  name: str,
43
- *,
44
- globals: Optional[Mapping[str, object]] = None, # noqa: A002
45
- context: Optional[RenderContext] = None,
32
+ globals: Mapping[str, object] | None = None,
33
+ context: RenderContext | None = None,
46
34
  **kwargs: object,
47
- ) -> BoundTemplate: ...
35
+ ) -> Template: ...
48
36
 
49
37
 
50
38
  class CachingLoaderMixin(ABC, _CachingLoaderProtocol):
@@ -62,19 +50,20 @@ class CachingLoaderMixin(ABC, _CachingLoaderProtocol):
62
50
  ):
63
51
  self.auto_reload = auto_reload
64
52
  self.cache = (
65
- ThreadSafeLRUCache[str, "BoundTemplate"](capacity=capacity)
53
+ ThreadSafeLRUCache[str, "Template"](capacity=capacity)
66
54
  if thread_safe
67
- else LRUCache[str, "BoundTemplate"](capacity=capacity)
55
+ else LRUCache[str, "Template"](capacity=capacity)
68
56
  )
69
57
  self.namespace_key = namespace_key
70
58
 
71
59
  def _check_cache(
72
60
  self,
73
- env: Environment, # noqa: ARG002
61
+ *,
62
+ env: Environment,
74
63
  cache_key: str,
75
- globals: Optional[Mapping[str, object]], # noqa: A002
76
- load_func: Callable[[], BoundTemplate],
77
- ) -> BoundTemplate:
64
+ globals: Mapping[str, object] | None,
65
+ load_func: Callable[[], Template],
66
+ ) -> Template:
78
67
  try:
79
68
  cached_template = self.cache[cache_key]
80
69
  except KeyError:
@@ -93,11 +82,12 @@ class CachingLoaderMixin(ABC, _CachingLoaderProtocol):
93
82
 
94
83
  async def _check_cache_async(
95
84
  self,
96
- env: Environment, # noqa: ARG002
85
+ *,
86
+ env: Environment,
97
87
  cache_key: str,
98
- globals: Optional[Mapping[str, object]], # noqa: A002
99
- load_func: Callable[[], Awaitable[BoundTemplate]],
100
- ) -> BoundTemplate:
88
+ globals: Mapping[str, object] | None,
89
+ load_func: Callable[[], Awaitable[Template]],
90
+ ) -> Template:
101
91
  try:
102
92
  cached_template = self.cache[cache_key]
103
93
  except KeyError:
@@ -118,17 +108,16 @@ class CachingLoaderMixin(ABC, _CachingLoaderProtocol):
118
108
  self,
119
109
  env: Environment,
120
110
  name: str,
121
- *,
122
- globals: Optional[Mapping[str, object]] = None, # noqa: A002
123
- context: Optional[RenderContext] = None,
111
+ globals: Mapping[str, object] | None = None,
112
+ context: RenderContext | None = None,
124
113
  **kwargs: object,
125
- ) -> BoundTemplate:
114
+ ) -> Template:
126
115
  cache_key = self.cache_key(name, context, kwargs)
127
116
  return self._check_cache(
128
- env,
129
- cache_key,
130
- globals,
131
- partial(
117
+ env=env,
118
+ cache_key=cache_key,
119
+ globals=globals,
120
+ load_func=partial(
132
121
  super().load, # type: ignore
133
122
  env,
134
123
  name,
@@ -142,17 +131,16 @@ class CachingLoaderMixin(ABC, _CachingLoaderProtocol):
142
131
  self,
143
132
  env: Environment,
144
133
  name: str,
145
- *,
146
- globals: Optional[Mapping[str, object]] = None, # noqa: A002
147
- context: Optional[RenderContext] = None,
134
+ globals: Mapping[str, object] | None = None,
135
+ context: RenderContext | None = None,
148
136
  **kwargs: object,
149
- ) -> BoundTemplate:
137
+ ) -> Template:
150
138
  cache_key = self.cache_key(name, context, kwargs)
151
139
  return await self._check_cache_async(
152
- env,
153
- cache_key,
154
- globals,
155
- partial(
140
+ env=env,
141
+ cache_key=cache_key,
142
+ globals=globals,
143
+ load_func=partial(
156
144
  super().load_async, # type: ignore
157
145
  env,
158
146
  name,
@@ -165,7 +153,7 @@ class CachingLoaderMixin(ABC, _CachingLoaderProtocol):
165
153
  def cache_key(
166
154
  self,
167
155
  name: str,
168
- context: Optional[RenderContext],
156
+ context: RenderContext | None,
169
157
  args: Mapping[str, object],
170
158
  ) -> str:
171
159
  if not self.namespace_key: