4.0 KiB
Python 3.14 + Dependency Update — Design
Date: 2026-07-08 Status: Approved Author: brainstorming session
Goal
Update the project to run on Python 3.14 and bring all dependencies up to recent stable versions. No functional changes to application behavior.
Background
- The local interpreter is already Python 3.14.6 (
/opt/homebrew/bin/python3.14). Dockerfilepinspython:3.9-alpineand hardcodes/usr/local/lib/python3.9/site-packagesin the final stage — a latent bug that breaks on any version bump.python-joseis declared inrequirements.txtbut never imported anywhere in the codebase (verified by grep across all*.py). It is effectively unmaintained (last release 3.5.0).main.pyalready runs fine under pydantic v2 and recent FastAPI on the local 3.14 venv; no code changes are required for the version bumps.- The repo contains pre-existing duplicate trees (
code/,source/) that are out of scope.
Scope
In scope:
requirements.txtrequirements-test.txtDockerfile- New
.python-versionfile
Out of scope:
- Any code changes to
main.py,generate_favicon.py, or templates. - Type-hint modernization (e.g.
Optional[X]→X | None). Not caused by this change. - Removal of unused imports in
main.py(HTTPException,Header,StaticFiles). Pre-existing dead code. - The
code/andsource/duplicate directories. - Switching the Docker base image from alpine to slim. Considered and rejected — alpine is the existing convention and keeps the diff minimal.
Decisions
Dependency specifier strategy
Keep the existing >= lower-bound convention, but bump floors to recent stable majors. Rationale: matches existing convention, allows automatic patch/minor updates, avoids the maintenance burden of exact pinning.
python-jose removal
Drop python-jose from requirements.txt. Rationale: unused (no imports anywhere), unmaintained, reduces install time and attack surface. All JWT operations use pyjwt.
Dockerfile base image
python:3.9-alpine → python:3.14-alpine. Keeps the alpine + multi-stage + non-root-user convention. Only changes that are forced by the version bump will be touched (base image tag + the two hardcoded python3.9 path references).
Changes
1. requirements.txt
Replace contents with:
fastapi>=0.115.0
uvicorn>=0.30.0
pyjwt>=2.9.0
requests>=2.32.0
cryptography>=44.0.0
(python-jose line removed.)
2. requirements-test.txt
Replace contents with:
pytest>=8.3.0
pytest-cov>=5.0.0
coverage>=7.4.0
httpx>=0.27.0
asgi_lifespan>=2.0.0
3. Dockerfile
Two surgical edits:
- Line 2:
FROM python:3.9-alpine AS python-base→FROM python:3.14-alpine AS python-base - Line 32:
COPY --from=builder /usr/local/lib/python3.9/site-packages /usr/local/lib/python3.9/site-packages→python3.14in both path segments.
Everything else in the Dockerfile stays unchanged: alpine packages (curl, gcc musl-dev libffi-dev openssl-dev), non-root user, port, healthcheck, CMD.
4. .python-version (new file)
Contents: 3.14
Purpose: signals the intended interpreter to pyenv-aware tooling and documents the target version for local development.
Verification
Success criteria — all must pass:
- Venv install: Recreate
venv/withpython3.14 -m venv venv,pip install -r requirements.txt -r requirements-test.txtexits 0. - Test suite:
./run_tests.shexits 0 with the same (or better) coverage as before. No new failures. - Docker build (if available):
docker build -t oidc-validator .exits 0.
Risks
- cryptography build from source on alpine: mitigated by the existing
gcc musl-dev libffi-dev openssl-devbuild-deps line. cryptography 44+ ships musllinux wheels for 3.14, so a wheel should be available; if not, the build deps cover it. - New dependency majors changing behavior: FastAPI 0.115 and pydantic v2 are already running locally without issue; no code changes observed as necessary. If tests surface breakage, it will be caught by the verification step and addressed then.