## File: docs/explanation/comparisons.rst ############# Comparisons ############# ************* pipx vs pip ************* - pip is a general Python package installer. It can install libraries or CLI applications with entry points. - pipx is a specialized package installer. It can only install packages with CLI entry points. - pipx and pip both install packages from PyPI (or locally). - pipx relies on pip (and venv). - pipx replaces a subset of pip's functionality: it installs CLI applications but not libraries that you import in your code. - You can install pipx with pip. Example: install pipx with pip, ``pip install --user pipx``. ***************** pipx vs uv tool ***************** Both `uv tool `_ and pipx install a Python tool into its own virtual environment and expose the tool's console scripts on ``PATH``. Both have a one-shot run mode (``uvx`` and ``pipx run``); ``uvx`` is ``uv tool run``. They differ in where state lives, which extra commands they ship, and how they handle managed Python. pipx keeps the same CLI across pip and uv backends; ``pipx install pipx[uv]`` opts you into uv-speed venv creation without changing any commands. ``uv tool`` ships a smaller per-tool surface, then reuses the rest of ``uv`` for free: managed Python, content-addressed cache, lockfiles, PEP 723 script handling. Where state lives ================= .. list-table:: :header-rows: 1 :widths: 24 38 38 - - State - pipx - uv tool - - Per-tool venvs - ``$PIPX_HOME/venvs/`` (``PIPX_HOME``) - ``$UV_TOOL_DIR/`` (``UV_TOOL_DIR``) - - Exposed binaries - ``$PIPX_BIN_DIR`` (default ``~/.local/bin``) - ``$UV_TOOL_BIN_DIR`` (default same) - - Man pages - ``$PIPX_MAN_DIR`` (default ``~/.local/share/man``) - *not exposed* - - Shared pip/setuptools/wheel - ``$PIPX_HOME/shared`` (pip backend only) - *none; uv venvs ship without pip* - - Ephemeral run cache - ``$PIPX_HOME/.cache`` (TTL 14 days) - ``$UV_CACHE_DIR`` (no TTL; ``uv cache prune``) - - Standalone Python - ``$PIPX_HOME/py`` (``PIPX_FETCH_PYTHON``) - ``$UV_PYTHON_INSTALL_DIR`` - - System-wide install - ``--global``, ``PIPX_GLOBAL_*`` - *not supported* ``PIPX_BIN_DIR`` and ``UV_TOOL_BIN_DIR`` both default to ``~/.local/bin`` on Unix, so installing the same tool with both managers writes the same filename. Each manager refuses to overwrite a binary the other one wrote without ``--force``. Use ``pipx install --suffix=...`` to keep two copies side-by-side; uv has no equivalent. Subcommand mapping ================== .. list-table:: :header-rows: 1 :widths: 26 37 37 - - Task - pipx - uv tool - - Install from PyPI - ``pipx install ruff`` - ``uv tool install ruff`` (or ``uvx ruff`` for one-off) - - Install from a git URL - ``pipx install 'git+https://…'`` - ``uv tool install 'git+https://…'`` - - Install editable from path - ``pipx install -e ./mypkg`` - ``uv tool install -e ./mypkg`` - - One-off run (no install) - ``pipx run black .`` - ``uvx black .`` - - Refresh one-off run - ``pipx run --refresh black .`` - ``uvx --refresh black .`` - - Show ephemeral cache - ``pipx cache dir`` - ``uv cache dir`` - - Purge ephemeral cache - ``pipx cache purge`` - ``uv cache clean`` - - One-off run with extra dep - ``pipx run --with mkdocs-material mkdocs`` - ``uvx --with mkdocs-material mkdocs`` - - Pinned-version one-off - ``pipx run --spec 'ruff==0.6.0' ruff check`` - ``uvx ruff@0.6.0 check`` - - Add a dep to existing tool - ``pipx inject mkdocs mkdocs-material`` - ``uv tool install mkdocs --with mkdocs-material`` (rebuilds) - - Remove an injected dep - ``pipx uninject mkdocs mkdocs-material`` - *rebuild without* ``--with`` - - Upgrade one - ``pipx upgrade ruff`` - ``uv tool upgrade ruff`` - - Upgrade all - ``pipx upgrade-all`` - ``uv tool upgrade --all`` - - List installed or outdated - ``pipx list`` (``--outdated``, ``--output json``) - ``uv tool list`` (``--show-with``, ``--outdated``, …) - - Diagnose broken environments - ``pipx health`` - *no equivalent* - - Repair broken environments - ``pipx repair ruff`` / ``repair`` - ``uv tool install ruff`` / *no bulk equivalent* - - Reinstall any environment - ``pipx reinstall ruff`` / ``reinstall-all`` - ``uv tool upgrade --reinstall ruff`` / ``--all`` - - Run pip inside a venv - ``pipx runpip -- pip ...`` - *not supported (no pip in uv venvs)* - - PATH setup - ``pipx ensurepath`` - ``uv tool update-shell`` - - Show resolved env - ``pipx environment`` - ``uv tool dir``, ``uv tool dir --bin``, ``uv cache dir``, ``uv python dir`` - - PEP 723 inline script - ``pipx run script.py`` (with uv backend uses ``uv run``) - ``uv run --script script.py`` Only in pipx ============ - ``pipx inject`` / ``uninject`` add or remove a package in place. ``uv tool install --with`` reaches the same end state by rebuilding the venv. - ``pipx runpip -- ...`` runs pip inside a tool's venv. uv venvs have no pip. - ``--include-deps`` exposes entry points from every dependency. uv requires you to enumerate dep packages with ``--with-executables-from``. - ``--suffix`` keeps two copies of the same tool side-by-side. - ``--global`` and the ``PIPX_GLOBAL_*`` variables drive a system-wide install. - Manual pages get symlinked under ``$PIPX_MAN_DIR``. - ``pipx manifest sync `` applies an explicit desired set; ``pipx manifest lock `` writes one PEP 751 lock per selected tool. - ``pipx install-all `` rebuilds every venv from a ``pipx list --output json`` snapshot for cross-machine migration. - ``[project.entry-points."pipx.run"]`` declares pipx-specific runtime extras in the package metadata. - ``pipx environment`` prints every variable and its resolved value in one place. - ``--cooldown DAYS`` provides the same release-age policy through pip and uv. Only in uv tool =============== - ``uv tool list`` toggles columns via ``--show-with``, ``--show-paths``, ``--show-version-specifiers``, ``--show-extras``, ``--show-python``. - ``uvx --with-editable PATH`` adds editable extras for a one-off run. - ``uv tool upgrade --all -p 3.13`` re-pins every tool to a different Python in one shot. - ``uv python install/list/find/pin/upgrade/uninstall`` integrates managed Python; uv auto-fetches when the requested Python isn't installed. - ``--torch-backend`` and ``--isolated`` add controls that pipx does not expose. - The content-addressed cache spans ``uv pip``, ``uv tool``, ``uv run``, and ``uv venv``. Wheels downloaded once get reused everywhere. Gotchas ======= - ``uvx`` reuses cached envs across invocations until you prune the cache (``uv cache clean``), pin a new version (``uvx black@latest``), or pass ``--refresh``. ``pipx run`` caches for 14 days and accepts ``--refresh`` for an early replacement. - ``uvx`` prefers a persistent install when one exists. After ``uv tool install ruff``, plain ``uvx ruff`` reuses that env instead of building an ephemeral one. Pass ``--isolated`` to bypass. - ``uv tool`` ignores project-local ``.python-version`` files. ``uv run`` honors them; tool envs do not. pipx never reads them; pass ``--python`` or set ``PIPX_DEFAULT_PYTHON``. - ``uv python upgrade`` only bumps patch versions. To move a tool from 3.12 to 3.13 run ``uv tool upgrade --all -p 3.13``. pipx's equivalent is ``reinstall-all --python python3.13``. - ``uv run --script`` needs a real on-disk path. When ``pipx run script.py`` content arrives via URL or named pipe, the uv backend falls back to building a venv. Picking one =========== pipx wins when you need its tool-specific extras: ``inject``/``uninject``, ``--global``, ``--suffix``, manual pages, or ``pipx install-all`` for migration. Install ``pipx[uv]`` to keep that surface and pick up uv-speed venv creation. Reach for ``uv tool`` when you already drive uv for managed Python or ``uv run --script`` and want one binary for everything. Running both is fine; the only collision point is the shared bin dir, and both sides refuse to overwrite without ``--force``. ************************** pipx vs poetry and pipenv ************************** - pipx is used solely for application consumption: you install CLI apps with it. - pipenv and poetry are CLI apps used to develop applications and libraries. - All three tools wrap pip and virtual environments for more convenient workflows. Example: install poetry with pipx, ``pipx install poetry``; run poetry without installing it, ``pipx run poetry --help``. ************** pipx vs venv ************** - venv is part of Python's standard library in Python 3.2 and above. - venv creates "virtual environments", which are sandboxed Python installations. - pipx relies heavily on the venv package. Example: pipx installs packages into environments created with venv, ``pipx install black --verbose``. *************** pipx vs pyenv *************** - pyenv manages Python versions on your system. It helps you install versions like Python 3.11, 3.12, and so on. - pipx installs packages in virtual environments and exposes their entry points on your ``PATH``. Example: install a Python interpreter with pyenv, then install a package with pipx using that interpreter, ``pipx install black --python=python3.11`` where ``python3.11`` was installed by pyenv. *************** pipx vs pipsi *************** - pipx and pipsi both install packages in a similar way. - pipx is under active development; pipsi is no longer maintained. - pipx always makes sure you're using the latest version of pip. - pipx can run an app in one line, leaving your system unchanged after it finishes (``pipx run APP``); pipsi cannot. - pipx can recursively install binaries from dependent packages. - pipx has more CLI options such as ``upgrade-all``, ``reinstall-all``, and ``uninstall-all``. - pipx is more modern. It requires Python 3.10+ and uses the standard-library ``venv`` package. - pipx works with Python homebrew installations while pipsi does not. - pipx lets you see each command it runs by passing ``--verbose``. Migrating to pipx from pipsi ============================ After you have installed pipx, run `migrate_pipsi_to_pipx.py `_. You can do this with pipx itself: .. code-block:: console $ pipx run https://raw.githubusercontent.com/pypa/pipx/main/scripts/migrate_pipsi_to_pipx.py ************** pipx vs brew ************** - Both brew and pipx install CLI tools. - They install from different sources: brew uses a curated repository specific to brew, and pipx generally uses PyPI. Example: brew can install pipx, but the two generally do not interact much. ************* pipx vs npx ************* - Both can run CLI tools. npx searches ``node_modules`` and otherwise runs in a temporary environment; ``pipx run`` searches ``__pypackages__`` and otherwise runs in a temporary environment. - npx works with JavaScript and pipx works with Python. - Both make running executables written in a dynamic language as easy as possible. - pipx can also install tools globally; npx cannot. Example: none. These tools work for different languages. ***************** pipx vs pip-run ***************** `pip-run `_ is focused on running **arbitrary Python code in ephemeral environments**, while pipx is focused on running **Python binaries in ephemeral and non-ephemeral environments**. For example, these two commands both install poetry to an ephemeral environment and invoke poetry with ``--help``: .. code-block:: bash pipx run poetry --help pip-run poetry -- -m poetry --help *************** pipx vs fades *************** `fades `_ runs **individual** Python scripts inside automatically provisioned virtualenvs with their dependencies installed. - Both `fades `_ and :doc:`pipx run <../reference/examples>` let you specify a script's dependencies in specially formatted comments, but the exact syntax differs. pipx's syntax is standardized by a `provisional specification `_; fades's syntax is not. - Both tools automatically set up reusable virtualenvs containing the necessary dependencies. - Both can download Python scripts or packages to execute from remote resources. - fades can only run individual script files while pipx can also run packages. *********************** pipx vs pae/pactivate *********************** *pae* is a Bash command-line function distributed with `pactivate `_ that uses pactivate to create non-ephemeral environments focused on general use, rather than just running command-line applications. There is a `detailed comparison `_, but to summarize: Similarities: - Both create isolated environments without having to specify (and remember) a directory in which to store them. - Both let you use any Python interpreter available on your system (subject to the version restrictions below). pae advantages: - Supports all versions of Python from 2.7 upward. pipx requires 3.10 or above. - Fewer dependencies. - Easier to have multiple versions of a single program, or use different Python versions for one program. - Somewhat more convenient for running arbitrary command-line programs in virtual environments, installing multiple packages in a single environment, and activating virtual environments. - Integrates well with source repos using `pactivate `_. pae disadvantages: - Usable with the Bash shell only. - Slightly less quick and convenient for installing or running command-line programs from single Python packages. - Can be slower than pipx at creating virtual environments. --- ## File: docs/explanation/how-pipx-works.rst ################ How pipx works ################ .. note:: This page describes the **pip backend** model, where a shared ``pip`` environment backs every managed venv through a ``.pth`` file. When the **uv backend** is active (the default whenever uv is available, via the ``pipx[uv]`` extra or on ``PATH``) pipx skips the shared environment and uses ``uv venv`` and ``uv pip`` instead; uv-created venvs ship without pip. See :doc:`../how-to/use-uv-backend`. *************************** Installing an application *************************** ``pipx install PACKAGE`` creates an isolated virtual environment under ``PIPX_HOME`` (for example ``~/.local/share/pipx/venvs/black``) and installs the package into it. Under the pip backend pipx first creates or reuses a shared environment that holds an up-to-date ``pip`` and exposes it to each managed venv through a `.pth file `_, so every venv borrows one pip rather than installing its own. Under the uv backend there is no shared environment: ``uv venv`` builds the venv (without pip) and ``uv pip`` installs into it. Once the package is installed, pipx exposes the application's resources so you can reach them from anywhere. It handles four kinds: - console and GUI scripts, into ``PIPX_BIN_DIR`` (default ``~/.local/bin``), for example ``~/.local/bin/black`` -> ``~/.local/share/pipx/venvs/black/bin/black``; - manual pages, into ``PIPX_MAN_DIR`` (default ``~/.local/share/man/man[1-9]``); - shell completion scripts, into ``PIPX_COMPLETION_DIR`` (default ``~/.local/share``). pipx symlinks each resource into place. On Windows, and on any filesystem that does not support symlinks, it copies the file instead. As long as ``PIPX_BIN_DIR`` is on your ``PATH`` the commands are available globally, and on systems with ``man`` support the pages are too. pipx records what it installed and exposed in a per-venv ``pipx_metadata.json`` file. Later commands (``upgrade``, ``reinstall``, ``expose``) read it to reproduce the same state. Adding ``--global`` to any command targets a system-wide location shared by all users instead of your home directory; the concrete paths and overrides live in :doc:`../how-to/configure-paths`. It is not available on Windows. For a ``.py`` script carrying PEP 723 metadata, pipx builds a temporary wheel from the script and its declared dependencies, installs that wheel like any other package, then records the original path or URL so ``upgrade`` and ``reinstall`` can rebuild it. .. mermaid:: flowchart LR A["pipx install black"] --> BK{"backend?"} BK -- pip --> P["shared venv (pip)reused via .pth"] BK -- uv --> U["uv venv(no pip)"] P --> C["create venvvenvs/black/"] U --> C C --> D["install packagepip install / uv pip install"] D --> E["expose apps~/.local/bin"] D --> F["expose man pages~/.local/share/man"] D --> G["expose completionsPIPX_COMPLETION_DIR"] classDef input fill:#3f72af,stroke:#28517f,color:#fff classDef decision fill:#c78c20,stroke:#8a6011,color:#fff classDef proc fill:#2a9d8f,stroke:#1c6b61,color:#fff classDef out fill:#388e3c,stroke:#256128,color:#fff class A input class BK decision class P,U,C,D proc class E,F,G out ************************* Running an application ************************* ``pipx run APP`` executes an application without installing it permanently. pipx either reuses a cached temporary venv or builds a fresh one, then invokes the app. The cache key is a hash of the package name, spec, Python version, and pip arguments; cached environments expire after 14 days, after which the next run rebuilds against the latest release. Under the pip backend the temporary venv borrows the shared pip; under the uv backend uv creates and populates it. ``pipx run --with PKG`` adds extra dependencies to that temporary environment. .. mermaid:: flowchart LR A["pipx run pycowsay"] --> C{"cachedvenv?"} C -- yes --> E["reuse cached venv"] C -- no --> BK{"backend?"} BK -- pip --> P["shared pip +python -m venv"] BK -- uv --> U["uv venv + uv pip"] P --> D["install pycowsay"] U --> D D --> F["invoke app"] E --> F classDef input fill:#3f72af,stroke:#28517f,color:#fff classDef decision fill:#c78c20,stroke:#8a6011,color:#fff classDef proc fill:#2a9d8f,stroke:#1c6b61,color:#fff classDef out fill:#388e3c,stroke:#256128,color:#fff class A input class C,BK decision class P,U,D,E proc class F out ********************** Exposing apps on PATH ********************** When you type an exposed command, the shell finds the symlink (or copy) in ``PIPX_BIN_DIR`` and follows it to the launcher inside the app's venv. That launcher runs the venv's own Python against the installed package, so the app always uses its isolated dependencies and never your system site-packages. .. mermaid:: flowchart LR U["user typesblack"] --> B["~/.local/bin/black(symlink or copy)"] B --> V["venvs/black/bin/black(launcher)"] V --> P["venv Python+ installed black"] classDef input fill:#3f72af,stroke:#28517f,color:#fff classDef proc fill:#2a9d8f,stroke:#1c6b61,color:#fff classDef out fill:#388e3c,stroke:#256128,color:#fff class U input class B,V proc class P out ****************** Directory layout ****************** pipx keeps its state under one home directory. The tree below is the conceptual shape; the concrete locations, defaults, and every override live in :doc:`../how-to/configure-paths`. .. mermaid:: flowchart TD HOME["~"] --> BIN["~/.local/bin/(on PATH)"] HOME --> DATA["~/.local/share/pipx/"] DATA --> SHARED["shared/(pip, pip backend only)"] DATA --> VENVS["venvs/"] VENVS --> V1["black/"] VENVS --> V2["poetry/"] VENVS --> V3["ruff/"] V1 --> V1BIN["bin/black"] BIN -->|symlink or copy| V1BIN classDef input fill:#3f72af,stroke:#28517f,color:#fff classDef proc fill:#2a9d8f,stroke:#1c6b61,color:#fff classDef out fill:#388e3c,stroke:#256128,color:#fff classDef venv fill:#7c4dff,stroke:#5a2fd0,color:#fff classDef shared fill:#c78c20,stroke:#8a6011,color:#fff class HOME input class DATA,VENVS proc class BIN out class SHARED shared class V1,V2,V3,V1BIN venv You can do all of this yourself; pipx automates it. Pass ``--verbose`` to see each command it runs and to stream installer output. *********************************** Resolving the Python interpreter *********************************** pipx prefers a real system Python and only downloads a standalone build as a fallback. When you pass ``--python``, it tries the value as a literal path, then as a command on ``PATH``, then as a ``pythonX.Y`` command, then through the ``py`` launcher on Windows. Only if every step fails, and ``--fetch-python`` permits it, does pipx fetch a build from `python-build-standalone `_. The default, ``--fetch-python=never``, keeps pipx offline and errors out instead. For the authoritative step-by-step order, the ``--fetch-python`` values, and when a downloaded build beats a patched system Python, see :doc:`../how-to/standalone-python`. .. mermaid:: flowchart TD S["--python VALUE"] --> A{"file exists?"} A -- yes --> USE["use interpreter"] A -- no --> B{"on PATH?shutil.which"} B -- yes --> USE B -- no --> C{"pythonX.Y?(non-Windows)"} C -- yes --> USE C -- no --> D{"py launcher?(Windows)"} D -- yes --> USE D -- no --> E{"--fetch-pythonallows download?"} E -- "missing / always" --> DL["download standalone build"] E -- "never (default)" --> ERR["error"] classDef input fill:#3f72af,stroke:#28517f,color:#fff classDef decision fill:#c78c20,stroke:#8a6011,color:#fff classDef out fill:#388e3c,stroke:#256128,color:#fff classDef err fill:#b3261e,stroke:#7a1a15,color:#fff class S input class A,B,C,D,E decision class USE,DL out class ERR err