thtml-tstring 0.1.5__tar.gz → 0.1.7__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: thtml-tstring
3
- Version: 0.1.5
3
+ Version: 0.1.7
4
4
  Summary: T-HTML renderer for PEP 750 template strings
5
5
  Keywords: html,pep750,t-strings,template-strings,thtml
6
6
  Author: Koudai Aono
@@ -13,7 +13,7 @@ Classifier: Programming Language :: Python :: 3
13
13
  Classifier: Programming Language :: Python :: 3 :: Only
14
14
  Classifier: Programming Language :: Python :: 3.14
15
15
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
16
- Requires-Dist: tstring-html-bindings>=0.1.5
16
+ Requires-Dist: tstring-html-bindings>=0.1.7
17
17
  Maintainer: Koudai Aono
18
18
  Maintainer-email: Koudai Aono <koxudaxi@gmail.com>
19
19
  Requires-Python: >=3.14
@@ -37,6 +37,6 @@ def Button(*, children: str, kind: str = "primary"):
37
37
  return t'<button class="{classes}">{children}</button>'
38
38
 
39
39
  label = "Save"
40
- page = thtml(t"<Button kind='primary'>{label}</Button>")
40
+ page = thtml(t"<Button kind='primary'>{label}</Button>", registry={"Button": Button})
41
41
  assert page.render() == '<button class="primary">Save</button>'
42
42
  ```
@@ -11,6 +11,6 @@ def Button(*, children: str, kind: str = "primary"):
11
11
  return t'<button class="{classes}">{children}</button>'
12
12
 
13
13
  label = "Save"
14
- page = thtml(t"<Button kind='primary'>{label}</Button>")
14
+ page = thtml(t"<Button kind='primary'>{label}</Button>", registry={"Button": Button})
15
15
  assert page.render() == '<button class="primary">Save</button>'
16
16
  ```
@@ -1,13 +1,13 @@
1
1
  [project]
2
2
  name = "thtml-tstring"
3
- version = "0.1.5"
3
+ version = "0.1.7"
4
4
  description = "T-HTML renderer for PEP 750 template strings"
5
5
  readme = "README.md"
6
6
  license = { text = "MIT" }
7
7
  authors = [{ name = "Koudai Aono", email = "koxudaxi@gmail.com" }]
8
8
  maintainers = [{ name = "Koudai Aono", email = "koxudaxi@gmail.com" }]
9
9
  requires-python = ">=3.14"
10
- dependencies = ["tstring-html-bindings>=0.1.5"]
10
+ dependencies = ["tstring-html-bindings>=0.1.7"]
11
11
  keywords = ["html", "pep750", "t-strings", "template-strings", "thtml"]
12
12
  classifiers = [
13
13
  "Development Status :: 4 - Beta",
@@ -42,7 +42,9 @@ def _capture_scope(
42
42
  frame = sys._getframe(frame_depth)
43
43
  except AttributeError, ValueError:
44
44
  raise TemplateRuntimeError(
45
- "Caller-frame inspection failed. Pass globals= or locals= explicitly."
45
+ "Caller-frame inspection failed. "
46
+ "On runtimes without frame inspection you must pass registry=, "
47
+ "or both globals= and locals= explicitly."
46
48
  ) from None
47
49
 
48
50
  captured_globals = dict(globals) if globals is not None else dict(frame.f_globals)
@@ -50,6 +52,23 @@ def _capture_scope(
50
52
  return captured_globals, captured_locals
51
53
 
52
54
 
55
+ def _normalize_scope_overrides(
56
+ *,
57
+ globals: Mapping[str, Any] | None,
58
+ locals: Mapping[str, Any] | None,
59
+ registry: Mapping[str, object] | None,
60
+ api_name: str,
61
+ ) -> tuple[Mapping[str, Any] | None, Mapping[str, Any] | None]:
62
+ if registry is not None:
63
+ if globals is not None or locals is not None:
64
+ raise TypeError(
65
+ f"{api_name} does not allow combining registry= "
66
+ "with globals= or locals=."
67
+ )
68
+ return dict(registry), {}
69
+ return globals, locals
70
+
71
+
53
72
  def _make_thtml_renderable(
54
73
  template: object,
55
74
  *,
@@ -76,9 +95,14 @@ def component(
76
95
  func: ComponentT | None = None,
77
96
  *,
78
97
  backend: str = "thtml",
98
+ registry: Mapping[str, object] | None = None,
79
99
  ) -> ComponentT | Callable[[ComponentT], ComponentT]:
80
100
  if backend not in {"thtml", "html"}:
81
101
  raise ValueError("component backend must be 'thtml' or 'html'.")
102
+ if backend == "html" and registry is not None:
103
+ raise ValueError("component registry= is only supported for backend='thtml'.")
104
+
105
+ captured_registry = dict(registry) if registry is not None else None
82
106
 
83
107
  def decorator(inner: ComponentT) -> ComponentT:
84
108
  @wraps(inner)
@@ -86,9 +110,14 @@ def component(
86
110
  result = inner(*args, **kwargs)
87
111
  if _is_template(result):
88
112
  if backend == "thtml":
113
+ resolved_globals = (
114
+ captured_registry
115
+ if captured_registry is not None
116
+ else cast(Mapping[str, Any], inner.__globals__)
117
+ )
89
118
  return _make_thtml_renderable(
90
119
  result,
91
- globals=cast(Mapping[str, Any], inner.__globals__),
120
+ globals=resolved_globals,
92
121
  locals={},
93
122
  frame_depth=0,
94
123
  api_name="component",
@@ -128,11 +157,18 @@ def thtml(
128
157
  *,
129
158
  globals: Mapping[str, Any] | None = None,
130
159
  locals: Mapping[str, Any] | None = None,
160
+ registry: Mapping[str, object] | None = None,
131
161
  ) -> Renderable:
132
- return _make_thtml_renderable(
133
- template,
162
+ normalized_globals, normalized_locals = _normalize_scope_overrides(
134
163
  globals=globals,
135
164
  locals=locals,
165
+ registry=registry,
166
+ api_name="thtml",
167
+ )
168
+ return _make_thtml_renderable(
169
+ template,
170
+ globals=normalized_globals,
171
+ locals=normalized_locals,
136
172
  frame_depth=3,
137
173
  api_name="thtml",
138
174
  )
@@ -143,14 +179,21 @@ def render_html(
143
179
  *,
144
180
  globals: Mapping[str, Any] | None = None,
145
181
  locals: Mapping[str, Any] | None = None,
182
+ registry: Mapping[str, object] | None = None,
146
183
  ) -> str:
147
184
  if _is_renderable(template):
148
185
  return cast(Renderable, template).render()
149
186
 
150
187
  checked = _validate_template(template, "render_html")
188
+ normalized_globals, normalized_locals = _normalize_scope_overrides(
189
+ globals=globals,
190
+ locals=locals,
191
+ registry=registry,
192
+ api_name="render_html",
193
+ )
151
194
  captured_globals, captured_locals = _capture_scope(
152
- globals,
153
- locals,
195
+ normalized_globals,
196
+ normalized_locals,
154
197
  frame_depth=2,
155
198
  )
156
199
  return _bindings.render_thtml_template(
@@ -165,13 +208,20 @@ def html(
165
208
  *,
166
209
  globals: Mapping[str, Any] | None = None,
167
210
  locals: Mapping[str, Any] | None = None,
211
+ registry: Mapping[str, object] | None = None,
168
212
  ) -> str:
169
213
  if _is_renderable(template):
170
214
  return cast(Renderable, template).render()
171
215
  checked = _validate_template(template, "html")
216
+ normalized_globals, normalized_locals = _normalize_scope_overrides(
217
+ globals=globals,
218
+ locals=locals,
219
+ registry=registry,
220
+ api_name="html",
221
+ )
172
222
  captured_globals, captured_locals = _capture_scope(
173
- globals,
174
- locals,
223
+ normalized_globals,
224
+ normalized_locals,
175
225
  frame_depth=2,
176
226
  )
177
227
  return _bindings.render_thtml_template(