Migrate dev tooling from pip-tools/tox to uv - #261
Conversation
Moves dev-tool extras to PEP 735 dependency-groups, replaces tox.ini and requirements.txt with uv.lock, drops build/twine in favor of native uv build/uv publish, and rewrites GitHub Actions workflows and Dependabot config to use astral-sh/setup-uv + uv sync/run instead of tox. Bumps datamodel-code-generator to >=0.27.1 to resolve an isort version conflict with the formatting group that tox's per-env isolated venvs had been masking. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Reverts the datamodel-code-generator bump: even the minimal bump to 0.27.1 breaks bo4e-python-generator==0.0.10, which relies on datamodel-code-generator internals (DataModelSet fields, DataTypeManager.type_map_factory signature) that changed across releases. Verified 0.25.9 (the version it was actually built against) works end-to-end for schema generation, pylint, and mypy. Resolves the original isort conflict by downgrading the formatting group's isort pin to 5.13.2 (last release satisfying datamodel-code-generator==0.25.9's isort<6.0 constraint) instead of bumping datamodel-code-generator. Also pins sqlmodel==0.0.24 in [project.dependencies]: the open-ended sqlmodel>=0.0.14 resolves to 0.0.39 by default, which breaks mypy against the bo4e-generated models (SQLModelConfig/ConfigDict incompatibilities). The old requirements.txt had silently frozen this same version for CI; uv.lock now does the same job explicitly. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
python-dotenv was unconstrained in [project.dependencies] (only frozen at 1.0.1 via the now-removed requirements.txt), so uv lock resolved it to 1.2.2. That breaks load_dotenv()'s implicit path discovery when pytest is wrapped by `coverage run -m pytest` from the tests/ directory (mirroring the old tox coverage env's changedir=tests), causing "OSError: Could not load .env file." during test collection. Confirmed locally: reproduces with 1.2.2, resolved with 1.0.1. Also matches repo history: a Dependabot PR bumping python-dotenv to 1.2.1 already failed CI here and was never merged. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
CI status: all checks green ✅Summary of the full fix chain that came out of debugging CI after the initial migration:
All three were cases where 🤖 Generated with Claude Code |
There was a problem hiding this comment.
Pull request overview
This PR migrates the repository’s Python dev tooling from pip-tools/tox to uv, centralizing dependency resolution in uv.lock and updating CI + documentation accordingly.
Changes:
- Replace
toxenv orchestration andrequirements.txtwithuvdependency groups anduv.lock. - Rewrite GitHub Actions workflows to use
astral-sh/setup-uv,uv sync --group …, anduv run …. - Update developer-facing tooling and docs (
pyproject.tomldependency groups, pre-commit hooks, README).
Reviewed changes
Copilot reviewed 12 out of 14 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| tox.ini | Removes legacy tox environments in favor of uv-based workflow steps. |
| requirements.txt | Removes pip-tools generated requirements in favor of uv.lock. |
| README.md | Updates dev setup and common commands to use uv sync / uv run. |
| pyproject.toml | Moves dev extras to [dependency-groups] and adjusts some pins. |
| .pre-commit-config.yaml | Updates formatter hook versions and adds uv-lock hook. |
| .github/workflows/unittests.yml | Migrates unit-test job to uv (but currently does not run tests). |
| .github/workflows/pythonlint.yml | Migrates lint/type/spell jobs to uv and inlines BO4E model generation. |
| .github/workflows/python-publish.yml | Migrates release workflow steps to uv and inlines checks. |
| .github/workflows/packaging_test.yml | Switches packaging test to uv build + uv publish --dry-run. |
| .github/workflows/integrationtests.yml | Migrates integration tests to uv and inlines DB/model setup. |
| .github/workflows/formatting.yml | Migrates formatting checks to uv groups and uv run. |
| .github/workflows/coverage.yml | Migrates coverage job to uv and inlines DB/model setup. |
| .github/dependabot.yml | Switches Dependabot ecosystem entry from pip to uv. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| cd src | ||
| uv run python -m borm.db.postgresql_db.create_env_file | ||
| docker compose -f borm/db/postgresql_db/docker-compose.yaml up -d | ||
| cd borm/db/postgresql_db | ||
| docker compose -f docker-compose.yaml down -v |
There was a problem hiding this comment.
Confirmed accurate, but this is pre-existing behavior, not something this migration changed — the old tox.ini's [testenv:unittests] also only ran tox -e setup_testpostgresql + tox -e remove_testpostgresql, never pytest (there's no separate unit-test suite in this repo, only tests/integrationtests, which is what integrationtests.yml actually exercises). I translated the tox behavior 1:1 rather than silently changing what this check does, since pytest (3.11, ubuntu-latest) is a required status check on main and I didn't want to risk changing its semantics without a separate discussion. Worth a follow-up issue if the maintainers want this job renamed or made to actually assert something.
pyproject.toml had a leftover merge-artifact comment ("toodynamic")
duplicating the dynamic field it sits next to. README had an
uncapitalized "windows" and missing comma.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Summary
tests,coverage,formatting,linting,spell_check,type_check,init_bo4e) from[project.optional-dependencies]to PEP 735[dependency-groups], plus a bundleddevgroup; drops thetest_packagingextra (build/twine) entirely.tox.iniandrequirements.txtwithuv.lock.astral-sh/setup-uv+uv sync --group X/uv runinstead ofpip install tox && tox -e X, inlining the docker-compose/BO4E-model-generation steps that tox used to chain via nestedtox -ecalls.packaging_test.ymlnow uses nativeuv build+uv publish --dry-runinstead ofbuild/twine..github/dependabot.ymlecosystem frompiptouv..pre-commit-config.yaml(bumps black rev to match new pins, adds theuv-lockhook).README.mddev setup instructions fromtox -e ...touv run/uv sync.Dependency pins (final state, after CI debugging)
datamodel-code-generatorstays pinned at==0.25.9(not bumped). An earlier attempt to bump it to resolve an isort conflict brokebo4e-python-generator==0.0.10, which relies ondatamodel-code-generatorinternals that changed across releases. Fixed the original isort conflict instead by pinning theformattinggroup'sisortto5.13.2(last release compatible withdatamodel-code-generator==0.25.9'sisort<6.0constraint).sqlmodelpinned to==0.0.24andpython-dotenvpinned to==1.0.1in[project.dependencies]. Both were previously open-ended constraints that only got frozen for CI via the now-removedrequirements.txt; without that freeze,uv lockpicked newer versions that breakmypy(sqlmodel) and.envloading undercoverage run -m pytest(python-dotenv). See PR comments below for the full debugging trail.No workflow matrix structures were changed, so existing required status checks on
mainshould still match by name.Test plan
uv lockresolves cleanlyuv sync --group devsucceedstests,linting,type_check,spell_check,coverage,formatting,init_bo4e)black --check,isort --check,codespell,pylint,mypy,pytestimport,bost --help,bo4e-generator --helpthroughuv runuv buildanduv publish --dry-runsucceed locally🤖 Generated with Claude Code