Hi all,
One more toolchain thread, next to Path to Ruff. Same idea on the packaging side: pip-tools to uv for compiling the requirements lockfile. This one is already written and open as a pull request.
What pip-tools is
pip-tools is the pair of programs that turns a loose list of dependencies into a locked one: requirements.in names what we want, pip-compile resolves the whole tree and writes every transitive pin into requirements.txt. That lock is what the images install, so a build is reproducible rather than whatever PyPI happened to serve that morning.
What uv is
uv is a Python packaging tool written in Rust that reimplements pip and pip-tools behind a single binary, resolving an order of magnitude or more faster than either of them. It comes from the same people as Ruff, and as ty, the type checker in tox -e typecheck.
The move
A single command changes, the one that compiles the lockfile:
pip-compile -> uv pip compile
One line in requirements/updater.sh, and the flags carry across as they are:
--no-strip-extras, --no-header, --quiet and --output-file carry over unchanged.
--upgrade and --upgrade-package carry over unchanged.
-r, the rebuild flag, becomes --refresh.
--allow-unsafe has no counterpart, because uv emits pip and setuptools by default.
The part that is not a flag swap
The script comments out the git requirements after compiling, so nothing is installed twice, once from requirements.txt and once from requirements_git.txt. It did that by matching a whole line from one file against the other, which worked because pip-compile echoed the branch ref back unchanged.
uv resolves a branch to the commit sha it points at. So where requirements_git.txt says certifi @ git+...@devel, uv emits certifi @ git+...@5aa52ab91f9d579bfe52b5acf30ca799f1a563d9, the old pattern stops matching, and all three git requirements are left uncommented. Matching is now on the package name instead, and the comment written into the file keeps the branch wording this repository actually tracks.
Worth saying plainly: that is the kind of thing a flag comparison does not surface. It only showed up by running the script and reading the output.
What the run showed
Compiled in the devel container against Python 3.14, holding the existing pins:
- All 148 version pins resolve identically to what is committed today.
- The three git lines end up commented exactly as before.
- The only diff in
requirements.txt is pip and setuptools moving out of pip-compile's trailing "considered to be unsafe" block into alphabetical order. Nothing in the repository reads that section.
What this does not touch
docs/docsite/updater.sh compiles the documentation lockfile and still used pip-tools. It is a separate requirements set with its own constraints, so it went into its own change, now open as #908. Two places compile that lockfile and both moved, the script and the pip-compile-docs testenv in tox.ini, so the repository is not left with one lockfile and two compilers. Checked the same way as here: holding the existing pins all 27 resolve identically, running the script end to end rewrites the file byte for byte, and the tox path agrees. The diff is the two scripts and nothing else.
./updater.sh dev rewrites requirements_dev.txt from the loose list it is today into a fully pinned closure. That is inherent to that code path rather than anything here: the committed file is hand maintained and unpinned, so no compiler would reproduce it.
Pull requests
Thanks for reading.