Skip to content

Commit

Permalink
Starlette support.
Browse files Browse the repository at this point in the history
  • Loading branch information
pelme committed Aug 26, 2024
1 parent 7417727 commit 4c1d1cd
Show file tree
Hide file tree
Showing 7 changed files with 80 additions and 0 deletions.
3 changes: 3 additions & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# Changelog

## next
- Support passing htpy elements directly to Starlette responses. Document Starlette support. [PR #50](https://github.com/pelme/htpy/pull/50).

## 24.8.2 - 2024-08-23
- Added support for passing data between components via Context. See the [Usage
docs](usage.md#passing-data-with-context) for more information. [PR #48](https://github.com/pelme/htpy/pull/48).
Expand Down
21 changes: 21 additions & 0 deletions docs/starlette.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Usage with Starlette

htpy can be used with Starlette to generate HTML. Since FastAPI is built upon Starlette, htpy can also be used with FastAPI.

To return HTML contents, pass a htpy element to Starlette's `HTMLResponse`:

```py
from starlette.applications import Starlette
from starlette.requests import Request
from starlette.responses import HTMLResponse
from starlette.routing import Route

from htpy import h1


async def index(request: Request) -> HTMLResponse:
return HTMLResponse(h1["Hi Starlette!"])


app = Starlette(routes=[Route("/", index)])
```
15 changes: 15 additions & 0 deletions examples/starlette_htmlresponse.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from starlette.applications import Starlette
from starlette.requests import Request
from starlette.responses import HTMLResponse
from starlette.routing import Route

from htpy import h1


async def index(request: Request) -> HTMLResponse:
return HTMLResponse(h1["Hi Starlette!"])


app = Starlette(
routes=[Route("/", index)],
)
6 changes: 6 additions & 0 deletions htpy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,12 @@ def _iter_context(self, ctx: dict[Context[t.Any], t.Any]) -> Iterator[str]:
def __repr__(self) -> str:
return f"<{self.__class__.__name__} '{self}'>"

# Allow starlette Response.render to directly render this element without
# explicitly casting to str:
# https://github.com/encode/starlette/blob/5ed55c441126687106109a3f5e051176f88cd3e6/starlette/responses.py#L44-L49
def encode(self, encoding: str = "utf-8", errors: str = "strict") -> bytes:
return str(self).encode(encoding, errors)

# Avoid having Django "call" a htpy element that is injected into a
# template. Setting do_not_call_in_templates will prevent Django from doing
# an extra call:
Expand Down
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ nav:
- common-patterns.md
- static-typing.md
- django.md
- starlette.md
- streaming.md
- html2htpy.md
- faq.md
Expand Down
2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ optional-dependencies.dev = [
"django",
"django-stubs",
"jinja2",
"starlette",
"httpx",
]
optional-dependencies.docs = [
"mkdocs-material==9.5.12",
Expand Down
32 changes: 32 additions & 0 deletions tests/test_starlette.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
from __future__ import annotations

import typing as t

from starlette.applications import Starlette
from starlette.responses import HTMLResponse
from starlette.routing import Route
from starlette.testclient import TestClient

from htpy import h1

if t.TYPE_CHECKING:
from starlette.requests import Request


async def html_response(request: Request) -> HTMLResponse:
return HTMLResponse(h1["Hello, HTMLResponse!"])


client = TestClient(
Starlette(
debug=True,
routes=[
Route("/html-response", html_response),
],
)
)


def test_html_response() -> None:
response = client.get("/html-response")
assert response.content == b"<h1>Hello, HTMLResponse!</h1>"

0 comments on commit 4c1d1cd

Please sign in to comment.