[project] name = "dashboards" version = "0.1.0" description = "Homelab dashboards on one domain: system resources, LLM engines, and UPS battery health" readme = "README.md" # 3.14 is what the Containerfile, the venv, and the fleet agent's tests run on. The floor # is deliberately hard: 3.13 would resolve a different lock and CI would test a stack nobody # deploys. requires-python = ">=3.14" # Deliberately small. Everything we collect is either our own agent's JSON (stdlib only, # see agent/host_agent.py) or an upstream Prometheus exposition parsed by our own parser # (src/dashboards/prom.py). No prometheus_client, no Grafana, no CDN, no bundler. dependencies = [ "fastapi>=0.143.3", "httpx>=0.28.1", "uvicorn[standard]>=0.54.0", "pydantic>=2.14.1", "python-dotenv>=1.2.4", # Phase 15: the dashboard mints its own root CA and signs the agent certs (`certs.py`). # Dashboard-side ONLY — `agent/host_agent.py` stays stdlib and loads the PEMs with `ssl`. # Wheels exist for every platform we build on, and it is the only sane way to issue X.509. "cryptography>=50.0.2", ] [dependency-groups] dev = [ "pytest>=9.1.1", "pytest-cov>=7.1.0", "pytest-asyncio>=1.4.0", "ruff>=0.17.1", "pyright>=1.1.414", "debugpy>=1.8.22", ] # Installed editable by `uv sync` (src layout), so `uv run dashboards` and # `uv run uvicorn dashboards.app:app` both work without PYTHONPATH gymnastics. [build-system] requires = ["hatchling>=1.27"] build-backend = "hatchling.build" [project.scripts] dashboards = "dashboards.__main__:main" [tool.hatch.build.targets.wheel] packages = ["src/dashboards"] [tool.pytest.ini_options] testpaths = ["tests"] addopts = "-q --strict-markers" markers = [ # `-m live --live` runs them; without --live they SKIP, so `uv run pytest` stays # network-free. See tests/test_live_fleet.py for the env vars each one needs. "live: needs real hardware (fleet hosts, LLM engines, or upsd) — opt in with --live", # `-m store_perf --store-perf` runs them: the phase-14 timing measurements over the seeded # production-shaped store (tests/store_perf.py). The seed itself runs in the default suite; # only the multi-minute measurement passes are behind this flag. Underscored because Python # decorators cannot carry a hyphen; the CLI flag stays `--store-perf`. "store_perf: measures the seeded store's hot paths — opt in with --store-perf", ] # auto: async tests run without a decorator on every single one asyncio_mode = "auto" filterwarnings = ["error::DeprecationWarning"] [tool.coverage.run] source = ["src/dashboards"] omit = ["tests/*"] [tool.coverage.report] show_missing = true skip_covered = false [tool.ruff] line-length = 110 target-version = "py314" src = ["src", "tests", "agent"] [tool.ruff.lint] select = ["E", "F", "W", "I", "UP", "B", "C4", "SIM", "RUF", "BLE", "PLC"] ignore = ["E501"] [tool.ruff.lint.per-file-ignores] # FastAPI's dependency injection is a call in a default argument; that is the API, not a bug. "src/dashboards/api.py" = ["B008"] [tool.pyright] include = ["src", "tests"] pythonVersion = "3.14" typeCheckingMode = "standard"