Migrate the backend from pip to uv
CI / Build and push docker image (push) Successful in 2m42s

Replace requirements.txt with a uv workspace and lockfile, install the five tavolo packages from packages/* in development and non-editable in the image, and build the Docker image with uv. Move dev tools to a PEP 735 dependency group and refresh the locked dependency versions.
This commit is contained in:
2026-10-20 07:25:25 +08:00
parent 03a571a6a5
commit 2d5c64218f
15 changed files with 1975 additions and 252 deletions
+27 -17
View File
@@ -99,7 +99,7 @@ All configuration comes from environment variables (see `.env.example`):
| `CORS_ALLOW_CREDENTIALS` | `false` | `1`/`true`/`yes`/`on` allow cookies/credentials on cross-origin requests |
| `CORS_EXPOSE_HEADERS` | unset | Comma-separated response headers exposed to the browser |
| `CORS_MAX_AGE` | `600` | Seconds browsers may cache the preflight response |
| `OTEL_ENABLED` | `false` | `1`/`true`/`yes`/`on` enable OpenTelemetry traces, metrics and logs (the Docker image bundles the `otel` extra; non-image installs need `pip install tavolo-app[otel]`) |
| `OTEL_ENABLED` | `false` | `1`/`true`/`yes`/`on` enable OpenTelemetry traces, metrics and logs (the Docker image bundles the `otel` extra; non-image installs need `uv sync --package tavolo-app --extra otel`) |
| `OTEL_SERVICE_NAME` | `tavolo` | `service.name` resource attribute of the exported telemetry |
| `OTEL_EXPORTER_OTLP_ENDPOINT` | unset | Base URL of an OTLP/HTTP collector (e.g. `http://localhost:4318`); unset uses the exporter default |
| `OTEL_EXPORTER_OTLP_HEADERS` | unset | Comma-separated `key=value` headers sent to the collector (e.g. authentication) |
@@ -276,7 +276,7 @@ rebuild every rating and aggregate from the recorded match history (e.g.
to backfill matches recorded before ratings existed):
```sh
.venv/bin/python -m tavolo.platform.backfill_elo \
uv run python -m tavolo.platform.backfill_elo \
--database-url postgres://tavolo:tavolo@localhost:5432/tavolo
```
@@ -511,24 +511,33 @@ rejected with an `illegal_move` error.
## Development
The backend is a [uv](https://docs.astral.sh/uv/) workspace: `pyproject.toml`
declares the five packages under `packages/` as members, and `uv.lock` pins
their full dependency closure. The checked-in `.python-version` selects
Python 3.14, matching the Docker image. Install uv, then from `server/`:
```sh
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt
.venv/bin/pip install -e ./packages/tavolo-platform -e ./packages/tavolo-scopone -e ./packages/tavolo-scopa -e ./packages/tavolo-briscola -e './packages/tavolo-app[dev]'
uv sync --package tavolo-app --extra otel
# app integration suite:
.venv/bin/python -m unittest discover -s tests -t .
uv run python -m unittest discover -s tests -t .
# per-package suites (each package is self-contained):
.venv/bin/python -m unittest discover -s packages/tavolo-platform/tests
.venv/bin/python -m unittest discover -s packages/tavolo-scopone/tests
.venv/bin/python -m unittest discover -s packages/tavolo-scopa/tests
.venv/bin/python -m unittest discover -s packages/tavolo-briscola/tests
uv run python -m unittest discover -s packages/tavolo-platform/tests
uv run python -m unittest discover -s packages/tavolo-scopone/tests
uv run python -m unittest discover -s packages/tavolo-scopa/tests
uv run python -m unittest discover -s packages/tavolo-briscola/tests
# type checks (see packages/tavolo-app/README.md for the app modules):
.venv/bin/python -m mypy -p tavolo.platform
.venv/bin/python -m mypy -p tavolo.scopone
.venv/bin/python -m mypy -p tavolo.scopa
.venv/bin/python -m mypy -p tavolo.briscola
uv run mypy -p tavolo.platform
uv run mypy -p tavolo.scopone
uv run mypy -p tavolo.scopa
uv run mypy -p tavolo.briscola
```
`uv sync` installs the workspace's `dev` dependency group (`mypy`,
`httpx-ws`) automatically; pass `--no-dev` for a runtime-only environment.
The `otel` extra is optional, but without it the telemetry integration tests
skip. The lockfile is committed: use `uv lock --upgrade` (or
`uv lock --upgrade-package <name>`) to update dependencies deliberately.
Tests run fully in-process: in-memory sqlite for Postgres, in-memory stores
for Redis, a fake OIDC user patched onto the mixins, and `httpx` /
`httpx-ws` ASGI transports for HTTP and WebSocket coverage. The platform
@@ -543,8 +552,8 @@ To add a migration after changing
`packages/tavolo-platform/src/tavolo/platform/models.py`:
```sh
DATABASE_URL=postgres://tavolo:tavolo@localhost:5432/tavolo .venv/bin/aerich migrate
DATABASE_URL=postgres://tavolo:tavolo@localhost:5432/tavolo .venv/bin/aerich upgrade
DATABASE_URL=postgres://tavolo:tavolo@localhost:5432/tavolo uv run aerich migrate
DATABASE_URL=postgres://tavolo:tavolo@localhost:5432/tavolo uv run aerich upgrade
```
(`aerich init-db` produces sqlite-flavored DDL when pointed at sqlite;
@@ -605,7 +614,8 @@ packages/tavolo-app/ # deployable app: composition root (own pyproject)
├── aerich_config.py # aerich CLI configuration
├── logging_config.py # logging setup
└── static.py # SPA shell hosting
pyproject.toml # tooling shim: [tool.aerich] + [tool.mypy] for server/ CWD
pyproject.toml # uv workspace root + [tool.aerich] / [tool.mypy]
uv.lock # locked dependency set for the whole workspace
migrations/ # aerich migrations for the platform models
tests/ # app integration suite (platform + games wired together)
```