Fix all linter issues

This commit is contained in:
Johannes Schriewer 2026-08-30 22:49:19 +02:00
parent fbd4b6c5e8
commit d4a2ace913
10 changed files with 2989 additions and 28 deletions

View file

@ -60,7 +60,7 @@ agent's own shell command line and kills the session.
while the UI switch is on, reaps stale locks by `who` marker on startup)
+ lact plugin (shells out to `lact cli`: per-GPU profile dropdown with
set/reload, active profile polled every 5 s, GPU names shortened with
`app/collect/gpu.py:_shorten` like the overview card).
`app/collect/gpu.py:shorten` like the overview card).
## Conventions

View file

@ -1 +0,0 @@
from app import routers # noqa: F401

View file

@ -16,7 +16,7 @@ def _read(path: str) -> str | None:
return None
def _shorten(name: str) -> str:
def shorten(name: str) -> str:
name = re.sub(r"\s*\(rev.*\)$", "", name).strip()
groups = re.findall(r"\[([^\]]+)\]", name)
if len(groups) >= 2:
@ -42,7 +42,7 @@ def _gpu_name() -> str:
).stdout
for line in out.splitlines():
if "VGA" in line or "3D controller" in line:
_name_cache = _shorten(line.split(":", 2)[-1].strip())
_name_cache = shorten(line.split(":", 2)[-1].strip())
break
except (OSError, subprocess.SubprocessError):
pass

View file

@ -1,10 +1,11 @@
from functools import lru_cache
from typing import ClassVar
from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings):
model_config = SettingsConfigDict(env_prefix="DASH_", env_file=".env", extra="ignore")
model_config: ClassVar[SettingsConfigDict] = SettingsConfigDict(env_prefix="DASH_", env_file=".env", extra="ignore")
host: str = "127.0.0.1"
port: int = 8501

View file

@ -39,6 +39,10 @@ async def lifespan(app: FastAPI):
pass
async def index():
return HTMLResponse(render("index.html", hostname=socket.gethostname()))
def create_app() -> FastAPI:
app = FastAPI(title="Dashboard", lifespan=lifespan)
app.mount("/static", StaticFiles(directory=BASE / "static"), name="static")
@ -46,10 +50,7 @@ def create_app() -> FastAPI:
app.include_router(r)
for r in PLUGIN_ROUTERS:
app.include_router(r)
@app.get("/", include_in_schema=False)
async def index():
return HTMLResponse(render("index.html", hostname=socket.gethostname()))
_ = app.get("/", include_in_schema=False)(index)
return app

View file

@ -1,12 +1,12 @@
import asyncio
import re
import time
from typing import Any
from typing import Annotated, Any
from fastapi import APIRouter, Form
from fastapi.responses import HTMLResponse
from app.collect.gpu import _shorten
from app.collect.gpu import shorten
from app.plugins.base import Plugin
from app.render import render
@ -55,7 +55,7 @@ def _parse_gpus(out: str) -> list[dict[str, str]]:
gpu_type = re.search(r"\[([^\]]*)\]\s*$", rest)
gpus.append({
"id": m.group(1),
"name": _shorten(name.group(1)) if name else rest.strip(),
"name": shorten(name.group(1)) if name else rest.strip(),
"type": gpu_type.group(1) if gpu_type else "",
})
return gpus
@ -126,7 +126,7 @@ async def state():
@router.post("/set")
async def set_profile(gpu_id: str = Form(...), profile: str = Form(...)):
async def set_profile(gpu_id: Annotated[str, Form()], profile: Annotated[str, Form()]):
async with _set_lock:
data = await _gather(with_profiles=True, force_gpus=True)
if data["error"]:
@ -145,7 +145,7 @@ async def set_profile(gpu_id: str = Form(...), profile: str = Form(...)):
@router.post("/reload")
async def reload(gpu_id: str | None = Form(None)):
async def reload(gpu_id: Annotated[str | None, Form()] = None):
_ = gpu_id
return HTMLResponse(await _skeleton(message="profiles refreshed"))

View file

@ -1,4 +1,4 @@
from typing import Any
from typing import Annotated, Any
import httpx
from fastapi import APIRouter, Form
@ -12,7 +12,7 @@ router = APIRouter(prefix="/api/plugins/llamacpp", tags=["plugins"])
def _headers(settings: Settings) -> dict[str, str]:
h = {}
h: dict[str, str] = {}
if settings.llama_api_key:
h["Authorization"] = f"Bearer {settings.llama_api_key}"
return h
@ -37,6 +37,7 @@ async def gather_status() -> dict[str, Any]:
"models": [],
"error": None,
}
models: list[dict[str, str | bool | float]] = []
try:
async with _client() as client:
try:
@ -62,12 +63,13 @@ async def gather_status() -> dict[str, Any]:
done = sum(p.get("done", 0) for p in prog.values())
total = sum(p.get("total", 1) for p in prog.values())
item["progress"] = round(done / total * 100, 1) if total else 0.0
status["models"].append(item)
status["models"].sort(key=lambda m: m["id"])
models.append(item)
models.sort(key=lambda m: m["id"])
except httpx.HTTPError as e:
status["error"] = f"unreachable: {e.__class__.__name__}"
except Exception as e: # noqa
status["error"] = str(e)[:200]
status["models"] = models
return status
@ -117,7 +119,7 @@ async def state():
@router.post("/load")
async def load(model: str = Form(...)):
async def load(model: Annotated[str, Form()]):
ok, err = await _action("/models/load", model)
return HTMLResponse(
await _skeleton(
@ -128,7 +130,7 @@ async def load(model: str = Form(...)):
@router.post("/unload")
async def unload(model: str = Form(...)):
async def unload(model: Annotated[str, Form()]):
ok, err = await _action("/models/unload", model)
return HTMLResponse(
await _skeleton(

View file

@ -2,7 +2,7 @@ import asyncio
import json
import os
import signal
from typing import Any
from typing import Annotated, Any, cast
from fastapi import APIRouter, Form
from fastapi.responses import HTMLResponse
@ -45,7 +45,7 @@ async def _list() -> tuple[list[dict[str, Any]], str]:
return [], "could not parse systemd-inhibit output"
if not isinstance(data, list):
return [], "unexpected systemd-inhibit output"
items: list[dict[str, Any]] = [e for e in data if isinstance(e, dict)]
items: list[dict[str, Any]] = [e for e in cast("list[Any]", data) if isinstance(e, dict)]
return items, ""
@ -155,7 +155,7 @@ async def state():
@router.post("/toggle")
async def toggle(on: str | None = Form(None)):
async def toggle(on: Annotated[str | None, Form()] = None):
async with _toggle_lock:
if on and _holder is None:
err = await _acquire()

View file

@ -1,4 +1,4 @@
from typing import Any
from typing import Annotated, Any
from fastapi import APIRouter, Form
from fastapi.responses import HTMLResponse
@ -95,10 +95,10 @@ async def service_detail(unit: str):
@router.post("/{unit}/action")
async def service_action(
unit: str,
action: str = Form(...),
q: str = Form(""),
sort: str = Form("name"),
order: str = Form("asc"),
action: Annotated[str, Form()],
q: Annotated[str, Form()] = "",
sort: Annotated[str, Form()] = "name",
order: Annotated[str, Form()] = "asc",
):
error = None
try:

File diff suppressed because it is too large Load diff