Stop the pipx virtualenvs depending on the system Python #2

Merged
mgbruin merged 1 commit from pin-uv-managed-python into main 2026-09-22 18:01:55 +00:00
Owner

Fixes the cause behind DWA-71 for this repository. One line in [env].

What broke

ansible-core, ansible-lint and yamllint all failed on river with ModuleNotFoundError, so mise run lint could not pass in any role or playbook repository.

The tools are uv virtualenvs, and uv had built them against /usr/bin/python3:

pyvenv.cfg home = /usr/bin, version_info = 3.12.3
packages lib/python3.12/site-packages
/usr/bin/python3 today 3.14.4 — python3.12 is gone

3.14 looks in lib/python3.14/site-packages, finds nothing, and every entry point imports nothing. The binaries were intact the whole time, which is why it read as a broken install rather than a moved interpreter.

The fix

[env]
UV_PYTHON_PREFERENCE = "only-managed"

uv then downloads and owns the interpreter, and an OS upgrade cannot orphan it.

Verified in both directions

The part worth checking was whether mise passes the variable through to a tool install at all, so I tested the inverse:

setting resulting pyvenv.cfg home
only-system /usr/bin (3.14.4)
only-managed ~/.local/share/uv/python/cpython-3.13-…

It does. Afterwards mise run lint passes at the production profile here, and the same rebuilt tools make it pass in ansible_role_monitoring, ansible_role_node_exporter, ansible_playbook_baseline and ansible_playbook_flatcar.

What did not work

Pinning python in [tools] — the obvious first attempt. mise installs that Python, and uv ignores it and picks its own anyway. It would have been misleading config with a comment claiming something untrue, so it is not in this PR.

Still to do elsewhere

The same line belongs in the other eight repositories, since this tooling is duplicated by design. Tracked in DWA-71 rather than done here, so each repo's change is reviewable on its own.

Fixes the cause behind DWA-71 for this repository. One line in `[env]`. ## What broke `ansible-core`, `ansible-lint` and `yamllint` all failed on river with `ModuleNotFoundError`, so `mise run lint` could not pass in **any** role or playbook repository. The tools are uv virtualenvs, and uv had built them against `/usr/bin/python3`: | | | |---|---| | `pyvenv.cfg` | `home = /usr/bin`, `version_info = 3.12.3` | | packages | `lib/python3.12/site-packages` | | `/usr/bin/python3` today | **3.14.4** — `python3.12` is gone | 3.14 looks in `lib/python3.14/site-packages`, finds nothing, and every entry point imports nothing. The binaries were intact the whole time, which is why it read as a broken install rather than a moved interpreter. ## The fix ```toml [env] UV_PYTHON_PREFERENCE = "only-managed" ``` uv then downloads and owns the interpreter, and an OS upgrade cannot orphan it. ## Verified in both directions The part worth checking was whether mise passes the variable through to a tool install at all, so I tested the inverse: | setting | resulting `pyvenv.cfg` `home` | |---|---| | `only-system` | `/usr/bin` (3.14.4) | | `only-managed` | `~/.local/share/uv/python/cpython-3.13-…` | It does. Afterwards `mise run lint` passes at the production profile here, and the same rebuilt tools make it pass in `ansible_role_monitoring`, `ansible_role_node_exporter`, `ansible_playbook_baseline` and `ansible_playbook_flatcar`. ## What did not work Pinning `python` in `[tools]` — the obvious first attempt. mise installs that Python, and uv ignores it and picks its own anyway. It would have been misleading config with a comment claiming something untrue, so it is not in this PR. ## Still to do elsewhere The same line belongs in the other eight repositories, since this tooling is duplicated by design. Tracked in DWA-71 rather than done here, so each repo's change is reviewable on its own.
The tools here are uv virtualenvs, and uv builds them against
/usr/bin/python3 whenever that interpreter is compatible. The OS then
replaces it: river went 3.12 -> 3.14, the packages stayed in
lib/python3.12/site-packages, and ansible-core, ansible-lint and
yamllint all died with ModuleNotFoundError while their binaries sat
there intact. `mise run lint` could not pass in any role or playbook
repository (DWA-71).

UV_PYTHON_PREFERENCE=only-managed makes uv download and own the
interpreter, which an OS upgrade cannot touch.

Verified in both directions rather than assumed: with only-system the
same install lands on /usr/bin and 3.14.4, and with only-managed it
lands in uv's own cpython-3.13 tree. mise does pass the variable through
to the tool install, which was the part worth checking.

Pinning python in [tools] was tried first and does nothing here: uv
ignores mise's interpreter and picks its own.
mgbruin force-pushed pin-uv-managed-python from 44ed466c82 to 448653c4ba 2026-09-21 20:21:08 +00:00 Compare
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
mgbruin/ansible_role_container_metrics!2
No description provided.