htmy 0.6.0__py3-none-any.whl → 0.7.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.
htmy/function_component.py
CHANGED
|
@@ -4,25 +4,22 @@ import asyncio
|
|
|
4
4
|
from collections.abc import Callable, Coroutine
|
|
5
5
|
from typing import Any, Protocol, TypeAlias, overload
|
|
6
6
|
|
|
7
|
-
from .typing import AsyncComponent, Component, Context, SyncComponent
|
|
7
|
+
from .typing import AsyncComponent, Component, Context, SyncComponent
|
|
8
|
+
from .typing import T as TProps
|
|
9
|
+
from .typing import U as TSelf
|
|
8
10
|
|
|
9
|
-
# -- Typing for "full" function components.
|
|
11
|
+
# -- Typing for "full" function components and context only method components.
|
|
10
12
|
|
|
11
|
-
_SyncFunctionComponent: TypeAlias = Callable[[
|
|
13
|
+
_SyncFunctionComponent: TypeAlias = Callable[[TProps, Context], Component]
|
|
12
14
|
"""
|
|
13
15
|
Protocol definition for sync function components that have both a properties and a context argument.
|
|
14
16
|
"""
|
|
15
17
|
|
|
16
|
-
_AsyncFunctionComponent: TypeAlias = Callable[[
|
|
18
|
+
_AsyncFunctionComponent: TypeAlias = Callable[[TProps, Context], Coroutine[Any, Any, Component]]
|
|
17
19
|
"""
|
|
18
20
|
Protocol definition for async function components that have both a properties and a context argument.
|
|
19
21
|
"""
|
|
20
22
|
|
|
21
|
-
_FunctionComponent: TypeAlias = _SyncFunctionComponent[T] | _AsyncFunctionComponent[T]
|
|
22
|
-
"""
|
|
23
|
-
Function component type that has both a properties and a context argument.
|
|
24
|
-
"""
|
|
25
|
-
|
|
26
23
|
# -- Typing for context-only function components.
|
|
27
24
|
|
|
28
25
|
_ContextOnlySyncFunctionComponent: TypeAlias = Callable[[Context], Component]
|
|
@@ -55,22 +52,22 @@ class _DecoratedContextOnlyAsyncFunctionComponent(SyncComponent, Protocol):
|
|
|
55
52
|
def __call__(self) -> SyncComponent: ...
|
|
56
53
|
|
|
57
54
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
55
|
+
# -- Typing for "full" method components.
|
|
56
|
+
|
|
57
|
+
_SyncMethodComponent: TypeAlias = Callable[[TSelf, TProps, Context], Component]
|
|
61
58
|
"""
|
|
62
|
-
|
|
59
|
+
Protocol definition for sync method components that have both a properties and a context argument.
|
|
63
60
|
"""
|
|
64
61
|
|
|
65
|
-
|
|
66
|
-
_DecoratedContextOnlySyncFunctionComponent | _DecoratedContextOnlyAsyncFunctionComponent
|
|
67
|
-
)
|
|
62
|
+
_AsyncMethodComponent: TypeAlias = Callable[[TSelf, TProps, Context], Coroutine[Any, Any, Component]]
|
|
68
63
|
"""
|
|
69
|
-
Protocol definition for
|
|
70
|
-
or async component when called.
|
|
64
|
+
Protocol definition for async method components that have both a properties and a context argument.
|
|
71
65
|
"""
|
|
72
66
|
|
|
73
67
|
|
|
68
|
+
# -- Component decorators.
|
|
69
|
+
|
|
70
|
+
|
|
74
71
|
class ComponentDecorators:
|
|
75
72
|
"""
|
|
76
73
|
Function component decorators.
|
|
@@ -78,18 +75,18 @@ class ComponentDecorators:
|
|
|
78
75
|
|
|
79
76
|
__slots__ = ()
|
|
80
77
|
|
|
81
|
-
# --
|
|
78
|
+
# -- Function component decorator.
|
|
82
79
|
|
|
83
80
|
@overload
|
|
84
|
-
def __call__(self, func: _SyncFunctionComponent[
|
|
81
|
+
def __call__(self, func: _SyncFunctionComponent[TProps]) -> Callable[[TProps], SyncComponent]: ...
|
|
85
82
|
|
|
86
83
|
@overload
|
|
87
|
-
def __call__(self, func: _AsyncFunctionComponent[
|
|
84
|
+
def __call__(self, func: _AsyncFunctionComponent[TProps]) -> Callable[[TProps], AsyncComponent]: ...
|
|
88
85
|
|
|
89
86
|
def __call__(
|
|
90
87
|
self,
|
|
91
|
-
func:
|
|
92
|
-
) -> Callable[[
|
|
88
|
+
func: _SyncFunctionComponent[TProps] | _AsyncFunctionComponent[TProps],
|
|
89
|
+
) -> Callable[[TProps], SyncComponent] | Callable[[TProps], AsyncComponent]:
|
|
93
90
|
"""
|
|
94
91
|
Decorator that converts the decorated function into one that must be called with
|
|
95
92
|
the function component's properties and returns a component instance.
|
|
@@ -104,7 +101,7 @@ class ComponentDecorators:
|
|
|
104
101
|
def my_component(props: int, context: Context) -> Component:
|
|
105
102
|
return html.p(f"Value: {props}")
|
|
106
103
|
|
|
107
|
-
async def render():
|
|
104
|
+
async def render() -> str:
|
|
108
105
|
return await Renderer().render(
|
|
109
106
|
my_component(42)
|
|
110
107
|
)
|
|
@@ -121,7 +118,7 @@ class ComponentDecorators:
|
|
|
121
118
|
|
|
122
119
|
if asyncio.iscoroutinefunction(func):
|
|
123
120
|
|
|
124
|
-
def async_wrapper(props:
|
|
121
|
+
def async_wrapper(props: TProps) -> AsyncComponent:
|
|
125
122
|
# This function must be async, in case the renderer inspects it to decide how to handle it.
|
|
126
123
|
async def component(context: Context) -> Component:
|
|
127
124
|
return await func(props, context) # type: ignore[no-any-return]
|
|
@@ -132,7 +129,7 @@ class ComponentDecorators:
|
|
|
132
129
|
return async_wrapper
|
|
133
130
|
else:
|
|
134
131
|
|
|
135
|
-
def sync_wrapper(props:
|
|
132
|
+
def sync_wrapper(props: TProps) -> SyncComponent:
|
|
136
133
|
def component(context: Context) -> Component:
|
|
137
134
|
return func(props, context) # type: ignore[return-value]
|
|
138
135
|
|
|
@@ -142,15 +139,15 @@ class ComponentDecorators:
|
|
|
142
139
|
return sync_wrapper
|
|
143
140
|
|
|
144
141
|
@overload
|
|
145
|
-
def function(self, func: _SyncFunctionComponent[
|
|
142
|
+
def function(self, func: _SyncFunctionComponent[TProps]) -> Callable[[TProps], SyncComponent]: ...
|
|
146
143
|
|
|
147
144
|
@overload
|
|
148
|
-
def function(self, func: _AsyncFunctionComponent[
|
|
145
|
+
def function(self, func: _AsyncFunctionComponent[TProps]) -> Callable[[TProps], AsyncComponent]: ...
|
|
149
146
|
|
|
150
147
|
def function(
|
|
151
148
|
self,
|
|
152
|
-
func:
|
|
153
|
-
) -> Callable[[
|
|
149
|
+
func: _SyncFunctionComponent[TProps] | _AsyncFunctionComponent[TProps],
|
|
150
|
+
) -> Callable[[TProps], SyncComponent] | Callable[[TProps], AsyncComponent]:
|
|
154
151
|
"""
|
|
155
152
|
Decorator that converts the decorated function into one that must be called with
|
|
156
153
|
the function component's properties and returns a component instance.
|
|
@@ -167,7 +164,7 @@ class ComponentDecorators:
|
|
|
167
164
|
def my_component(props: int, context: Context) -> Component:
|
|
168
165
|
return html.p(f"Value: {props}")
|
|
169
166
|
|
|
170
|
-
async def render():
|
|
167
|
+
async def render() -> str:
|
|
171
168
|
return await Renderer().render(
|
|
172
169
|
my_component(42)
|
|
173
170
|
)
|
|
@@ -182,7 +179,7 @@ class ComponentDecorators:
|
|
|
182
179
|
"""
|
|
183
180
|
return self(func)
|
|
184
181
|
|
|
185
|
-
# --
|
|
182
|
+
# -- Context-only function component decorator.
|
|
186
183
|
|
|
187
184
|
@overload
|
|
188
185
|
def context_only(
|
|
@@ -196,7 +193,7 @@ class ComponentDecorators:
|
|
|
196
193
|
|
|
197
194
|
def context_only(
|
|
198
195
|
self,
|
|
199
|
-
func:
|
|
196
|
+
func: _ContextOnlySyncFunctionComponent | _ContextOnlyAsyncFunctionComponent,
|
|
200
197
|
) -> _DecoratedContextOnlySyncFunctionComponent | _DecoratedContextOnlyAsyncFunctionComponent:
|
|
201
198
|
"""
|
|
202
199
|
Decorator that converts the decorated function into a component.
|
|
@@ -204,19 +201,16 @@ class ComponentDecorators:
|
|
|
204
201
|
If used on an async function, the resulting component will also be async;
|
|
205
202
|
otherwise it will be sync.
|
|
206
203
|
|
|
207
|
-
|
|
208
|
-
component object, so it can be used in the component tree both with and without the
|
|
209
|
-
call signature:
|
|
204
|
+
Example:
|
|
210
205
|
|
|
211
206
|
```python
|
|
212
207
|
@component.context_only
|
|
213
208
|
def my_component(ctx):
|
|
214
209
|
return "Context only function component."
|
|
215
210
|
|
|
216
|
-
async def render():
|
|
211
|
+
async def render() -> str:
|
|
217
212
|
return await Renderer().render(
|
|
218
|
-
my_component()
|
|
219
|
-
my_component, # Without call signature.
|
|
213
|
+
my_component()
|
|
220
214
|
)
|
|
221
215
|
```
|
|
222
216
|
|
|
@@ -231,9 +225,139 @@ class ComponentDecorators:
|
|
|
231
225
|
func.htmy = func # type: ignore[union-attr]
|
|
232
226
|
return func # type: ignore[return-value]
|
|
233
227
|
|
|
228
|
+
# This assignment adds support for context-only function components without call signature.
|
|
234
229
|
wrapper.htmy = func # type: ignore[attr-defined]
|
|
235
230
|
return wrapper # type: ignore[return-value]
|
|
236
231
|
|
|
232
|
+
# -- Method component decorator.
|
|
233
|
+
|
|
234
|
+
@overload
|
|
235
|
+
def method(
|
|
236
|
+
self, func: _SyncMethodComponent[TSelf, TProps]
|
|
237
|
+
) -> Callable[[TSelf, TProps], SyncComponent]: ...
|
|
238
|
+
|
|
239
|
+
@overload
|
|
240
|
+
def method(
|
|
241
|
+
self, func: _AsyncMethodComponent[TSelf, TProps]
|
|
242
|
+
) -> Callable[[TSelf, TProps], AsyncComponent]: ...
|
|
243
|
+
|
|
244
|
+
def method(
|
|
245
|
+
self,
|
|
246
|
+
func: _SyncMethodComponent[TSelf, TProps] | _AsyncMethodComponent[TSelf, TProps],
|
|
247
|
+
) -> Callable[[TSelf, TProps], SyncComponent] | Callable[[TSelf, TProps], AsyncComponent]:
|
|
248
|
+
"""
|
|
249
|
+
Decorator that converts the decorated method into one that must be called with
|
|
250
|
+
the method component's properties and returns a component instance.
|
|
251
|
+
|
|
252
|
+
If used on an async method, the resulting component will also be async;
|
|
253
|
+
otherwise it will be sync.
|
|
254
|
+
|
|
255
|
+
Example:
|
|
256
|
+
|
|
257
|
+
```python
|
|
258
|
+
@dataclass
|
|
259
|
+
class MyBusinessObject:
|
|
260
|
+
message: str
|
|
261
|
+
|
|
262
|
+
@component.method
|
|
263
|
+
def paragraph(self, props: int, context: Context) -> Component:
|
|
264
|
+
return html.p(f"{self.message} {props}")
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
async def render() -> str:
|
|
268
|
+
return await Renderer().render(
|
|
269
|
+
MyBusinessObject("Hi!").paragraph(42)
|
|
270
|
+
)
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
Arguments:
|
|
274
|
+
func: The decorated method.
|
|
275
|
+
|
|
276
|
+
Returns:
|
|
277
|
+
A method that must be called with the method component's properties and
|
|
278
|
+
returns a component instance. (Or loosly speaking, an `HTMYComponentType` which
|
|
279
|
+
can be "instantiated" with the method component's properties.)
|
|
280
|
+
"""
|
|
281
|
+
if asyncio.iscoroutinefunction(func):
|
|
282
|
+
|
|
283
|
+
def async_wrapper(self: TSelf, props: TProps) -> AsyncComponent:
|
|
284
|
+
# This function must be async, in case the renderer inspects it to decide how to handle it.
|
|
285
|
+
async def component(context: Context) -> Component:
|
|
286
|
+
return await func(self, props, context) # type: ignore[no-any-return]
|
|
287
|
+
|
|
288
|
+
component.htmy = component # type: ignore[attr-defined]
|
|
289
|
+
return component # type: ignore[return-value]
|
|
290
|
+
|
|
291
|
+
return async_wrapper
|
|
292
|
+
else:
|
|
293
|
+
|
|
294
|
+
def sync_wrapper(self: TSelf, props: TProps) -> SyncComponent:
|
|
295
|
+
def component(context: Context) -> Component:
|
|
296
|
+
return func(self, props, context) # type: ignore[return-value]
|
|
297
|
+
|
|
298
|
+
component.htmy = component # type: ignore[attr-defined]
|
|
299
|
+
return component # type: ignore[return-value]
|
|
300
|
+
|
|
301
|
+
return sync_wrapper
|
|
302
|
+
|
|
303
|
+
# -- Context-only function component decorator.
|
|
304
|
+
|
|
305
|
+
@overload
|
|
306
|
+
def context_only_method(
|
|
307
|
+
self, func: _SyncFunctionComponent[TSelf]
|
|
308
|
+
) -> Callable[[TSelf], SyncComponent]: ...
|
|
309
|
+
|
|
310
|
+
@overload
|
|
311
|
+
def context_only_method(
|
|
312
|
+
self, func: _AsyncFunctionComponent[TSelf]
|
|
313
|
+
) -> Callable[[TSelf], AsyncComponent]: ...
|
|
314
|
+
|
|
315
|
+
def context_only_method(
|
|
316
|
+
self,
|
|
317
|
+
func: _SyncFunctionComponent[TSelf] | _AsyncFunctionComponent[TSelf],
|
|
318
|
+
) -> Callable[[TSelf], SyncComponent] | Callable[[TSelf], AsyncComponent]:
|
|
319
|
+
"""
|
|
320
|
+
Decorator that converts the decorated method into one that must be called
|
|
321
|
+
without any arguments and returns a component instance.
|
|
322
|
+
|
|
323
|
+
If used on an async method, the resulting component will also be async;
|
|
324
|
+
otherwise it will be sync.
|
|
325
|
+
|
|
326
|
+
Example:
|
|
327
|
+
|
|
328
|
+
```python
|
|
329
|
+
@dataclass
|
|
330
|
+
class MyBusinessObject:
|
|
331
|
+
message: str
|
|
332
|
+
|
|
333
|
+
@component.context_only_method
|
|
334
|
+
def paragraph(self, context: Context) -> Component:
|
|
335
|
+
return html.p(f"{self.message} Goodbye!")
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
async def render() -> str:
|
|
339
|
+
return await Renderer().render(
|
|
340
|
+
MyBusinessObject("Hello!").paragraph()
|
|
341
|
+
)
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
Arguments:
|
|
345
|
+
func: The decorated method.
|
|
346
|
+
|
|
347
|
+
Returns:
|
|
348
|
+
A method that must be called without any arguments and returns a component instance.
|
|
349
|
+
(Or loosly speaking, an `HTMYComponentType` which can be "instantiated" by calling
|
|
350
|
+
the method.)
|
|
351
|
+
"""
|
|
352
|
+
# A context only method component must be implemented in the same way as
|
|
353
|
+
# a function component. The self argument replaces the props argument
|
|
354
|
+
# and it is added automatically by Python when the method is called.
|
|
355
|
+
# Even the type hint must be the same.
|
|
356
|
+
# This implementation doesn't make the function itself a component though,
|
|
357
|
+
# so the call signature is always necessary (unlike for context-only function
|
|
358
|
+
# components).
|
|
359
|
+
return self(func)
|
|
360
|
+
|
|
237
361
|
|
|
238
362
|
component = ComponentDecorators()
|
|
239
363
|
"""
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
htmy/__init__.py,sha256=Us5P9Y6ZSp38poIz88bsAh2Hxuze5jE3V_uMtMyuH-E,1880
|
|
2
2
|
htmy/core.py,sha256=OoL11j2V-CfePC0dbkC2A5GbdK942b5Huszw3rLo7fc,15124
|
|
3
3
|
htmy/etree.py,sha256=yKxom__AdsJY-Q1kbU0sdTMr0ZF5dMSVBKxayntNFyQ,3062
|
|
4
|
-
htmy/function_component.py,sha256=
|
|
4
|
+
htmy/function_component.py,sha256=iSp5cGrErmIsc-VfNq053_J2m-Nuu_k2xK9UxvEnlw8,12431
|
|
5
5
|
htmy/html.py,sha256=7UohfPRtl-3IoSbOiDxazsSHQpCZ0tyRdNayQISPM8A,21086
|
|
6
6
|
htmy/i18n.py,sha256=brNazQjObBFfbnViZCpcnxa0qgxQbJfX7xJAH-MqTW8,5124
|
|
7
7
|
htmy/io.py,sha256=iebJOZp7L0kZ9SWdqMatKtW5VGRIkEd-eD0_vTAldH8,41
|
|
@@ -15,7 +15,7 @@ htmy/renderer/default.py,sha256=lVMGuRybpFZ0u7pMB3IGOsFxw_rY8KqFQzWcNlmKCVI,1078
|
|
|
15
15
|
htmy/snippet.py,sha256=dkHEOuULGsgawIMnSz99hghvNu8pLVGAQMQSlrn9ibY,10260
|
|
16
16
|
htmy/typing.py,sha256=0spTpz_JWql2yy_lSlRx0uqgXar7fxwyBqWeIzltvKU,3111
|
|
17
17
|
htmy/utils.py,sha256=Kp0j9G8CBeRiyFGmz-CoDiLtXHfpvHzlTVsWeDhIebM,1935
|
|
18
|
-
htmy-0.
|
|
19
|
-
htmy-0.
|
|
20
|
-
htmy-0.
|
|
21
|
-
htmy-0.
|
|
18
|
+
htmy-0.7.0.dist-info/LICENSE,sha256=rFtoGU_3c_rlacXgOZapTHfMErN-JFPT5Bq_col4bqI,1067
|
|
19
|
+
htmy-0.7.0.dist-info/METADATA,sha256=5fzJ6L_K2WKV8-G-wa5a34IquAwdO5_v-DOWErOPRHg,18306
|
|
20
|
+
htmy-0.7.0.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
|
|
21
|
+
htmy-0.7.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|