thtml-tstring 0.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.
- thtml_tstring/__init__.py +41 -0
- thtml_tstring/_bindings.py +35 -0
- thtml_tstring/_runtime.py +181 -0
- thtml_tstring/py.typed +1 -0
- thtml_tstring-0.1.0.dist-info/METADATA +42 -0
- thtml_tstring-0.1.0.dist-info/RECORD +7 -0
- thtml_tstring-0.1.0.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
from ._bindings import (
|
|
2
|
+
CompiledThtmlTemplate,
|
|
3
|
+
Fragment,
|
|
4
|
+
RawHtml,
|
|
5
|
+
Renderable,
|
|
6
|
+
TemplateError,
|
|
7
|
+
TemplateParseError,
|
|
8
|
+
TemplateRuntimeError,
|
|
9
|
+
TemplateSemanticError,
|
|
10
|
+
)
|
|
11
|
+
from ._runtime import (
|
|
12
|
+
ThtmlTemplate,
|
|
13
|
+
check_template,
|
|
14
|
+
compile_template,
|
|
15
|
+
component,
|
|
16
|
+
format_template,
|
|
17
|
+
html,
|
|
18
|
+
render_html,
|
|
19
|
+
spread,
|
|
20
|
+
thtml,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
__all__ = [
|
|
24
|
+
"CompiledThtmlTemplate",
|
|
25
|
+
"Fragment",
|
|
26
|
+
"RawHtml",
|
|
27
|
+
"Renderable",
|
|
28
|
+
"TemplateError",
|
|
29
|
+
"TemplateParseError",
|
|
30
|
+
"TemplateRuntimeError",
|
|
31
|
+
"TemplateSemanticError",
|
|
32
|
+
"ThtmlTemplate",
|
|
33
|
+
"check_template",
|
|
34
|
+
"compile_template",
|
|
35
|
+
"component",
|
|
36
|
+
"format_template",
|
|
37
|
+
"html",
|
|
38
|
+
"render_html",
|
|
39
|
+
"spread",
|
|
40
|
+
"thtml",
|
|
41
|
+
]
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
try:
|
|
4
|
+
import tstring_html_bindings as _bindings
|
|
5
|
+
except ImportError: # pragma: no cover
|
|
6
|
+
from tstring_html_bindings import _bindings # type: ignore[attr-defined]
|
|
7
|
+
|
|
8
|
+
TemplateError = _bindings.TemplateError
|
|
9
|
+
TemplateParseError = _bindings.TemplateParseError
|
|
10
|
+
TemplateSemanticError = _bindings.TemplateSemanticError
|
|
11
|
+
TemplateRuntimeError = _bindings.TemplateRuntimeError
|
|
12
|
+
Fragment = _bindings.Fragment
|
|
13
|
+
RawHtml = _bindings.RawHtml
|
|
14
|
+
Renderable = _bindings.Renderable
|
|
15
|
+
CompiledThtmlTemplate = _bindings.CompiledThtmlTemplate
|
|
16
|
+
|
|
17
|
+
check_thtml_template = _bindings.check_thtml_template
|
|
18
|
+
format_thtml_template = _bindings.format_thtml_template
|
|
19
|
+
compile_thtml_template = _bindings.compile_thtml_template
|
|
20
|
+
render_thtml_template = _bindings.render_thtml_template
|
|
21
|
+
|
|
22
|
+
__all__ = [
|
|
23
|
+
"CompiledThtmlTemplate",
|
|
24
|
+
"Fragment",
|
|
25
|
+
"RawHtml",
|
|
26
|
+
"Renderable",
|
|
27
|
+
"TemplateError",
|
|
28
|
+
"TemplateParseError",
|
|
29
|
+
"TemplateRuntimeError",
|
|
30
|
+
"TemplateSemanticError",
|
|
31
|
+
"check_thtml_template",
|
|
32
|
+
"compile_thtml_template",
|
|
33
|
+
"format_thtml_template",
|
|
34
|
+
"render_thtml_template",
|
|
35
|
+
]
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import sys
|
|
4
|
+
from functools import wraps
|
|
5
|
+
from string.templatelib import Template
|
|
6
|
+
from typing import Annotated, Any, Callable, Mapping, TypeIs, TypeVar, cast
|
|
7
|
+
|
|
8
|
+
from . import _bindings
|
|
9
|
+
from ._bindings import CompiledThtmlTemplate, Renderable, TemplateRuntimeError
|
|
10
|
+
|
|
11
|
+
type ThtmlTemplate = Annotated[Template, "thtml"]
|
|
12
|
+
ComponentT = TypeVar("ComponentT", bound=Callable[..., object])
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _is_template(value: object) -> TypeIs[Template]:
|
|
16
|
+
return isinstance(value, Template)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _is_renderable(value: object) -> TypeIs[Renderable]:
|
|
20
|
+
return isinstance(value, Renderable)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _validate_template(template: object, api_name: str) -> ThtmlTemplate:
|
|
24
|
+
if _is_template(template):
|
|
25
|
+
return template
|
|
26
|
+
raise TypeError(
|
|
27
|
+
f"{api_name} requires a PEP 750 Template object. "
|
|
28
|
+
f"Got {type(template).__name__} instead."
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _capture_scope(
|
|
33
|
+
globals: Mapping[str, Any] | None,
|
|
34
|
+
locals: Mapping[str, Any] | None,
|
|
35
|
+
*,
|
|
36
|
+
frame_depth: int,
|
|
37
|
+
) -> tuple[dict[str, Any], dict[str, Any]]:
|
|
38
|
+
if globals is not None and locals is not None:
|
|
39
|
+
return dict(globals), dict(locals)
|
|
40
|
+
|
|
41
|
+
try:
|
|
42
|
+
frame = sys._getframe(frame_depth)
|
|
43
|
+
except AttributeError, ValueError:
|
|
44
|
+
raise TemplateRuntimeError(
|
|
45
|
+
"Caller-frame inspection failed. Pass globals= or locals= explicitly."
|
|
46
|
+
) from None
|
|
47
|
+
|
|
48
|
+
captured_globals = dict(globals) if globals is not None else dict(frame.f_globals)
|
|
49
|
+
captured_locals = dict(locals) if locals is not None else dict(frame.f_locals)
|
|
50
|
+
return captured_globals, captured_locals
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def _make_thtml_renderable(
|
|
54
|
+
template: object,
|
|
55
|
+
*,
|
|
56
|
+
globals: Mapping[str, Any] | None,
|
|
57
|
+
locals: Mapping[str, Any] | None,
|
|
58
|
+
frame_depth: int,
|
|
59
|
+
api_name: str,
|
|
60
|
+
) -> Renderable:
|
|
61
|
+
checked = _validate_template(template, api_name)
|
|
62
|
+
captured_globals, captured_locals = _capture_scope(
|
|
63
|
+
globals,
|
|
64
|
+
locals,
|
|
65
|
+
frame_depth=frame_depth,
|
|
66
|
+
)
|
|
67
|
+
return Renderable(
|
|
68
|
+
"thtml",
|
|
69
|
+
checked,
|
|
70
|
+
globals=captured_globals,
|
|
71
|
+
locals=captured_locals,
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def component(
|
|
76
|
+
func: ComponentT | None = None,
|
|
77
|
+
*,
|
|
78
|
+
backend: str = "thtml",
|
|
79
|
+
) -> ComponentT | Callable[[ComponentT], ComponentT]:
|
|
80
|
+
if backend not in {"thtml", "html"}:
|
|
81
|
+
raise ValueError("component backend must be 'thtml' or 'html'.")
|
|
82
|
+
|
|
83
|
+
def decorator(inner: ComponentT) -> ComponentT:
|
|
84
|
+
@wraps(inner)
|
|
85
|
+
def wrapped(*args: Any, **kwargs: Any) -> object:
|
|
86
|
+
result = inner(*args, **kwargs)
|
|
87
|
+
if _is_template(result):
|
|
88
|
+
if backend == "thtml":
|
|
89
|
+
return _make_thtml_renderable(
|
|
90
|
+
result,
|
|
91
|
+
globals=cast(Mapping[str, Any], inner.__globals__),
|
|
92
|
+
locals={},
|
|
93
|
+
frame_depth=0,
|
|
94
|
+
api_name="component",
|
|
95
|
+
)
|
|
96
|
+
from html_tstring import html as html_renderable
|
|
97
|
+
|
|
98
|
+
return html_renderable(result)
|
|
99
|
+
return result
|
|
100
|
+
|
|
101
|
+
return cast(ComponentT, wrapped)
|
|
102
|
+
|
|
103
|
+
if func is None:
|
|
104
|
+
return decorator
|
|
105
|
+
return decorator(func)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def spread(value: Mapping[str, Any]) -> Mapping[str, Any]:
|
|
109
|
+
return value
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def check_template(template: ThtmlTemplate) -> None:
|
|
113
|
+
_bindings.check_thtml_template(_validate_template(template, "check_template"))
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def format_template(template: ThtmlTemplate) -> str:
|
|
117
|
+
checked = _validate_template(template, "format_template")
|
|
118
|
+
return _bindings.format_thtml_template(checked)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def compile_template(template: ThtmlTemplate) -> CompiledThtmlTemplate:
|
|
122
|
+
checked = _validate_template(template, "compile_template")
|
|
123
|
+
return _bindings.compile_thtml_template(checked)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def thtml(
|
|
127
|
+
template: ThtmlTemplate,
|
|
128
|
+
*,
|
|
129
|
+
globals: Mapping[str, Any] | None = None,
|
|
130
|
+
locals: Mapping[str, Any] | None = None,
|
|
131
|
+
) -> Renderable:
|
|
132
|
+
return _make_thtml_renderable(
|
|
133
|
+
template,
|
|
134
|
+
globals=globals,
|
|
135
|
+
locals=locals,
|
|
136
|
+
frame_depth=3,
|
|
137
|
+
api_name="thtml",
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def render_html(
|
|
142
|
+
template: ThtmlTemplate | Renderable,
|
|
143
|
+
*,
|
|
144
|
+
globals: Mapping[str, Any] | None = None,
|
|
145
|
+
locals: Mapping[str, Any] | None = None,
|
|
146
|
+
) -> str:
|
|
147
|
+
if _is_renderable(template):
|
|
148
|
+
return cast(Renderable, template).render()
|
|
149
|
+
|
|
150
|
+
checked = _validate_template(template, "render_html")
|
|
151
|
+
captured_globals, captured_locals = _capture_scope(
|
|
152
|
+
globals,
|
|
153
|
+
locals,
|
|
154
|
+
frame_depth=2,
|
|
155
|
+
)
|
|
156
|
+
return _bindings.render_thtml_template(
|
|
157
|
+
checked,
|
|
158
|
+
globals=captured_globals,
|
|
159
|
+
locals=captured_locals,
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def html(
|
|
164
|
+
template: ThtmlTemplate | Renderable,
|
|
165
|
+
*,
|
|
166
|
+
globals: Mapping[str, Any] | None = None,
|
|
167
|
+
locals: Mapping[str, Any] | None = None,
|
|
168
|
+
) -> str:
|
|
169
|
+
if _is_renderable(template):
|
|
170
|
+
return cast(Renderable, template).render()
|
|
171
|
+
checked = _validate_template(template, "html")
|
|
172
|
+
captured_globals, captured_locals = _capture_scope(
|
|
173
|
+
globals,
|
|
174
|
+
locals,
|
|
175
|
+
frame_depth=2,
|
|
176
|
+
)
|
|
177
|
+
return _bindings.render_thtml_template(
|
|
178
|
+
checked,
|
|
179
|
+
globals=captured_globals,
|
|
180
|
+
locals=captured_locals,
|
|
181
|
+
)
|
thtml_tstring/py.typed
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: thtml-tstring
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: T-HTML renderer for PEP 750 template strings
|
|
5
|
+
Keywords: html,pep750,t-strings,template-strings,thtml
|
|
6
|
+
Author: Koudai Aono
|
|
7
|
+
Author-email: Koudai Aono <koxudaxi@gmail.com>
|
|
8
|
+
License: MIT
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
15
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
16
|
+
Requires-Dist: tstring-html-bindings>=0.1.0
|
|
17
|
+
Maintainer: Koudai Aono
|
|
18
|
+
Maintainer-email: Koudai Aono <koxudaxi@gmail.com>
|
|
19
|
+
Requires-Python: >=3.14
|
|
20
|
+
Project-URL: Homepage, https://github.com/koxudaxi/tstring-html
|
|
21
|
+
Project-URL: Repository, https://github.com/koxudaxi/tstring-html
|
|
22
|
+
Project-URL: Documentation, https://github.com/koxudaxi/tstring-html/blob/main/thtml-tstring/README.md
|
|
23
|
+
Project-URL: Changelog, https://github.com/koxudaxi/tstring-html/blob/main/CHANGELOG.md
|
|
24
|
+
Project-URL: Issues, https://github.com/koxudaxi/tstring-html/issues
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
|
|
27
|
+
# thtml-tstring
|
|
28
|
+
|
|
29
|
+
Higher-level T-HTML renderer for PEP 750 template strings.
|
|
30
|
+
|
|
31
|
+
```python
|
|
32
|
+
from thtml_tstring import component, thtml
|
|
33
|
+
|
|
34
|
+
@component
|
|
35
|
+
def Button(*, children: str, kind: str = "primary"):
|
|
36
|
+
classes = [kind]
|
|
37
|
+
return t'<button class="{classes}">{children}</button>'
|
|
38
|
+
|
|
39
|
+
label = "Save"
|
|
40
|
+
page = thtml(t"<Button kind='primary'>{label}</Button>")
|
|
41
|
+
assert page.render() == '<button class="primary">Save</button>'
|
|
42
|
+
```
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
thtml_tstring/__init__.py,sha256=E2cjwA0Rku0cDFAtKchEDJzwRAVOpryuz3tz9lUwWiI,728
|
|
2
|
+
thtml_tstring/_bindings.py,sha256=T_kY16PsDTiMjYrpc6YUiq9gzlwAV9zDlx9_CcNVFBc,1092
|
|
3
|
+
thtml_tstring/_runtime.py,sha256=cuLwZXQpzQKob_JcppnvVMM7bgPJFcThBxwi30BA3Oc,5152
|
|
4
|
+
thtml_tstring/py.typed,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
5
|
+
thtml_tstring-0.1.0.dist-info/WHEEL,sha256=GuAqCqoyQuys5_R4zkHUJFlKXw4RpRLNzo31-ui90WQ,81
|
|
6
|
+
thtml_tstring-0.1.0.dist-info/METADATA,sha256=tWifaUE1fDL-NlYvs0SiWbwYkJt4TaKI1fgziqbQ5IM,1603
|
|
7
|
+
thtml_tstring-0.1.0.dist-info/RECORD,,
|