Skip to content

Commit 2e64a57

Browse files
Merge pull request #4 from feldroy/use-starlette-pattern
Follow starlette guide for middleware
2 parents ad9cdb5 + be83fa3 commit 2e64a57

4 files changed

Lines changed: 6 additions & 61 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ static = HashedStatic("static")
3232
app.mount("/static", static)
3333

3434
# Wrap any ASGI app to rewrite static paths in HTML responses
35-
app = StaticRewriteMiddleware(app, static=static)
35+
app.add_middleware(StaticRewriteMiddleware, static=static)
3636

3737
# In templates, resolve cache-busted URLs:
3838
static.url("styles.css") # /static/styles.a1b2c3d4.css

docs/usage.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ static = HashedStatic("static")
1212
# Mount it however your framework mounts sub-apps:
1313
app.mount("/static", static)
1414

15-
# Wrap the app to rewrite static paths in HTML responses:
16-
app = StaticRewriteMiddleware(app, static=static)
15+
# If you're using Starlette / FastAPI / Air, add the middleware to your app like this:
16+
app.add_middleware(StaticRewriteMiddleware, static=static)
1717
```
1818

1919
`HashedStatic` hashes every file in the directory at startup. When a browser requests the hashed filename, it gets an immutable cache header. When it requests the original filename, the file is served without aggressive caching.

src/staticware/middleware.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
static = HashedStatic("static")
99
1010
# Wrap any ASGI app to rewrite /static/styles.css -> /static/styles.a1b2c3d4.css
11-
app = StaticRewriteMiddleware(your_app, static=static)
11+
app.add_middleware(StaticRewriteMiddleware, static=static)
1212
1313
# In templates:
1414
static.url("styles.css") # -> /static/styles.a1b2c3d4.css
@@ -184,7 +184,7 @@ class StaticRewriteMiddleware:
184184
HTML — no template function needed (though ``static.url()`` is there
185185
if you want it).
186186
187-
app = StaticRewriteMiddleware(app, static=static)
187+
app.add_middleware(StaticRewriteMiddleware, static=static)
188188
"""
189189

190190
def __init__(self, app: ASGIApp, *, static: HashedStatic) -> None:
@@ -251,7 +251,7 @@ async def send_wrapper(message: dict[str, Any]) -> None:
251251
await send({"type": "http.response.body", "body": full_body})
252252
return
253253

254-
return await self.app(scope, receive, send_wrapper)
254+
await self.app(scope, receive, send_wrapper)
255255

256256

257257
# ── Raw ASGI helpers ────────────────────────────────────────────────────

tests/test_staticware.py

Lines changed: 0 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -526,58 +526,3 @@ async def test_hashed_url_no_etag(static: HashedStatic) -> None:
526526
await static(make_scope(f"/static/{hashed_name}"), receive, resp)
527527
assert resp.status == 200
528528
assert b"etag" not in resp.headers, "Hashed URL should not include an etag header"
529-
530-
531-
# ── StaticRewriteMiddleware: return value propagation ──────────────
532-
533-
534-
async def test_rewrite_middleware_returns_inner_app_result(
535-
static: HashedStatic,
536-
) -> None:
537-
"""Middleware should propagate the inner app's return value on the HTTP path.
538-
539-
ASGI apps normally return None, but the spec does not forbid return values.
540-
Frameworks like Starlette rely on ``return await self.app(...)`` so that
541-
return values propagate through the middleware chain. A bare ``await``
542-
without ``return`` silently discards the result.
543-
"""
544-
sentinel = "app_result"
545-
546-
async def inner_app(scope: dict, receive: Any, send: Any) -> str:
547-
body = b"<html>hello</html>"
548-
await send(
549-
{
550-
"type": "http.response.start",
551-
"status": 200,
552-
"headers": [
553-
(b"content-type", b"text/html; charset=utf-8"),
554-
(b"content-length", str(len(body)).encode("latin-1")),
555-
],
556-
}
557-
)
558-
await send({"type": "http.response.body", "body": body})
559-
return sentinel
560-
561-
app = StaticRewriteMiddleware(inner_app, static=static)
562-
resp = ResponseCollector()
563-
result = await app(make_scope("/"), receive, resp)
564-
assert result == sentinel
565-
566-
567-
async def test_rewrite_middleware_returns_inner_app_result_non_http(
568-
static: HashedStatic,
569-
) -> None:
570-
"""Middleware should propagate the inner app's return value for non-HTTP scopes.
571-
572-
When the scope type is not "http", the middleware forwards directly to the
573-
inner app. It must ``return await self.app(...)`` so the return value is
574-
not silently discarded.
575-
"""
576-
sentinel = "ws_result"
577-
578-
async def inner_app(scope: dict, receive: Any, send: Any) -> str:
579-
return sentinel
580-
581-
app = StaticRewriteMiddleware(inner_app, static=static)
582-
result = await app({"type": "websocket", "path": "/"}, receive, ResponseCollector())
583-
assert result == sentinel

0 commit comments

Comments
 (0)