Skip to content

Commit 66bd301

Browse files
authored
feat: wrap _WithChildrenUnbound into function for better types (#148)
* feat: wrap _WithChildrenUnbound into function for better types * fix: pass mypy checks * chore: rm duplicated docstring and `update_wrapper`call
1 parent 0b3ce2a commit 66bd301

File tree

1 file changed

+21
-27
lines changed

1 file changed

+21
-27
lines changed

src/htpy/_with_children.py

Lines changed: 21 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -17,39 +17,13 @@
1717

1818

1919
class _WithChildrenUnbound(t.Generic[C, P, R]):
20-
"""Decorator to make a component support children nodes.
21-
22-
This decorator is used to create a component that can accept children nodes,
23-
just like native htpy components.
24-
25-
It lets you convert this:
26-
27-
```python
28-
def my_component(*, title: str, children: h.Node) -> h.Renderable:
29-
...
30-
31-
my_component(title="My title", children=h.div["My content"])
32-
```
33-
34-
To this:
35-
36-
```python
37-
@h.with_children
38-
def my_component(children: h.Node, *, title: str) -> h.Renderable:
39-
...
40-
41-
my_component(title="My title")[h.div["My content"]]
42-
```
43-
"""
44-
4520
wrapped: Callable[t.Concatenate[C | None, P], R]
4621

4722
def __init__(self, func: Callable[t.Concatenate[C | None, P], R]) -> None:
4823
# This instance is created at import time when decorating the component.
4924
# It means that this object is global, and shared between all renderings
5025
# of the same component.
5126
self.wrapped = func
52-
functools.update_wrapper(self, func)
5327

5428
def __repr__(self) -> str:
5529
return f"with_children({self.wrapped.__name__}, <unbound>)"
@@ -139,4 +113,24 @@ def iter_chunks(
139113
return self._func(None, *self._args, **self._kwargs).iter_chunks(context)
140114

141115

142-
with_children = _WithChildrenUnbound
116+
def with_children(
117+
func: Callable[t.Concatenate[C | None, P], R],
118+
) -> _WithChildrenUnbound[C | None, P, R]:
119+
"""Decorator to make a component support children nodes.
120+
121+
This decorator allows you to create components that can accept children nodes
122+
using the bracket notation, similar to native htpy components.
123+
124+
Example:
125+
@with_children
126+
def my_component(children: Node, *, title: str) -> Renderable:
127+
return div(class_="container")[h1[title], children]
128+
129+
# Usage:
130+
my_component(title="Hello")[span["World"]]
131+
"""
132+
wrapper = _WithChildrenUnbound(func)
133+
# Ensure the wrapper has the same signature as the original function
134+
# This is crucial for LSP to recognize the function arguments
135+
functools.update_wrapper(wrapper, func)
136+
return wrapper

0 commit comments

Comments
 (0)