Skip to content

Commit 6d821a4

Browse files
committed
feat: make the component_selector argument optional for the htmy
integration, fixes #81
1 parent 1e5e6b5 commit 6d821a4

File tree

2 files changed

+34
-6
lines changed

2 files changed

+34
-6
lines changed

fasthx/htmy.py

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ class HTMY:
134134

135135
def hx(
136136
self,
137-
component_selector: HTMYComponentSelector[T],
137+
component_selector: HTMYComponentSelector[T] | None = None,
138138
*,
139139
error_component_selector: HTMYComponentSelector[Exception] | None = None,
140140
no_data: bool = False,
@@ -143,12 +143,15 @@ def hx(
143143
Decorator for rendering the route's result if the request was an HTMX one.
144144
145145
Arguments:
146-
component_selector: The component selector to use.
146+
component_selector: An optional component selector to use. If not provided, it is
147+
assumed the route returns a component that should be rendered as is.
147148
error_component_selector: The component selector to use for route error rendering.
148149
no_data: If set, the route will only accept HTMX requests.
149150
"""
150151
return hx(
151-
self._make_render_function(component_selector),
152+
self._make_render_function(
153+
_default_component_selector if component_selector is None else component_selector
154+
),
152155
render_error=None
153156
if error_component_selector is None
154157
else self._make_error_render_function(error_component_selector),
@@ -157,7 +160,7 @@ def hx(
157160

158161
def page(
159162
self,
160-
component_selector: HTMYComponentSelector[T],
163+
component_selector: HTMYComponentSelector[T] | None = None,
161164
*,
162165
error_component_selector: HTMYComponentSelector[Exception] | None = None,
163166
) -> Callable[[MaybeAsyncFunc[P, T]], Callable[P, Coroutine[None, None, T | Response]]]:
@@ -167,11 +170,14 @@ def page(
167170
This decorator triggers HTML rendering regardless of whether the request was HTMX or not.
168171
169172
Arguments:
170-
component_selector: The component selector to use.
173+
component_selector: An optional component selector to use. If not provided, it is
174+
assumed the route returns a component that should be rendered as is.
171175
error_component_selector: The component selector to use for route error rendering.
172176
"""
173177
return page(
174-
self._make_render_function(component_selector),
178+
self._make_render_function(
179+
_default_component_selector if component_selector is None else component_selector
180+
),
175181
render_error=None
176182
if error_component_selector is None
177183
else self._make_error_render_function(error_component_selector),
@@ -255,3 +261,13 @@ def _make_render_context(self, request: Request, route_params: dict[str, Any]) -
255261
result.update(cp(request))
256262

257263
return result
264+
265+
266+
def _default_component_selector(route_result: Any) -> Any:
267+
"""
268+
Default component selector that returns the route result as is.
269+
270+
It is assumed (and not validated) that the route result is a `htmy.Component` when
271+
this component selector is used. Otherwise rendering will fail.
272+
"""
273+
return route_result

tests/test_htmy.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,16 @@ def htmx_or_data_by_id(id: int) -> User:
7676
def header_with_no_default() -> User:
7777
return billy
7878

79+
@app.get("/hx-no-selector", response_model=None)
80+
@htmy.hx() # HelloWorld is a component, render it as is.
81+
def hx_no_selector() -> HelloWorld:
82+
return HelloWorld()
83+
84+
@app.get("/page-no-selector", response_model=None)
85+
@htmy.page() # HelloWorld is a component, render it as is.
86+
def page_no_selector() -> HelloWorld:
87+
return HelloWorld()
88+
7989
@app.get("/error")
8090
@app.get("/error/{kind}")
8191
@htmy.hx( # type: ignore[arg-type]
@@ -184,6 +194,8 @@ def htmy_client(htmy_app: FastAPI) -> TestClient:
184194
{},
185195
),
186196
("/header-with-no-default", {"HX-Request": "true"}, 500, "", {}),
197+
("/hx-no-selector", {"HX-Request": "true"}, 200, "Hello World!", {}),
198+
("/page-no-selector", {"HX-Request": "true"}, 200, "Hello World!", {}),
187199
# htmy.hx(no_data=True) - raises exception for non-HTMX requests.
188200
("/htmx-only", {"HX-Request": "true"}, 200, user_list_html, {}),
189201
("/htmx-only", None, 400, "", {}),

0 commit comments

Comments
 (0)