Getting started
Prerequisites
- Python 3.12+
- uv (dependency management)
make(optional - every target is one command you can type by hand)- Docker (optional - only for PostgreSQL or the container image)
- Node.js 22+ (optional - only for the documentation site and releases)
Run it
git clone https://github.com/davidcohenDC/python-clean-architecture-template
cd python-clean-architecture-template
make install # uv sync --all-extras && git config core.hooksPath .githooks
make run # alembic upgrade head && uvicorn cleanarch.main:app --reload
Open http://localhost:8000/docs. You get a SQLite file (dev.db)
and every feature's endpoints under /api/v1.
No database at all? Use the in-memory adapters:
make run-memory # DATABASE_URL=memory:// uvicorn cleanarch.main:app --reload
PostgreSQL:
docker compose up db -d
DATABASE_URL=postgresql+asyncpg://postgres:postgres@localhost:5432/app make run
Or the whole thing in containers: docker compose up.
Try the example API
# create a tournament: 2 Swiss rounds, then a top-8 single-elimination bracket
curl -s -X POST localhost:8000/api/v1/tournaments -H 'content-type: application/json' -d '{
"name": "Spring Cup",
"phases": [
{"config": {"kind": "round", "rounds": 2, "pairing": "swiss"}},
{"config": {"kind": "bracket", "elimination": "single"}, "cut": {"players": 8}}
]
}'
# → 201 {"id": "...", "name": "Spring Cup", "phases": [...], "progress": {"status": "not_started", ...}}
curl -s -X POST localhost:8000/api/v1/tournaments/<id>/start # → in_progress, phase 0, round 0
curl -s -X POST localhost:8000/api/v1/tournaments/<id>/advance # → phase 0, round 1
curl -s -X POST localhost:8000/api/v1/tournaments/<id>/advance # → phase 1 (bracket)
curl -s -X POST localhost:8000/api/v1/tournaments/<id>/advance # → finished
curl -s -X POST localhost:8000/api/v1/tournaments/<id>/advance # → 422 TournamentAlreadyFinished
The same use cases from the terminal
uv run python -m cleanarch tournaments create "Spring Cup" --rounds 2 --top 8
uv run python -m cleanarch tournaments list
uv run python -m cleanarch tournaments start <id>
Same use cases, same database, no HTTP: tournaments/cli/ is a second driving adapter.
Run the checks
make test # whole suite with coverage
make test-fast # everything but the repository contract tests
make lint # ruff check + ruff format --check
make typecheck # mypy --strict
make check # all of the above - what CI runs
make proof # (template repository only) the executable guarantees, one verdict each
Configuration
Everything is an environment variable with a default (see .env.example and
bootstrap/settings.py). Copy .env.example to .env to override locally.
| Variable | Default | Notes |
|---|---|---|
DATABASE_URL | sqlite+aiosqlite:///./dev.db | any SQLAlchemy async URL, or memory:// |
DATABASE_ECHO | false | log SQL statements |
LOG_LEVEL | INFO | |
LOG_FORMAT | text | json for log collectors; every line carries the request id |
DEBUG | false | FastAPI debug mode |
ENVIRONMENT | development | development / test / production |
API_KEYS | {} | JSON map key → actor[:role,...]; empty = open API, everyone is anonymous |
Make it yours
uv run python scripts/init_project.py --name shopapi --remove-example
uv run python scripts/new_feature.py orders