Changes
- Error, warning, and help messages now state what pipx found and what to run next, without hedges such as "already seems to be installed" or "Perhaps". Update scripts that match the old message text (#2376) by @gaborbernat.
Bug fixes
- A pipx that changed its own environment, through
pipx upgrade pipxorpipx reinstall pipxfor example, no longer crashes with anImportErrorwhen another pipx command empties the trash while it is still running, such as during the rest ofpipx upgrade-all. The copy of its environment it imports from now stays in the trash until the process exits (#2397) by @gaborbernat. - Interrupting a parallel
pipx reinstall-allwith Ctrl-C now gives a restored environment back the shared app, man page or completion links another environment took while the rebuild had it in the trash, as a failed rebuild already did (#2386) by @gaborbernat. - On Windows under the uv backend,
pipx run --refreshor--no-cacheof a local script no longer deletes the cached environment while another run of the same script is still executing in it, and neither does the expiry sweep. Such a run builds a throwaway environment for itself instead, and after--refreshthe next run to find the cached one idle rebuilds it (#2387) by @gaborbernat. - On Windows under the uv backend,
pipx upgrade pipxon a pipx that manages itself no longer fails withAccess is deniedand rolls back. uv deletes the files it replaces, which Windows refuses for the runningpipx.exe, so pipx now moves that launcher to its trash first, where the next pipx command deletes it (#2396) by @gaborbernat. - Where pipx copies launchers instead of linking them, as on Windows without symlink rights,
pipx reinstallandpipx install --forceno longer warnOverwriting filefor the package's own launcher. Windows.exelaunchers embed their build time, so a rebuilt one never matched its old copy byte for byte and every reinstall warned. pipx now recognises its own copy by the interpreter it names and replaces it without a warning; a file another venv or the user put there still gets one (#2394) by @gaborbernat. - With the uv backend and
UV_LINK_MODE=symlink,pipx uninstallnow removes the man page and shell completion links it exposed, andpipx listno longer reports those man pages as missing. uv makes the environment's own copies symlinks into its cache, and pipx followed them there instead of stopping at the environment (#2380) by @gaborbernat. --fetch-pythonandpipx interpreter upgradenow download and unpack the standalone Python build next to the interpreter directory instead of in the system temp dir, so a tmpfs/tmpor a/tmpon another btrfs subvolume no longer forces a full copy of the build into the pipx home or splits its hard links into separate files (#2403) by @gaborbernat.pipx inject pipxwithout--include-appsandpipx runpip pipxon a pipx that manages itself no longer mix old and new pipx code when they change the pipx package. Likepipx upgrade pipx, they now load late imports from a copy of the environment, which the next pipx command deletes from the trash (#2393) by @gaborbernat.pipx list --jsonno longer exports the interpreter a self-managed pipx recorded when that path no longer leads to the interpreter its environment runs on, such as a removed bootstrap environment'spython3.pipx install-allthen builds that environment on the default interpreter instead of whatever appears at the old path (#2389) by @gaborbernat.pipx reinstall pipxon a pipx that manages itself no longer crashes with anImportErrorwhen it installs a different pipx version. Modules the running pipx imported late came from the version it was installing, so old and new code mixed. It now loads them from its own moved environment, which the next pipx command deletes from the trash (#2377) by @gaborbernat.pipx upgrade pipx,pipx upgrade-allandpipx install --force pipxon a pipx that manages itself no longer crash with anImportErrorwhen they install a different pipx version. The running pipx now loads its late imports from a copy of its environment, which the next pipx command deletes from the trash (#2388) by @gaborbernat.- pipx now recognises the app copies it made when the environment's interpreter path is too long for a shebang line or contains a space. pip and uv start such launchers with a
#!/bin/shline that hands over to the interpreter, and pipx took/bin/shfor the interpreter, sopipx reinstallkept a stale copy and warned "File exists ... Not modifying." (#2392) by @gaborbernat.
Security
pipx runnow names its cached environments with an HMAC keyed by a random per-user secret, stored with mode0600in.run-keyinside the run cache. Before, the name was a plain hash of inputs that include tokens and proxy passwords from the environment, so another account that could list the cache could check guesses at those values against it. Existing cache entries are not reused and expire as usual (#2370) by @gaborbernat.- pipx no longer records an abbreviation of a one-shot pip option that the current pip finds ambiguous but an older pip accepts, such as
--requirem FILE, which pip 24.0 reads as--requirement FILE. With such a shared pip, a laterpipx upgradeorpipx reinstallused to replay it and install from whatever another account had put at that path. An existing record drops it when read, and an abbreviation that could name a source option such as--constraintgoes through the same replay check as that option (#2390) by @gaborbernat. - pipx no longer records an interpreter that lives inside another virtual environment, such as the
python3of an activated bootstrap environment or of one made withpython3 -m venv --copies. It records the base interpreter named in that environment'spyvenv.cfg, which outlives the bootstrap.pipx install-allalso stops building on an exported interpreter that sits inside a virtual environment or that another account can change, and uses the default Python with a message instead, so a snapshot taken before the bootstrap was removed no longer runs whatever another account later puts at its old path (#2402) by @gaborbernat.