Installing Packages

This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production.

The reference material consulted while preparing these pages is listed in the Python Reference bibliography.

pip install is pip’s central command: it turns requirements into installed distributions in one environment. This page goes through its behaviour and options for pip 26.2.2. Every example ran on CPython 3.14.6 on 2026-10-22, in a fresh venv, against PyPI on that day and the birdtally wheel built on the packaging concepts page (passed with --find-links dist). Requirement files, constraints, groups, indexes, VCS installs, builds and hashes have their own pages; see the pip landing page.

What pip install does

pip install [options] <requirement specifier> [package-index-options] ...
pip install [options] -r <requirements file> [package-index-options] ...
pip install [options] [-e] <vcs project url> ...
pip install [options] [-e] <local project path> ...
pip install [options] <archive url/path> ...
  1. Argument handling. Each argument is classified, in this order, as a project or archive URL, a local directory (which must contain pyproject.toml or setup.py), a local sdist or wheel file, or a requirement specifier.

  2. Working out the name and version. For a wheel, from the file name. For local directories and explicitly given sdists, pip asks the project’s build backend for the metadata (a PEP 517 build, see Build System Interface). For sdists found on an index, from the file name.

  3. Finding packages on the index (PyPI unless --index-url says otherwise), --find-links locations and any --extra-index-url. All locations are equal: pip takes the best version from any of them.

  4. Satisfying requirements. The resolver picks, for every package, the latest version that satisfies all constraints, excluding pre-releases by default. See Dependency Resolution.

  5. Installation order. Dependencies are installed before their dependents ("topological order", since pip 6.1), so the environment stays usable if the install fails half way. That is the only promise about order.

Requirement forms

python -m pip install birdtally                       # a name: the latest final release
python -m pip install "birdtally==0.1.0"              # a specifier
python -m pip install "birdtally[pretty]>=0.1"        # extras and a specifier
python -m pip install 'colorama; sys_platform == "win32"'   # a marker
python -m pip install ./dist/birdtally-0.1.0-py3-none-any.whl   # a local wheel or sdist
python -m pip install .                               # a local project directory
python -m pip install "birdtally @ https://example.org/birdtally-0.1.0-py3-none-any.whl"   # a direct URL
python -m pip install -r requirements.txt             # a requirements file

Quote anything with [, <, >, ; or spaces. > redirects output in every shell (pip install rich>=13 writes a file named =13), and zsh treats [pretty] as a glob, failing with no matches found before pip even runs. The syntax itself is PEP 508; see Versions & Dependency Specifiers.

Upgrades and reinstalls

Without --upgrade, an already installed version that satisfies the requirement is kept and the resolver does not even look at newer ones. The options:

Option Effect

-U, --upgrade (PIP_UPGRADE)

Allow the named packages to move to the newest allowed version.

--upgrade-strategy only-if-needed (default)

Dependencies are upgraded only if the new version of a named package needs a newer one.

--upgrade-strategy eager

Upgrade every dependency to the newest allowed version too.

--force-reinstall

Reinstall all packages even if they are up to date.

-I, --ignore-installed

Ignore what is installed and overwrite it. Can break an environment whose packages came from another installer.

--no-deps

Install only the named packages, none of their dependencies.

--ignore-requires-python

Ignore Requires-Python. Almost never correct.

With rich 13.9.4 already installed, installing birdtally with its pretty extra keeps it, because rich>=13 is satisfied:

python -m pip install "rich==13.9.4"
python -m pip install --find-links dist "birdtally[pretty]"
Looking in links: dist
Processing ./dist/birdtally-0.1.0-py3-none-any.whl
Requirement already satisfied: rich>=13 in ./.venv/lib/python3.14/site-packages (from birdtally[pretty]) (13.9.4)
Requirement already satisfied: markdown-it-py>=2.2.0 in ./.venv/lib/python3.14/site-packages (from rich>=13->birdtally[pretty]) (4.2.0)
Requirement already satisfied: pygments<3.0.0,>=2.13.0 in ./.venv/lib/python3.14/site-packages (from rich>=13->birdtally[pretty]) (2.21.0)
Requirement already satisfied: mdurl~=0.1 in ./.venv/lib/python3.14/site-packages (from markdown-it-py>=2.2.0->rich>=13->birdtally[pretty]) (0.1.2)
Installing collected packages: birdtally
Successfully installed birdtally-0.1.0

--upgrade alone still keeps rich 13.9.4 (only-if-needed); --upgrade-strategy eager replaces it:

python -m pip install --upgrade --upgrade-strategy eager --find-links dist "birdtally[pretty]"
…
    Uninstalling rich-13.9.4:
      Successfully uninstalled rich-13.9.4
Successfully installed rich-15.0.0

only-if-needed became the default in pip 10. The design notes describe a third, undocumented to-satisfy-only strategy that you should not use.

--only-deps (pip 26.2)

--only-deps installs the dependencies of the given requirements without the requirements themselves: the common "prepare an environment for this project, then mount the source" step. Extras work:

python -m pip install --only-deps "./birdtally[pretty]"
python -m pip list
Processing …/pip-flavour/birdtally
Collecting rich>=13 (from birdtally==0.1.0)
  Using cached rich-15.0.0-py3-none-any.whl.metadata (18 kB)
…
Installing collected packages: pygments, mdurl, markdown-it-py, rich

Successfully installed markdown-it-py-4.2.0 mdurl-0.1.2 pygments-2.21.0 rich-15.0.0

birdtally itself is not in pip list afterwards. The option cannot be combined with --no-deps, -r, --group or --requirements-from-script (or the legacy resolver): every package in a requirements file or group counts as user-supplied, so pip could not tell whether you mean "these packages" or "their dependencies".

python -m pip install --only-deps --group test .
ERROR: Cannot use '--only-dependencies' in combination with '--group'. If this is unexpected, please refer to the user guide:

    https://pip.pypa.io/en/stable/user_guide/#installing-only-dependencies

Poetry’s equivalent is poetry install --no-root.

Where packages go

Option Destination

(none)

The site-packages of the environment pip runs in.

--user (PIP_USER)

The user site (~/.local on Linux and macOS, %APPDATA%\Python on Windows). Not available in a venv, and subject to PEP 668 on managed Pythons.

-t, --target <dir>

A plain directory, for vendoring or bundling. Existing files are not replaced unless --upgrade is given.

--prefix <dir>

An installation prefix with its own lib/pythonX.Y/site-packages and bin. Scripts still reference pip’s interpreter.

--root <dir>

Install everything relative to an alternate root, for building distribution packages.

Inside a venv the user site is invisible, and --user fails:

ERROR: Can not perform a '--user' install. User site-packages are not visible in this virtualenv.

--target ./target and --prefix ./prefix with tomli-w produce:

target/tomli_w
target/tomli_w-1.2.0.dist-info

prefix/lib/python3.14/site-packages/tomli_w
prefix/lib/python3.14/site-packages/tomli_w-1.2.0.dist-info

Neither is checked by the PEP 668 marker, because neither installs into the interpreter’s own environment.

Pre-releases

By default pip ignores pre-releases unless nothing else satisfies a requirement. On 2026-10-22 the newest Celery was 5.7.0rc1 while the newest final release was 5.6.3:

Command celery kombu (a dependency)

pip install celery

5.6.3

5.6.2

pip install --pre celery

5.7.0rc1

5.7.0rc1

pip install --all-releases celery celery

5.7.0rc1

5.7.0rc1

pip install --all-releases :all: --only-final kombu celery

5.6.3

5.6.2

(Each row was produced with --dry-run --quiet --report - and the versions read from the report.)

  • --pre (PIP_PRE) allows pre-releases of every package.

  • --all-releases <names> (26.0) allows them for the named packages only, :all: for all, :none: to reset.

  • --only-final <names> (26.0) forbids them for the named packages, which wins over --all-releases :all:.

  • --pre cannot be combined with the other two: ERROR: --pre cannot be used with --all-releases or --only-final.

Allowing pre-releases of celery alone also pulled in kombu 5.7.0rc1, because celery 5.7.0rc1 requires a kombu pre-release explicitly, and a specifier that names a pre-release allows it. In the last row, forbidding kombu pre-releases forced pip back to the final Celery. A pre-release that is already installed is always acceptable.

Wheels or sources

Option Effect

--only-binary <names>

Never use sdists for these packages (:all: for all). PIP_ONLY_BINARY.

--no-binary <names>

Never use wheels from the index for these packages; build from source. Cached wheels may still be used.

--prefer-binary

Prefer an older wheel over a newer sdist.

docopt has only ever published an sdist, so binary-only mode cannot install it:

python -m pip install --dry-run --only-binary :all: docopt
ERROR: Could not find a version that satisfies the requirement docopt (from versions: none)
ERROR: No matching distribution found for docopt

(from versions: none) here does not mean the project is missing: every file was filtered out. Without the option pip downloads docopt-0.6.2.tar.gz and builds it. --no-binary tomli-w does the reverse and builds tomli_w-1.2.0.tar.gz although a wheel exists. Wheels are preferred because installing one runs no project code; see Packaging Concepts & Standards.

Selecting for another platform

--platform, --python-version, --implementation and --abi make pip pick wheels for a different interpreter or operating system, which is mainly useful with pip download and --target to prepare a bundle. Because pip cannot build or inspect sdists for a platform it is not running on, these options require --no-deps or --only-binary=:all::

python -m pip download --platform win_amd64 -d w2 tomli
ERROR: When restricting platform and interpreter constraints using --python-version, --platform, --abi, or --implementation, either --no-deps must be set, or --only-binary=:all: must be set and --no-binary must not be set (or must be set to :none:).
python -m pip download --no-deps --only-binary :all: --platform win_amd64 --python-version 3.13 --implementation cp -d winwheels "tomli==2.5.0"
ls winwheels
Saved ./winwheels/tomli-2.5.0-cp313-cp313-win_amd64.whl
Successfully downloaded tomli
tomli-2.5.0-cp313-cp313-win_amd64.whl

Time and freshness: --uploaded-prior-to and --refresh-package

--uploaded-prior-to (26.0, durations such as P3D since 26.1) hides files uploaded after a date or more recently than a number of days, as a cooldown against compromised releases or to reproduce an old resolution. --refresh-package <names> (26.2) bypasses the cached index page for those packages; it is needed since 26.2 because pip now honours the index’s Cache-Control headers, so a release published a minute ago may not be visible yet. Both are demonstrated on Supply-Chain Security.

--dry-run and the installation report

--dry-run (22.2) resolves and prints Would install … without changing anything. --report <file> (22.2, format version 1 stable since 23.0) writes a JSON description of what pip installed or would install; - writes it to standard output, in which case add --quiet so that log lines do not mix with the JSON. With --ignore-installed the report describes a full resolution regardless of what is installed:

python -m pip install --dry-run --ignore-installed --quiet --report - --find-links dist "birdtally[pretty]" > report.json

The top level holds version, pip_version, the marker environment and the install array. The first two items, with the metadata trimmed and the hashes shortened:

{
  "download_info": {
    "url": "file://…/dist/birdtally-0.1.0-py3-none-any.whl",
    "archive_info": {
      "hashes": {
        "sha256": "35a50693…9984a56b5a"
      },
      "hash": "sha256=35a5069350968616bed7f40135c5594911438241543d3b4a03fa389984a56b5a"
    }
  },
  "is_direct": false,
  "is_yanked": false,
  "requested": true,
  "requested_extras": [
    "pretty"
  ],
  "metadata": {
    "metadata_version": "2.5",
    "name": "birdtally",
    "version": "0.1.0",
    "requires_dist": [
      "rich>=13; extra == 'pretty'"
    ],
    "provides_extra": [
      "pretty"
    ]
  }
}
{
  "download_info": {
    "url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl",
    "archive_info": {
      "hashes": {
        "sha256": "33bd4ef7…e27de0bb"
      },
      "hash": "sha256=33bd4ef74232fb73fe9279a257718407f169c09b78a87ad3d296f548e27de0bb"
    }
  },
  "is_direct": false,
  "is_yanked": false,
  "requested": false
}
  • requested is true for what you asked for (on the command line or in a requirements file), false for dependencies, and requested_extras appears only on requested items.

  • is_direct is true for direct URL requirements; download_info then equals the future direct_url.json.

  • is_yanked (23.3) flags a yanked file that pip still selected because it was pinned exactly.

  • metadata is the full core metadata as JSON, including the PEP 639 licence fields since pip 25.0.

The documentation is explicit that the report is "not meant to be a lock file format": it describes one resolution on one platform. Use pip lock or poetry.lock for that.

Bytecode and root

--compile (the default) byte-compiles the installed .py files; --no-compile skips it, which saves time and space in images where the files are compiled on first import anyway. --no-warn-script-location silences the warning that a console script went into a directory that is not on PATH, and --no-warn-conflicts the conflict warning described next. --root-user-action ignore silences the warning about running as root.

The consistency pitfall: pip install x, then pip install y

Each pip install resolves only the requirements it is given, together with what they need. It does not re-check every package already installed. A second command can therefore break the first:

python -m pip install "rich==15.0.0"
python -m pip install "markdown-it-py<2"
python -m pip check; echo "exit=$?"
ERROR: pip's dependency resolver does not currently take into account all the packages that are installed. This behaviour is the source of the following dependency conflicts.
rich 15.0.0 requires markdown-it-py>=2.2.0, but you have markdown-it-py 1.1.0 which is incompatible.
Successfully installed attrs-21.4.0 markdown-it-py-1.1.0
rich 15.0.0 has requirement markdown-it-py>=2.2.0, but you have markdown-it-py 1.1.0.
exit=1

The install succeeds with a warning; only pip check (exit code 1) turns it into a failure. Worse, extras are invisible to the check: after pip install "birdtally[pretty]", pip install "rich<13" installed rich 12.6.0 and pip check printed No broken requirements found., because pip does not record which extras were requested. The cure is to install everything an environment needs in one command (a requirements file, a lock file or a group) and to run pip check in CI. Poetry avoids the problem by resolving the whole project every time; see Poetry: Lock File, install, update & sync.

pip and Poetry

pip Poetry

pip install rich

poetry add rich (records it in pyproject.toml and the lock)

pip install -U rich

poetry update rich

pip install --only-deps .

poetry install --no-root

pip install --pre celery

poetry add celery --allow-prereleases

pip install --dry-run

poetry install --dry-run, poetry add --dry-run

--only-binary / --no-binary

installer.only-binary / installer.no-binary settings