Repository navigation
chore(api): manage Python dependencies with uv - #9950
Conversation
Replace apps/api/requirements*.txt with pyproject.toml dependencies and dependency groups (production, dev, test), pinned in a committed uv.lock. - Dockerfile.api / Dockerfile.dev install with `uv sync --locked` into the image's Python (/usr/local), so python/gunicorn/celery paths and pip are unchanged; uv is bind-mounted for the build step and not shipped in the production image. - docker-compose-test.yml re-syncs against the mounted lock instead of pip-installing test requirements. - CI uses astral-sh/setup-uv; --locked fails the job on a stale lock. - Bump the test-only httpx pin 0.24.1 -> 0.28.1: a shared lock would otherwise downgrade production to h11 0.14.0 (CVE-2025-43859). - Restrict psycopg-c to Linux so `uv sync` works on macOS without libpq headers (psycopg-binary covers it there).
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configuration
⛔ Files ignored due to path filters (1)
📒 Files selected for processing (12)
💤 Files with no reviewable changes (1)
🚧 Files skipped from review as they are similar to previous changes (1)
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review. 📝 WalkthroughWalkthroughThe API dependency configuration now uses uv and Python 3.12. Docker images, test execution, and CI workflows sync dependencies through uv. The previous requirements files are removed, and contributor and test documentation describes the updated setup. ChangesAPI dependency management
Priority: ⬇️ Low Estimated code review effort: 3 (Moderate) | ~20 minutes Change: Other Merge Risk: ⚪ Minimal · up to The documented container dependency command preserves the image’s pip installation. No confirmed blocker remains; complete the planned CI and image checks before merging. Security Architecture ReviewSecurity architecture risk: 🔵 Low · up to The migration pins dependency installation while preserving existing runtime entrypoints. No privilege expansion or unsafe startup transition was demonstrated. Remaining uncertainty concerns dependency state in reused test images and deployment-wide rollout and rollback behavior. Retained concerns Security review detailsSecurity Blast Radius
Trust Boundaries and Controls
Resilience and Maintainability Implications
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
- Lint: drop `ruff check --fix` so fixable violations fail the job, remove the three unused imports it was silently fixing, and sync only the dev group for the lint job. - psycopg: base keeps only `psycopg`; `psycopg-c` moves to the production group (production image + migration-check) and `psycopg-binary` to dev/test, so local setups never compile and production ships no unused binary wheel. - Pin uv once: `[tool.uv] required-version = "==0.12.21"`, read by setup-uv via version-file; the uv image is pinned by digest. - CI runs on managed CPython 3.12.12 to match the production image. - Move ruff config to ruff.toml so pyproject.toml (and the Docker dependency layer) only changes with dependencies. - .dockerignore also excludes venv, .env and host bytecode. - Test entrypoint fails with a rebuild hint on pre-uv images; documented `run` commands pass --build; document `uv sync --inexact` in containers.
pablohashescobar
left a comment
There was a problem hiding this comment.
Approving. All first-round threads are addressed and CI is green.
Known limits, accepted for this PR:
- The uv image is amd64/arm64 only, so from-source self-host builds on other architectures (install.sh fallback) no longer build.
RUN --mountin Dockerfile.api requires BuildKit.- Both API workflows share a setup-uv cache key, so migration-check never caches its psycopg-c build; a per-job
cache-suffixfixes it.
Description
Moves the API server (
apps/api) from piprequirements*.txtfiles to uv, with a committed lockfile so every environment installs the same, hash-verified dependency set.apps/api/pyproject.tomland pinned inapps/api/uv.lock. The old files map to:base.txt→[project].dependencies;production.txt→productiongroup (gunicorn);local.txt→devgroup;test.txt→testgroup.uv syncinstallsdev+testby default..python-versionpins 3.12.[tool.uv] required-version = "==0.12.21"pins uv itself. Ruff config moved toapps/api/ruff.toml, sopyproject.toml(and the Docker dependency layer) only changes when dependencies do.Dockerfile.api,Dockerfile.dev) install withuv sync --locked, using the uv 0.12.21 image pinned by digest, into the image's own Python (/usr/local) rather than a venv. That keepspython,gunicorn,celeryand the entrypoints at the same paths as before, keepspipusable in the container, and avoids the dev compose bind-mount (./apps/api:/code) hiding an in-tree.venv. The production image bind-mounts uv for the install step only, so the binary isn't shipped.docker-compose-test.ymlre-syncs against the mounteduv.lock(a no-op when the image is current) instead ofpip install -r requirements/test.txt. On an image built before this PR it exits with a hint to rebuild, and the documentedruncommands pass--build.migration-check.yml,pull-request-build-lint-api.yml) usesastral-sh/setup-uv@v7with lock-keyed caching. It reads the uv version fromrequired-versionand runs on managed CPython 3.12.12, the same patch release as the production image.--lockedfails the job ifpyproject.tomlchanges without regeneratinguv.lock. Lint syncs only thedevgroup, uses the locked ruff (0.9.7), and no longer passes--fix, so fixable violations fail the job. The three unused imports--fixhad been silently rewriting are removed.AGENTS.mdgets a short uv section;RUNNING_TESTS.mdandCONTRIBUTING.mdare updated. A newapps/api/.dockerignorekeeps local venvs,.envand host bytecode out of the dev image.Dependency decisions worth reviewing
httpx0.24.1 → 0.28.1 (test group). A uv lock holds one version per package across all groups, so the old test-only pin would have pulled production down tohttpcore0.17 /h110.14.0, which is affected by CVE-2025-43859 (request smuggling). Production already resolved 0.28.1 viaopenai, and no code importshttpxdirectly (tests use DRF'sAPIClient).psycopg.psycopg-c(sdist-only, needs libpq headers and a compiler) is inproduction, so only the production image and migration-check compile it.psycopg-binaryis indev/test, so local setups and the dev/test image never compile, and production no longer ships the unused binary wheel. The dev/test image therefore uses the binary implementation, while production uses C.testgroup, becausetestis a default group.Heads-up:
apps/api/requirements.txtandrequirements/are deleted. Any external tooling that runspip install -r apps/api/requirements.txtshould switch touv sync --locked --no-default-groups --group production, or install fromuv export --no-default-groups --group production.Type of Change
Screenshots and Media (if applicable)
Test Scenarios
Verified locally:
uv exportfrom the lock lists the same package versions asuv pip compileof the old requirements files (linux, py3.12). The only differences are the intentionalhttpxbump and Windows-onlycolorama.Dockerfile.api) builds on Alpine with 106 packages, includingpsycopg-cand notpsycopg-binary.uvis not present in the image,psycopg.pq.__impl__ == "c", andpython manage.py checkpasses with production settings.manage.py checkandmakemigrations --check --dry-run.docker compose -f docker-compose-test.yml up --build --abort-on-container-exit --exit-code-from api-tests(builds the newDockerfile.dev): 706 passed. The only failures came from a local, uncommitted WIP test file that isn't part of this PR.cd apps/api && uv syncsucceeds without Postgres dev headers (psycopg.pq.__impl__ == "binary").UV_PYTHON=3.12.12 uv sync --locked --only-group devinstalls 6 packages.ruff check .exits 1 on a fixable violation and 0 on the tree.required-versionerror. On a pre-uv image, the test entrypoint prints the rebuild hint and exits 1.For reviewers:
docker compose -f docker-compose-local.yml up --buildand check that api, worker, beat-worker and migrator start and the app loads.Dockerfile.apiforlinux/amd64as well (the multi-arch release build) and run the image's entrypoint against a real DB.References
apps/api/uv.lockin place of the removed requirements files.🤖 Generated with Claude Code
Summary by CodeRabbit
Chores
Documentation