web: fix TemplateResponse aufrufe für neue starlette/fastapi-API

Starlette ab 0.27 verlangt request als erstes Positionalargument bei
TemplateResponse, das alte Schema (request im context-dict) bricht
hart mit 'TypeError: unhashable type: dict' weil der context-dict an
der name-Position landet und Jinja ihn als Cache-Key hashen will.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Stefan Hacker 2026-04-26 12:17:14 +02:00
parent fb3534553b
commit 7c8c256ffa
1 changed files with 7 additions and 13 deletions

View File

@ -45,8 +45,7 @@ async def index(request: Request):
devices = usb.scan() devices = usb.scan()
with fwdb.open_db(DB_PATH) as conn: with fwdb.open_db(DB_PATH) as conn:
fw_count = conn.execute("SELECT COUNT(*) FROM firmware").fetchone()[0] fw_count = conn.execute("SELECT COUNT(*) FROM firmware").fetchone()[0]
return templates.TemplateResponse("index.html", { return templates.TemplateResponse(request, "index.html", {
"request": request,
"devices": devices, "devices": devices,
"fw_count": fw_count, "fw_count": fw_count,
"firmware_root": FIRMWARE_ROOT, "firmware_root": FIRMWARE_ROOT,
@ -58,13 +57,12 @@ async def index(request: Request):
@app.get("/devices", response_class=HTMLResponse) @app.get("/devices", response_class=HTMLResponse)
async def devices_page(request: Request): async def devices_page(request: Request):
return templates.TemplateResponse("devices.html", {"request": request}) return templates.TemplateResponse(request, "devices.html", {})
@app.get("/api/devices/html", response_class=HTMLResponse) @app.get("/api/devices/html", response_class=HTMLResponse)
async def devices_partial(request: Request): async def devices_partial(request: Request):
return templates.TemplateResponse("_devices.html", { return templates.TemplateResponse(request, "_devices.html", {
"request": request,
"devices": usb.scan(), "devices": usb.scan(),
}) })
@ -75,8 +73,7 @@ async def devices_partial(request: Request):
async def firmware_page(request: Request): async def firmware_page(request: Request):
with fwdb.open_db(DB_PATH) as conn: with fwdb.open_db(DB_PATH) as conn:
rows = fwdb.list_all(conn) rows = fwdb.list_all(conn)
return templates.TemplateResponse("firmware.html", { return templates.TemplateResponse(request, "firmware.html", {
"request": request,
"firmware": rows, "firmware": rows,
"firmware_root": FIRMWARE_ROOT, "firmware_root": FIRMWARE_ROOT,
}) })
@ -124,8 +121,7 @@ async def firmware_detail(request: Request, fw_id: int):
row = fwdb.get_by_id(conn, fw_id) row = fwdb.get_by_id(conn, fw_id)
if row is None: if row is None:
raise HTTPException(404) raise HTTPException(404)
return templates.TemplateResponse("firmware_detail.html", { return templates.TemplateResponse(request, "firmware_detail.html", {
"request": request,
"fw": row, "fw": row,
"firmware_root": FIRMWARE_ROOT, "firmware_root": FIRMWARE_ROOT,
}) })
@ -139,8 +135,7 @@ async def browse(request: Request, path: str = ""):
target, entries = filebrowse.list_dir(FIRMWARE_ROOT, path) target, entries = filebrowse.list_dir(FIRMWARE_ROOT, path)
except (filebrowse.PathEscapeError, FileNotFoundError, NotADirectoryError) as e: except (filebrowse.PathEscapeError, FileNotFoundError, NotADirectoryError) as e:
raise HTTPException(400, str(e)) raise HTTPException(400, str(e))
return templates.TemplateResponse("browse.html", { return templates.TemplateResponse(request, "browse.html", {
"request": request,
"rel": path, "rel": path,
"entries": entries, "entries": entries,
"crumbs": filebrowse.breadcrumbs(path), "crumbs": filebrowse.breadcrumbs(path),
@ -152,8 +147,7 @@ async def browse(request: Request, path: str = ""):
@app.get("/workflows/p10lite", response_class=HTMLResponse) @app.get("/workflows/p10lite", response_class=HTMLResponse)
async def workflow_p10lite(request: Request): async def workflow_p10lite(request: Request):
return templates.TemplateResponse("p10lite.html", { return templates.TemplateResponse(request, "p10lite.html", {
"request": request,
"instructions": p10lite.erecovery_instructions(), "instructions": p10lite.erecovery_instructions(),
}) })