Use project-pinned uv and check min version in prek hooks#65531
Use project-pinned uv and check min version in prek hooks#65531potiuk merged 5 commits intoapache:mainfrom
Conversation
Prek hooks that invoke uv (directly or via breeze) now prefer `.venv/bin/uv` from the project's main virtualenv over PATH uv so the uv version is pinned by the project, and verify it satisfies the minimum declared in `[tool.uv] required-version` in the root pyproject.toml. If the main-venv uv is missing, the mypy local runner falls back to PATH uv with a warning. An outdated uv fails fast with upgrade instructions instead of emitting confusing downstream errors.
`breeze`'s `perform_environment_checks` already validates Docker and docker-compose versions before running any command; extend it with a matching `check_uv_version` that reads `[tool.uv] required-version` from the root `pyproject.toml` and confirms the `uv` on PATH satisfies it, matching the pattern the prek hooks now use. Users get the same clear "upgrade uv to X.Y.Z" error from `breeze` commands that they'd see from a standalone prek hook, instead of a confusing failure deeper in the shell bootstrap.
`[tool.uv] required-version` is the minimum uv contributors must have installed, not the exact uv version CI pins to. Bumping it on every uv release would force every contributor to upgrade uv in lockstep, which is far more churn than the floor check is worth. Leave an explicit comment both at the declaration site and in `scripts/ci/prek/upgrade_important_versions.py` (where `UV_PATTERNS` could be tempted to pick it up) so a future contributor doesn't wire it into the automated bump by accident. The breeze/prek uv version checks already read it dynamically and tolerate a stale floor.
The uv version check is not docker-specific — it applies to any breeze entry point that invokes uv, including flows that never talk to Docker. Move `check_uv_version` and `_read_required_uv_version` from `docker_command_utils` into the generic `environment_check` module, use `packaging.version.parse` directly instead of docker-scoped `compare_version`, and move the unit tests alongside. `perform_environment_checks` continues to call it after the Docker checks so the behavior is unchanged.
`[tool.uv] required-version` is bumped manually (by design — see the comment next to it in pyproject.toml). When it moves, any hard-coded uv version in tests that represents that floor needs to move too or the fixtures silently drift. Add a `sync-uv-min-version-markers` prek hook that reads the current `required-version` and rewrites any line tagged with a `# sync-uv-min-version` marker to match. The hook fails (prek convention) when it makes a change, so the contributor just re-stages. The existing `check_uv_version` tests carry the marker on their mocked floor constant so a future bump to `required-version` will propagate through the marker and keep the success-path assertions in sync.
jscheffl
left a comment
There was a problem hiding this comment.
Oh, wow a lot of code just to check and allow other UV installs.
Unfortunately - and we would not have to do it if not the parsing issue with uv`s internal version check. |
Backport failed to create: v3-2-test. View the failure log Run detailsNote: As of Merging PRs targeted for Airflow 3.X In matter of doubt please ask in #release-management Slack channel.
You can attempt to backport this manually by running: cherry_picker 0a67541 v3-2-testThis should apply the commit to the v3-2-test branch and leave the commit in conflict state marking After you have resolved the conflicts, you can continue the backport process by running: cherry_picker --continueIf you don't have cherry-picker installed, see the installation guide. |
Prek hooks that invoke
uv(directly from the mypy local runner or indirectly viabreeze) now:uvfrom the project's main.venv/bin/uvover whateveruvis onPATH, so the uv version used to sync and run mypy is pinned by the project.uvis already part of thedevgroup viaapache-airflow[all], so a regularuv syncinstalls it. The mypy local runner falls back touvonPATHwith a warning if.venv/bin/uvis missing.uvthey are about to invoke meets the minimum declared in[tool.uv] required-versionin the rootpyproject.toml, and fail fast with upgrade instructions (uv self update/uv sync) if it is older — instead of letting a stale uv produce confusing downstream errors.Implemented as a manual check (regex parse of
pyproject.toml, tuple compare ofuv --version) inscripts/ci/prek/common_prek_utils.py; wired intoinitialize_breeze_prek()so every breeze-calling hook gets it, and called explicitly from the mypy local runner against the selecteduv_bin.AGENTS.mdandcontributing-docs/08_static_code_checks.rstupdated to describe both behaviors.Was generative AI tooling used to co-author this PR?
Generated-by: Claude Code (claude-opus-4-7) following the guidelines