Skip to content

Commit 2fcc0aa

Browse files
authored
Merge pull request #40 from volfpeter/jinja-error-rendering-fix
Jinja error rendering fix
2 parents 1480f05 + 4051c3d commit 2fcc0aa

File tree

4 files changed

+33
-9
lines changed

4 files changed

+33
-9
lines changed

fasthx/jinja.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,9 @@ def hx(
311311
self._make_render_function(template, make_context=make_context, prefix=prefix),
312312
render_error=None
313313
if error_template is None
314-
else self._make_render_function(error_template, make_context=make_context, prefix=prefix),
314+
else self._make_render_function(
315+
error_template, make_context=make_context, prefix=prefix, error_renderer=True
316+
),
315317
no_data=self.no_data or no_data,
316318
)
317319

@@ -341,7 +343,9 @@ def page(
341343
self._make_render_function(template, make_context=make_context, prefix=prefix),
342344
render_error=None
343345
if error_template is None
344-
else self._make_render_function(error_template, make_context=make_context, prefix=prefix),
346+
else self._make_render_function(
347+
error_template, make_context=make_context, prefix=prefix, error_renderer=True
348+
),
345349
)
346350

347351
def _make_render_function(
@@ -350,6 +354,7 @@ def _make_render_function(
350354
*,
351355
make_context: JinjaContextFactory,
352356
prefix: str | None,
357+
error_renderer: bool = False,
353358
) -> HTMLRenderer[Any]:
354359
"""
355360
Creates an `HTMLRenderer` with the given configuration.
@@ -358,10 +363,16 @@ def _make_render_function(
358363
template: The template the renderer function should use.
359364
make_context: The Jinja rendering context factory to use.
360365
prefix: Optional template name prefix.
366+
error_renderer: Whether this is an error renderer creation.
361367
"""
362368

363369
def render(result: Any, *, context: dict[str, Any], request: Request) -> str | Response:
364-
template_name = self._resolve_template_name(template, prefix=prefix, request=request)
370+
template_name = self._resolve_template_name(
371+
template,
372+
error=result if error_renderer else None,
373+
prefix=prefix,
374+
request=request,
375+
)
365376
return self._make_response(
366377
template_name,
367378
jinja_context=make_context(route_result=result, route_context=context),
@@ -413,6 +424,7 @@ def _resolve_template_name(
413424
414425
Arguments:
415426
template: The template selector.
427+
error: The error raised by the route.
416428
prefix: Optional template name prefix.
417429
request: The current request.
418430

fasthx/typing.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,5 +105,5 @@ def get_component(self, request: Request, error: Exception | None) -> str:
105105
...
106106

107107

108-
ComponentSelector: TypeAlias = str | RequestComponentSelector[T]
108+
ComponentSelector: TypeAlias = T | RequestComponentSelector[T]
109109
"""Type alias for known component selectors."""

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "fasthx"
3-
version = "2.0.1"
3+
version = "2.0.2"
44
description = "FastAPI data APIs with HTMX support."
55
authors = ["Peter Volf <[email protected]>"]
66
readme = "README.md"

tests/test_jinja.py

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ def __init__(self, data: dict[str, Any], *, response: Response) -> None:
3535

3636

3737
@pytest.fixture
38-
def jinja_app() -> FastAPI:
38+
def jinja_app() -> FastAPI: # noqa: C901
3939
app = FastAPI()
4040

4141
jinja = Jinja(Jinja2Templates("tests/templates"))
@@ -88,6 +88,7 @@ def header_with_no_default() -> User:
8888
return billy
8989

9090
@app.get("/error")
91+
@app.get("/error/{kind}")
9192
@jinja.hx(
9293
TemplateHeader("X-Component", {}), # No rendering if there's no exception.
9394
error_template=TemplateHeader(
@@ -98,20 +99,29 @@ def header_with_no_default() -> User:
9899
),
99100
no_data=True,
100101
)
101-
def error(response: Response) -> None:
102+
def error(response: Response, kind: str | None = None) -> None:
103+
if kind:
104+
# Unhandled error type to see if we get HTTP 500
105+
raise ValueError(kind)
106+
102107
raise RenderedError({"a": 1, "b": 2}, response=response)
103108

104109
@app.get("/error-page")
110+
@app.get("/error-page/{kind}")
105111
@jinja.page(
106112
TemplateHeader("X-Component", {}), # No rendering if there's no exception.
107113
error_template=TemplateHeader(
108114
"X-Error-Component",
109115
{},
110116
default="hello-world.jinja",
111-
error=(RenderedError, TypeError, ValueError), # Test error tuple
117+
error=(RenderedError, TypeError, SyntaxError), # Test error tuple
112118
),
113119
)
114-
def error_page(response: Response) -> None:
120+
def error_page(response: Response, kind: str | None = None) -> None:
121+
if kind:
122+
# Unhandled error type to see if we get HTTP 500
123+
raise ValueError(kind)
124+
115125
raise RenderedError({"a": 1, "b": 2}, response=response)
116126

117127
@app.get("/global-no-data")
@@ -194,8 +204,10 @@ def jinja_client(jinja_app: FastAPI) -> TestClient:
194204
("/htmx-only", {"HX-Request": "false"}, 400, "", {}),
195205
# hx() error rendering
196206
("/error", {"HX-Request": "true"}, 456, "Hello World!", {}),
207+
("/error/value-error", {"HX-Request": "true"}, 500, "", {}),
197208
# page() error rendering
198209
("/error-page", None, 456, "Hello World!", {}),
210+
("/error-page/value-error", None, 500, "None", {}),
199211
# Globally disabled data responses
200212
("/global-no-data", None, 400, "", {}),
201213
),

0 commit comments

Comments
 (0)