@@ -66,7 +66,7 @@ for the name and project version (this is in theory slightly less reliable
than using the ``egg_info`` command, but avoids downloading and processing
unnecessary numbers of files).

Any URL may use the ``#egg=name`` syntax (see :ref:`VCS Support`) to
Any URL may use the ``#egg=name`` syntax (see :doc:`../topics/vcs-support`) to
explicitly state the project name.

Satisfying Requirements
@@ -372,168 +372,7 @@ that enables installation of pre-releases and development releases.
VCS Support
-----------

pip supports installing from Git, Mercurial, Subversion and Bazaar, and detects
the type of VCS using URL prefixes: ``git+``, ``hg+``, ``svn+``, and ``bzr+``.

pip requires a working VCS command on your path: ``git``, ``hg``, ``svn``, or
``bzr``.

VCS projects can be installed in :ref:`editable mode <editable-installs>` (using
the :ref:`--editable <install_--editable>` option) or not.

* For editable installs, the clone location by default is ``<venv
path>/src/SomeProject`` in virtual environments, and
``<cwd>/src/SomeProject``
for global installs. The :ref:`--src <install_--src>` option can be used to
modify this location.
* For non-editable installs, the project is built locally in a temp dir and then
installed normally. Note that if a satisfactory version of the package is
already installed, the VCS source will not overwrite it without an
``--upgrade`` flag. VCS requirements pin the package version (specified
in the ``setup.py`` file) of the target commit, not necessarily the commit
itself.
* The :ref:`pip freeze` subcommand will record the VCS requirement specifier
(referencing a specific commit) if and only if the install is done using the
editable option.

The "project name" component of the URL suffix ``egg=<project name>``
is used by pip in its dependency logic to identify the project prior
to pip downloading and analyzing the metadata. For projects
where ``setup.py`` is not in the root of project, the "subdirectory" component
is used. The value of the "subdirectory" component should be a path starting
from the root of the project to where ``setup.py`` is located.

If your repository layout is::

pkg_dir
├── setup.py # setup.py for package "pkg"
└── some_module.py
other_dir
└── some_file
some_other_file

Then, to install from this repository, the syntax would be:

.. tab:: Unix/macOS

.. code-block:: shell
python -m pip install -e "vcs+protocol://repo_url/#egg=pkg&subdirectory=pkg_dir"
.. tab:: Windows

.. code-block:: shell
py -m pip install -e "vcs+protocol://repo_url/#egg=pkg&subdirectory=pkg_dir"
Git
^^^

pip currently supports cloning over ``git``, ``git+http``, ``git+https``,
``git+ssh``, ``git+git`` and ``git+file``.

.. warning::

Note that the use of ``git``, ``git+git``, and ``git+http`` is discouraged.
The former two use `the Git Protocol`_, which lacks authentication, and HTTP is
insecure due to lack of TLS based encryption.

Here are the supported forms::

[-e] git+http://git.example.com/MyProject#egg=MyProject
[-e] git+https://git.example.com/MyProject#egg=MyProject
[-e] git+ssh://git.example.com/MyProject#egg=MyProject
[-e] git+file:///home/user/projects/MyProject#egg=MyProject

Passing a branch name, a commit hash, a tag name or a git ref is possible like so::

[-e] git+https://git.example.com/MyProject.git@main#egg=MyProject
[-e] git+https://git.example.com/MyProject.git@v1.0#egg=MyProject
[-e] git+https://git.example.com/MyProject.git@da39a3ee5e6b4b0d3255bfef95601890afd80709#egg=MyProject
[-e] git+https://git.example.com/MyProject.git@refs/pull/123/head#egg=MyProject

When passing a commit hash, specifying a full hash is preferable to a partial
hash because a full hash allows pip to operate more efficiently (e.g. by
making fewer network calls).

.. _`the Git Protocol`: https://git-scm.com/book/en/v2/Git-on-the-Server-The-Protocols

Mercurial
^^^^^^^^^

The supported schemes are: ``hg+file``, ``hg+http``, ``hg+https``,
``hg+static-http``, and ``hg+ssh``.

Here are the supported forms::

[-e] hg+http://hg.myproject.org/MyProject#egg=MyProject
[-e] hg+https://hg.myproject.org/MyProject#egg=MyProject
[-e] hg+ssh://hg.myproject.org/MyProject#egg=MyProject
[-e] hg+file:///home/user/projects/MyProject#egg=MyProject

You can also specify a revision number, a revision hash, a tag name or a local
branch name like so::

[-e] hg+http://hg.example.com/MyProject@da39a3ee5e6b#egg=MyProject
[-e] hg+http://hg.example.com/MyProject@2019#egg=MyProject
[-e] hg+http://hg.example.com/MyProject@v1.0#egg=MyProject
[-e] hg+http://hg.example.com/MyProject@special_feature#egg=MyProject

Subversion
^^^^^^^^^^

pip supports the URL schemes ``svn``, ``svn+svn``, ``svn+http``, ``svn+https``, ``svn+ssh``.

Here are some of the supported forms::

[-e] svn+https://svn.example.com/MyProject#egg=MyProject
[-e] svn+ssh://svn.example.com/MyProject#egg=MyProject
[-e] svn+ssh://user@svn.example.com/MyProject#egg=MyProject

You can also give specific revisions to an SVN URL, like so::

[-e] svn+svn://svn.example.com/svn/MyProject#egg=MyProject
[-e] svn+http://svn.example.com/svn/MyProject/trunk@2019#egg=MyProject

which will check out revision 2019. ``@{20080101}`` would also check
out the revision from 2008-01-01. You can only check out specific
revisions using ``-e svn+...``.

Bazaar
^^^^^^

pip supports Bazaar using the ``bzr+http``, ``bzr+https``, ``bzr+ssh``,
``bzr+sftp``, ``bzr+ftp`` and ``bzr+lp`` schemes.

Here are the supported forms::

[-e] bzr+http://bzr.example.com/MyProject/trunk#egg=MyProject
[-e] bzr+sftp://user@example.com/MyProject/trunk#egg=MyProject
[-e] bzr+ssh://user@example.com/MyProject/trunk#egg=MyProject
[-e] bzr+ftp://user@example.com/MyProject/trunk#egg=MyProject
[-e] bzr+lp:MyProject#egg=MyProject

Tags or revisions can be installed like so::

[-e] bzr+https://bzr.example.com/MyProject/trunk@2019#egg=MyProject
[-e] bzr+http://bzr.example.com/MyProject/trunk@v1.0#egg=MyProject

Using Environment Variables
^^^^^^^^^^^^^^^^^^^^^^^^^^^

Since version 10, pip also makes it possible to use environment variables which
makes it possible to reference private repositories without having to store
access tokens in the requirements file. For example, a private git repository
allowing Basic Auth for authentication can be refenced like this::

[-e] git+http://${AUTH_USER}:${AUTH_PASSWORD}@git.example.com/MyProject#egg=MyProject
[-e] git+https://${AUTH_USER}:${AUTH_PASSWORD}@git.example.com/MyProject#egg=MyProject

.. note::

Only ``${VARIABLE}`` is supported, other formats like ``$VARIABLE`` or
``%VARIABLE%`` won't work.
This is now covered in :doc:`../topics/vcs-support`.

Finding Packages
----------------
@@ -574,62 +413,14 @@ overridden by using ``--cert`` option or by using ``PIP_CERT``,
Caching
-------

Starting with v6.0, pip provides an on-by-default cache which functions
similarly to that of a web browser. While the cache is on by default and is
designed do the right thing by default you can disable the cache and always
access PyPI by utilizing the ``--no-cache-dir`` option.

When making any HTTP request pip will first check its local cache to determine
if it has a suitable response stored for that request which has not expired. If
it does then it simply returns that response and doesn't make the request.

If it has a response stored, but it has expired, then it will attempt to make a
conditional request to refresh the cache which will either return an empty
response telling pip to simply use the cached item (and refresh the expiration
timer) or it will return a whole new response which pip can then store in the
cache.

While this cache attempts to minimize network activity, it does not prevent
network access altogether. If you want a local install solution that
circumvents accessing PyPI, see :ref:`Installing from local packages`.

The default location for the cache directory depends on the operating system:

Unix
:file:`~/.cache/pip` and it respects the ``XDG_CACHE_HOME`` directory.
macOS
:file:`~/Library/Caches/pip`.
Windows
:file:`<CSIDL_LOCAL_APPDATA>\\pip\\Cache`

Run ``pip cache dir`` to show the cache directory and see :ref:`pip cache` to
inspect and manage pip’s cache.

This is now covered in :doc:`../topics/caching`

.. _`Wheel cache`:

Wheel Cache
^^^^^^^^^^^

pip will read from the subdirectory ``wheels`` within the pip cache directory
and use any packages found there. This is disabled via the same
``--no-cache-dir`` option that disables the HTTP cache. The internal structure
of that is not part of the pip API. As of 7.0, pip makes a subdirectory for
each sdist that wheels are built from and places the resulting wheels inside.

As of version 20.0, pip also caches wheels when building from an immutable Git
reference (i.e. a commit hash).

pip attempts to choose the best wheels from those built in preference to
building a new wheel. Note that this means when a package has both optional
C extensions and builds ``py`` tagged wheels when the C extension can't be built
that pip will not attempt to build a better wheel for Pythons that would have
supported it, once any generic wheel is built. To correct this, make sure that
the wheels are built with Python specific tags - e.g. pp on PyPy.

When no wheels are found for an sdist, pip will attempt to build a wheel
automatically and insert it into the wheel cache.

This is now covered in :doc:`../topics/caching`

.. _`hash-checking mode`:

@@ -728,9 +519,9 @@ of having the wheel cache disabled is thus extra build time for sdists, and
this can be solved by making sure pre-built wheels are available from the index
server.

Hash-checking mode also works with :ref:`pip download` and :ref:`pip wheel`. A
:ref:`comparison of hash-checking mode with other repeatability strategies
<Repeatability>` is available in the User Guide.
Hash-checking mode also works with :ref:`pip download` and :ref:`pip wheel`.
See :doc:`../topics/repeatable-installs` for a comparison of hash-checking mode
with other repeatability strategies.

.. warning::

@@ -849,7 +640,7 @@ You can install local projects or VCS projects in "editable" mode:
py -m pip install -e git+http://repo/my_project.git#egg=SomeProject
(See the :ref:`VCS Support` section above for more information on VCS-related syntax.)
(See the :doc:`../topics/vcs-support` section above for more information on VCS-related syntax.)

For local projects, the "SomeProject.egg-info" directory is created relative to
the project path. This is one advantage over just using ``setup.py develop``,
@@ -1040,7 +831,7 @@ Examples
py -m pip install SomeProject@git+https://git.repo/some_pkg.git@1.3.1
#. Install a project from VCS in "editable" mode. See the sections on :ref:`VCS Support <VCS Support>` and :ref:`Editable Installs <editable-installs>`.
#. Install a project from VCS in "editable" mode. See the sections on :doc:`../topics/vcs-support` and :ref:`Editable Installs <editable-installs>`.

.. tab:: Unix/macOS

@@ -30,7 +30,7 @@

# General information about the project.
project = "pip"
copyright = "2008-2020, PyPA"
copyright = "The pip developers"

# Find the version and release information.
# We have a single source of truth for our version number: pip's __init__.py file.
@@ -52,6 +52,10 @@
print("pip version:", version)
print("pip release:", release)

# -- Options for myst-parser ----------------------------------------------------------

myst_enable_extensions = ["deflist"]

# -- Options for smartquotes ----------------------------------------------------------

# Disable the conversion of dashes so that long options like "--find-links" won't

This file was deleted.

@@ -7,7 +7,7 @@ of all forms. The sections below will help you get started with development,
testing, and documentation.

You can also join ``#pypa`` (general packaging discussion and user support) and
``#pypa-dev`` (discussion about development of packaging tools) `on Freenode`_,
``#pypa-dev`` (discussion about development of packaging tools) `on Libera.chat`_,
or the `distutils-sig mailing list`_, to ask questions or get involved.

.. toctree::
@@ -26,5 +26,5 @@ or the `distutils-sig mailing list`_, to ask questions or get involved.
pip's development documentation has been rearranged and some older
references might be broken.

.. _`on Freenode`: https://webchat.freenode.net/?channels=%23pypa-dev,pypa
.. _`on Libera.chat`: https://kiwiirc.com/nextclient/#ircs://irc.libera.chat:+6697/pypa-dev
.. _`distutils-sig mailing list`: https://mail.python.org/mailman3/lists/distutils-sig.python.org/
@@ -0,0 +1,104 @@
# Getting Started

To get started with using pip, you should [install Python] on your system.

[install Python]: https://realpython.com/installing-python/

## Ensure you have a working pip

As a first step, you should check that you have a working Python with pip
installed. This can be done by running the following commands and making
sure that the output looks similar.

```{pip-cli}
$ python --version
Python 3.N.N
$ pip --version
pip X.Y.Z from ... (python 3.N.N)
```

If that worked, congratulations! You have a working pip in your environment.

If you got output that does not look like the sample above, please read
the {doc}`installation` page. It provides guidance on how to install pip
within a Python environment that doesn't have it.

## Common tasks

### Install a package

```{pip-cli}
$ pip install sampleproject
[...]
Successfully installed sampleproject
```

By default, pip will fetch packages from [Python Package Index][PyPI], a
repository of software for the Python programming language where anyone can
upload packages.

[PyPI]: https://pypi.org/

### Install a package from GitHub

```{pip-cli}
$ pip install git+https://github.com/pypa/sampleproject.git@main
[...]
Successfully installed sampleproject
```

See {doc}`topics/vcs-support` for more information about this syntax.

### Install a package from a distribution file

pip can install directly from distribution files as well. They come in 2 forms:

- {term}`source distribution <Source Distribution (or "sdist")>` (usually shortened to "sdist")
- {term}`wheel distribution <Wheel>` (usually shortened to "wheel")

```{pip-cli}
$ pip install sampleproject-1.0.tar.gz
[...]
Successfully installed sampleproject
$ pip install sampleproject-1.0-py3-none-any.whl
[...]
Successfully installed sampleproject
```

### Install multiple packages using a requirements file

Many Python projects use {file}`requirements.txt` files, to specify the
list of packages that need to be installed for the project to run. To install
the packages listed in that file, you can run:

```{pip-cli}
$ pip install -r requirements.txt
[...]
Successfully installed sampleproject
```

### Upgrade a package

```{pip-cli}
$ pip install --upgrade sampleproject
Uninstalling sampleproject:
[...]
Proceed (y/n)? y
Successfully uninstalled sampleproject
```

### Uninstall a package

```{pip-cli}
$ pip uninstall sampleproject
Uninstalling sampleproject:
[...]
Proceed (y/n)? y
Successfully uninstalled sampleproject
```

## Next Steps

It is recommended to learn about what virtual environments are and how to use
them. This is covered in the ["Installing Packages"](pypug:tutorials/installing-packages)
tutorial on packaging.python.org.
@@ -10,9 +10,10 @@ install packages from the [Python Package Index][pypi] and other indexes.
```{toctree}
:hidden:
quickstart
installing
getting-started
installation
user_guide
topics/index
cli/index
```

@@ -29,7 +30,7 @@ GitHub <https://github.com/pypa/pip>

If you want to learn about how to use pip, check out the following resources:

- [Quickstart](quickstart)
- [Getting Started](getting-started)
- [Python Packaging User Guide](https://packaging.python.org)

If you find bugs, need help, or want to talk to the developers, use our mailing
@@ -44,5 +45,5 @@ lists or chat rooms:
[pypi]: https://pypi.org/
[issue-tracker]: https://github.com/pypa/pip/issues/
[packaging-discourse]: https://discuss.python.org/c/packaging/14
[irc-pypa]: https://webchat.freenode.net/#pypa
[irc-pypa-dev]: https://webchat.freenode.net/#pypa-dev
[irc-pypa]: https://kiwiirc.com/nextclient/#ircs://irc.libera.chat:+6697/pypa
[irc-pypa-dev]: https://kiwiirc.com/nextclient/#ircs://irc.libera.chat:+6697/pypa-dev
@@ -0,0 +1,80 @@
# Installation

Usually, pip is automatically installed if you are:

- working in a
{ref}`virtual environment <pypug:Creating and using Virtual Environments>`
- using Python downloaded from [python.org](https://www.python.org)
- using Python that has not been modified by a redistributor to remove
{mod}`ensurepip`

## Supported Methods

If your Python environment does not have pip installed, there are 2 mechanisms
to install pip supported directly by pip's maintainers:

- [`ensurepip`](#ensurepip)
- [`get-pip.py`](#get-pip-py)

### `ensurepip`

Python comes with an {mod}`ensurepip` module[^python], which can install pip in
a Python environment.

```{pip-cli}
$ python -m ensurepip --upgrade
```

More details about how {mod}`ensurepip` works and how it can be used, is
available in the standard library documentation.

### `get-pip.py`

This is a Python script that uses some bootstrapping logic to install
pip.

- Download the script, from <https://bootstrap.pypa.io/get-pip.py>.
- Open a terminal/command prompt, `cd` to the folder containing the
`get-pip.py` file and run:

```{pip-cli}
$ python get-pip.py
```

More details about this script can be found in [pypa/get-pip]'s README.

[pypa/get-pip]: https://github.com/pypa/get-pip

## Alternative Methods

Depending on how you installed Python, there might be other mechanisms
available to you for installing pip such as
{ref}`using Linux package managers <pypug:installing pip/setuptools/wheel with linux package managers>`.

These mechanisms are provided by redistributors of pip, who may have modified
pip to change its behaviour. This has been a frequent source of user confusion,
since it causes a mismatch between documented behaviour in this documentation
and how pip works after those modifications.

If you face issues when using Python and pip installed using these mechanisms,
it is recommended to request for support from the relevant provider (eg: Linux
distro community, cloud provider support channels, etc).

(compatibility-requirements)=

## Compatibility

The current version of pip works on:

- Windows, Linux and MacOS.
- CPython 3.6, 3.7, 3.8, 3.9 and latest PyPy3.

pip is tested to work on the latest patch version of the Python interpreter,
for each of the minor versions listed above. Previous patch versions are
supported on a best effort approach.

pip's maintainers do not provide support for users on older versions of Python,
and these users should request for support from the relevant provider
(eg: Linux distro community, cloud provider support channels, etc).

[^python]: The `ensurepip` module was added to the Python standard library in Python 3.4.
@@ -1,230 +1,11 @@
.. _`Installation`:
:orphan:

============
Installation
============
.. meta::

Do I need to install pip?
=========================
:http-equiv=refresh: 3; url=../installation/

pip is already installed if you are using Python 2 >=2.7.9 or Python 3 >=3.4
downloaded from `python.org <https://www.python.org>`_ or if you are working
in a :ref:`Virtual Environment <pypug:Creating and using Virtual Environments>`
created by :ref:`pypug:virtualenv` or :ref:`venv <pypug:venv>`. Just make sure
to :ref:`upgrade pip <Upgrading pip>`.
This page has moved
===================

Use the following command to check whether pip is installed:

.. tab:: Unix/macOS

.. code-block:: console

$ python -m pip --version
pip X.Y.Z from .../site-packages/pip (python X.Y)

.. tab:: Windows

.. code-block:: console

C:\> py -m pip --version
pip X.Y.Z from ...\site-packages\pip (python X.Y)

Using Linux Package Managers
============================

.. warning::

If you installed Python from a package manager on Linux, you should always
install pip for that Python installation using the same source.

See `pypug:Installing pip/setuptools/wheel with Linux Package Managers <https://packaging.python.org/guides/installing-using-linux-tools/>`_
in the Python Packaging User Guide.

Here are ways to contact a few Linux package maintainers if you run into
problems:

* `Deadsnakes PPA <https://github.com/deadsnakes/issues>`_
* `Debian Python Team <https://wiki.debian.org/Teams/PythonTeam>`_ (for general
issues related to ``apt``)
* `Red Hat Bugzilla <https://bugzilla.redhat.com/>`_

pip developers do not have control over how Linux distributions handle pip
installations, and are unable to provide solutions to related issues in
general.

Using ensurepip
===============

Python >=3.4 can self-bootstrap pip with the built-in
:ref:`ensurepip <pypug:ensurepip>` module. Refer to the standard library
documentation for more details. Make sure to :ref:`upgrade pip <Upgrading pip>`
after ``ensurepip`` installs pip.

See the `Using Linux Package Managers`_ section if your Python reports
``No module named ensurepip`` on Debian and derived systems (e.g. Ubuntu).


.. _`get-pip`:

Installing with get-pip.py
==========================

.. warning::

Be cautious if you are using a Python install that is managed by your operating
system or another package manager. ``get-pip.py`` does not coordinate with
those tools, and may leave your system in an inconsistent state.

To manually install pip, securely [1]_ download ``get-pip.py`` by following
this link: `get-pip.py
<https://bootstrap.pypa.io/get-pip.py>`_. Alternatively, use ``curl``::

curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py

Then run the following command in the folder where you
have downloaded ``get-pip.py``:

.. tab:: Unix/macOS

.. code-block:: shell
python get-pip.py
.. tab:: Windows

.. code-block:: shell
py get-pip.py
``get-pip.py`` also installs :ref:`pypug:setuptools` [2]_ and :ref:`pypug:wheel`
if they are not already. :ref:`pypug:setuptools` is required to install
:term:`source distributions <pypug:Source Distribution (or "sdist")>`. Both are
required in order to build a :ref:`Wheel cache` (which improves installation
speed), although neither are required to install pre-built :term:`wheels
<pypug:Wheel>`.

.. note::

The get-pip.py script is supported on the same python version as pip.
For the now unsupported Python 2.6, alternate script is available
`here <https://bootstrap.pypa.io/2.6/get-pip.py>`__.


get-pip.py options
------------------

.. option:: --no-setuptools

If set, do not attempt to install :ref:`pypug:setuptools`

.. option:: --no-wheel

If set, do not attempt to install :ref:`pypug:wheel`


``get-pip.py`` allows :ref:`pip install options <pip
install Options>` and the :ref:`general options <General Options>`. Below are
some examples:

Install from local copies of pip and setuptools:

.. tab:: Unix/macOS

.. code-block:: shell
python get-pip.py --no-index --find-links=/local/copies
.. tab:: Windows

.. code-block:: shell
py get-pip.py --no-index --find-links=/local/copies
Install to the user site [3]_:

.. tab:: Unix/macOS

.. code-block:: shell
python get-pip.py --user
.. tab:: Windows

.. code-block:: shell
py get-pip.py --user
Install behind a proxy:

.. tab:: Unix/macOS

.. code-block:: shell
python get-pip.py --proxy="http://[user:passwd@]proxy.server:port"
.. tab:: Windows

.. code-block:: shell
py get-pip.py --proxy="http://[user:passwd@]proxy.server:port"
``get-pip.py`` can also be used to install a specified combination of ``pip``,
``setuptools``, and ``wheel`` using the same requirements syntax as pip:

.. tab:: Unix/macOS

.. code-block:: shell
python get-pip.py pip==9.0.2 wheel==0.30.0 setuptools==28.8.0
.. tab:: Windows

.. code-block:: shell
py get-pip.py pip==9.0.2 wheel==0.30.0 setuptools==28.8.0
.. _`Upgrading pip`:

Upgrading pip
=============

.. tab:: Unix/macOS

.. code-block:: shell
python -m pip install -U pip
.. tab:: Windows

.. code-block:: shell
py -m pip install -U pip
.. _compatibility-requirements:

Python and OS Compatibility
===========================

pip works with CPython versions 3.6, 3.7, 3.8, 3.9 and also PyPy.

This means pip works on the latest patch version of each of these minor
versions. Previous patch versions are supported on a best effort approach.

pip works on Unix/Linux, macOS, and Windows.


----

.. [1] "Secure" in this context means using a modern browser or a
tool like ``curl`` that verifies SSL certificates when downloading from
https URLs.
.. [2] Beginning with pip v1.5.1, ``get-pip.py`` stopped requiring setuptools to
be installed first.
.. [3] The pip developers are considering making ``--user`` the default for all
installs, including ``get-pip.py`` installs of pip, but at this time,
``--user`` installs for pip itself, should not be considered to be fully
tested or endorsed. For discussion, see `Issue 1668
<https://github.com/pypa/pip/issues/1668>`_.
You should be redirected automatically in 3 seconds. If that didn't
work, here's a link: :doc:`installation`

This file was deleted.

@@ -1,136 +1,11 @@
==========
Quickstart
==========
:orphan:

First, :doc:`install pip <installing>`.
.. meta::

Install a package from `PyPI`_:
:http-equiv=refresh: 3; url=../getting-started/

.. tab:: Unix/macOS
This page has moved
===================

.. code-block:: console

$ python -m pip install SomePackage
[...]
Successfully installed SomePackage

.. tab:: Windows

.. code-block:: console

C:\> py -m pip install SomePackage
[...]
Successfully installed SomePackage


Install a package that's already been downloaded from `PyPI`_ or
obtained from elsewhere. This is useful if the target machine does not have a
network connection:

.. tab:: Unix/macOS

.. code-block:: console

$ python -m pip install SomePackage-1.0-py2.py3-none-any.whl
[...]
Successfully installed SomePackage

.. tab:: Windows

.. code-block:: console

C:\> py -m pip install SomePackage-1.0-py2.py3-none-any.whl
[...]
Successfully installed SomePackage

Show what files were installed:

.. tab:: Unix/macOS

.. code-block:: console

$ python -m pip show --files SomePackage
Name: SomePackage
Version: 1.0
Location: /my/env/lib/pythonx.x/site-packages
Files:
../somepackage/__init__.py
[...]

.. tab:: Windows

.. code-block:: console

C:\> py -m pip show --files SomePackage
Name: SomePackage
Version: 1.0
Location: /my/env/lib/pythonx.x/site-packages
Files:
../somepackage/__init__.py
[...]

List what packages are outdated:

.. tab:: Unix/macOS

.. code-block:: console

$ python -m pip list --outdated
SomePackage (Current: 1.0 Latest: 2.0)

.. tab:: Windows

.. code-block:: console

C:\> py -m pip list --outdated
SomePackage (Current: 1.0 Latest: 2.0)

Upgrade a package:

.. tab:: Unix/macOS

.. code-block:: console

$ python -m pip install --upgrade SomePackage
[...]
Found existing installation: SomePackage 1.0
Uninstalling SomePackage:
Successfully uninstalled SomePackage
Running setup.py install for SomePackage
Successfully installed SomePackage

.. tab:: Windows

.. code-block:: console

C:\> py -m pip install --upgrade SomePackage
[...]
Found existing installation: SomePackage 1.0
Uninstalling SomePackage:
Successfully uninstalled SomePackage
Running setup.py install for SomePackage
Successfully installed SomePackage

Uninstall a package:

.. tab:: Unix/macOS

.. code-block:: console

$ python -m pip uninstall SomePackage
Uninstalling SomePackage:
/my/env/lib/pythonx.x/site-packages/somepackage
Proceed (y/n)? y
Successfully uninstalled SomePackage

.. tab:: Windows

.. code-block:: console

C:\> py -m pip uninstall SomePackage
Uninstalling SomePackage:
/my/env/lib/pythonx.x/site-packages/somepackage
Proceed (y/n)? y
Successfully uninstalled SomePackage

.. _PyPI: https://pypi.org/
You should be redirected automatically in 3 seconds. If that didn't
work, here's a link: :doc:`getting-started`
@@ -0,0 +1,83 @@
# Authentication

## Basic HTTP authentication

pip supports basic HTTP-based authentication credentials. This is done by
providing the username (and optionally password) in the URL:

```
https://username:password@pypi.company.com/simple
```

For indexes that only require single-part authentication tokens, provide the
token as the "username" and do not provide a password:

```
https://0123456789abcdef@pypi.company.com/simple
```

### Percent-encoding special characters

```{versionadded} 10.0
```

Certain special characters are not valid in the credential part of a URL.
If the user or password part of your login credentials contain any of these
[special characters][reserved-chars], then they must be percent-encoded. As an
example, for a user with username `user` and password `he//o` accessing a
repository at `pypi.company.com/simple`, the URL with credentials would look
like:

```
https://user:he%2F%2Fo@pypi.company.com/simple
```

[reserved-chars]: https://en.wikipedia.org/wiki/Percent-encoding#Percent-encoding_reserved_characters

## netrc support

pip supports loading credentials from a user's `.netrc` file. If no credentials
are part of the URL, pip will attempt to get authentication credentials for the
URL's hostname from the user's `.netrc` file. This behaviour comes from the
underlying use of {pypi}`requests`, which in turn delegates it to the
[Python standard library's `netrc` module][netrc-std-lib].

```{note}
As mentioned in the [standard library documentation for netrc][netrc-std-lib],
only ASCII characters are allowed in `.netrc` files. Whitespace and
non-printable characters are not allowed in passwords.
```

Below is an example `.netrc`, for the host `example.com`, with a user named
`daniel`, using the password `qwerty`:

```
machine example.com
login daniel
password qwerty
```

More information about the `.netrc` file format can be found in the GNU [`ftp`
man pages][netrc-docs].

[netrc-docs]: https://www.gnu.org/software/inetutils/manual/html_node/The-_002enetrc-file.html
[netrc-std-lib]: https://docs.python.org/3/library/netrc.html

## Keyring Support

pip supports loading credentials stored in your keyring using the
{pypi}`keyring` library.

```bash
$ pip install keyring # install keyring from PyPI
$ echo "your-password" | keyring set pypi.company.com your-username
$ pip install your-package --index-url https://pypi.company.com/
```

Note that `keyring` (the Python package) needs to be installed separately from
pip. This can create a bootstrapping issue if you need the credentials stored in
the keyring to download and install keyring.

It is, thus, expected that users that wish to use pip's keyring support have
some mechanism for downloading and installing {pypi}`keyring` in their Python
environment.
@@ -0,0 +1,86 @@
# Caching

```{versionadded} 6.0
```

pip provides an on-by-default caching, designed to reduce the amount of time
spent on duplicate downloads and builds.

## What is cached

### HTTP responses

This cache functions like a web browser cache.

When making any HTTP request, pip will first check its local cache to determine
if it has a suitable response stored for that request which has not expired. If
it does then it returns that response and doesn't re-download the content.

If it has a response stored but it has expired, then it will attempt to make a
conditional request to refresh the cache which will either return an empty
response telling pip to simply use the cached item (and refresh the expiration
timer) or it will return a whole new response which pip can then store in the
cache.

While this cache attempts to minimize network activity, it does not prevent
network access altogether. If you want a local install solution that
circumvents accessing PyPI, see {ref}`Installing from local packages`.

### Locally built wheels

pip attempts to use wheels from its local wheel cache whenever possible.

This means that if there is a cached wheel for the same version of a specific
package name, pip will use that wheel instead of rebuilding the project.

When no wheels are found for a source distribution, pip will attempt to build a
wheel using the package's build system. If the build is successful, this wheel
is added to the cache and used in subsequent installs for the same package
version.

```{versionchanged} 20.0
pip now caches wheels when building from an immutable Git reference
(i.e. a commit hash).
```

## Avoiding caching

pip tries to use its cache whenever possible, and it is designed do the right
thing by default.

In some cases, pip's caching behaviour can be undesirable. As an example, if you
have package with optional C extensions, that generates a pure Python wheel
when the C extension can’t be built, pip will use that cached wheel even when
you later invoke it from an environment that could have built those optional C
extensions. This is because pip is seeing a cached wheel for that matches the
package being built, and pip assumes that the result of building a package from
a package index is deterministic.

The recommended approach for dealing with these situations is to directly
install from a source distribution instead of letting pip auto-discover the
package when it is trying to install. Installing directly from a source
distribution will make pip build a wheel, regardless of whether there is a
matching cached wheel. This usually means doing something like:

```{pip-cli}
$ pip download sampleproject==1.0.0 --no-binary :all:
$ pip install sampleproject-1.0.0.tar.gz
```

It is also a good idea to remove the offending cached wheel using the
{ref}`pip cache` command.

## Cache management

The {ref}`pip cache` command can be used to manage pip's cache.

The exact filesystem structure of pip's cache is considered to be an
implementation detail and may change between any two versions of pip.

## Disabling caching

pip's caching behaviour is disabled by passing the ``--no-cache-dir`` option.

It is, however, recommended to **NOT** disable pip's caching. Doing so can
significantly slow down pip (due to repeated operations and package builds)
and result in significantly more network usage.
@@ -0,0 +1,226 @@
# Configuration

pip allows a user to change its behaviour via 3 mechanisms:

- command line options
- environment variables
- configuration files

This page explains how the configuration files and environment variables work,
and how they are related to pip's various command line options.

## Configuration Files

Configuration files can change the default values for command line option.
They are written using a standard INI style configuration files.

pip has 3 "levels" of configuration files:

- `global`: system-wide configuration file, shared across users.
- `user`: per-user configuration file.
- `site`: per-environment configuration file; i.e. per-virtualenv.

### Location

pip's configuration files are located in fairly standard locations. This
location is different on different operating systems, and has some additional
complexity for backwards compatibility reasons.

```{tab} Unix
Global
: {file}`/etc/pip.conf`
Alternatively, it may be in a "pip" subdirectory of any of the paths set
in the environment variable `XDG_CONFIG_DIRS` (if it exists), for
example {file}`/etc/xdg/pip/pip.conf`.
User
: {file}`$HOME/.config/pip/pip.conf`, which respects the `XDG_CONFIG_HOME` environment variable.
The legacy "per-user" configuration file is also loaded, if it exists: {file}`$HOME/.pip/pip.conf`.
Site
: {file}`$VIRTUAL_ENV/pip.conf`
```

```{tab} MacOS
Global
: {file}`/Library/Application Support/pip/pip.conf`
User
: {file}`$HOME/Library/Application Support/pip/pip.conf`
if directory `$HOME/Library/Application Support/pip` exists
else {file}`$HOME/.config/pip/pip.conf`
The legacy "per-user" configuration file is also loaded, if it exists: {file}`$HOME/.pip/pip.conf`.
Site
: {file}`$VIRTUAL_ENV/pip.conf`
```

```{tab} Windows
Global
: * On Windows 7 and later: {file}`C:\\ProgramData\\pip\\pip.ini`
(hidden but writeable)
* On Windows Vista: Global configuration is not supported.
* On Windows XP:
{file}`C:\\Documents and Settings\\All Users\\Application Data\\pip\\pip.ini`
User
: {file}`%APPDATA%\\pip\\pip.ini`
The legacy "per-user" configuration file is also loaded, if it exists: {file}`%HOME%\\pip\\pip.ini`
Site
: {file}`%VIRTUAL_ENV%\\pip.ini`
```

### `PIP_CONFIG_FILE`

Additionally, the environment variable `PIP_CONFIG_FILE` can be used to specify
a configuration file that's loaded first, and whose values are overridden by
the values set in the aforementioned files. Setting this to {any}`os.devnull`
disables the loading of _all_ configuration files.

### Loading order

When multiple configuration files are found, pip combines them in the following
order:

- `PIP_CONFIG_FILE`, if given.
- Global
- User
- Site

Each file read overrides any values read from previous files, so if the
global timeout is specified in both the global file and the per-user file
then the latter value will be used.

### Naming

The names of the settings are derived from the long command line option.

As an example, if you want to use a different package index (`--index-url`) and
set the HTTP timeout (`--default-timeout`) to 60 seconds, your config file would
look like this:

```ini
[global]
timeout = 60
index-url = https://download.zope.org/ppix
```

### Per-command section

Each subcommand can be configured optionally in its own section. This overrides
the global setting with the same name.

As an example, if you want to decrease the `timeout` to `10` seconds when
running the {ref}`pip freeze`, and use `60` seconds for all other commands:

```ini
[global]
timeout = 60
[freeze]
timeout = 10
```

### Boolean options

Boolean options like `--ignore-installed` or `--no-dependencies` can be set
like this:

```ini
[install]
ignore-installed = true
no-dependencies = yes
```

To enable the boolean options `--no-compile`, `--no-warn-script-location` and
`--no-cache-dir`, falsy values have to be used:

```ini
[global]
no-cache-dir = false
[install]
no-compile = no
no-warn-script-location = false
```

### Repeatable options

For options which can be repeated like `--verbose` and `--quiet`, a
non-negative integer can be used to represent the level to be specified:

```ini
[global]
quiet = 0
verbose = 2
```

It is possible to append values to a section within a configuration file. This
is applicable to appending options like `--find-links` or `--trusted-host`,
which can be written on multiple lines:

```ini
[global]
find-links =
http://download.example.com
[install]
find-links =
http://mirror1.example.com
http://mirror2.example.com
trusted-host =
mirror1.example.com
mirror2.example.com
```

This enables users to add additional values in the order of entry for such
command line arguments.

## Environment Variables

pip's command line options can be set with environment variables using the
format `PIP_<UPPER_LONG_NAME>` . Dashes (`-`) have to be replaced with
underscores (`_`).

- `PIP_DEFAULT_TIMEOUT=60` is the same as `--default-timeout=60`
- ```
PIP_FIND_LINKS="http://mirror1.example.com http://mirror2.example.com"
```

is the same as

```
--find-links=http://mirror1.example.com --find-links=http://mirror2.example.com
```

Repeatable options that do not take a value (such as `--verbose`) can be
specified using the number of repetitions:

- `PIP_VERBOSE=3` is the same as `pip install -vvv`

```{note}
Environment variables set to an empty string (like with `export X=` on Unix) will **not** be treated as false.
Use `no`, `false` or `0` instead.
```

## Precedence / Override order

Command line options have override environment variables, which override the
values in a configuration file. Within the configuration file, values in
command-specific sections over values in the global section.

Examples:

- `--host=foo` overrides `PIP_HOST=foo`
- `PIP_HOST=foo` overrides a config file with `[global] host = foo`
- A command specific section in the config file `[<command>] host = bar`
overrides the option with same name in the `[global]` config file section.
@@ -0,0 +1,108 @@
# Dependency Resolution

pip is capable of determining and installing the dependencies of packages. The
process of determining which version of a dependency to install is known as
dependency resolution. This behaviour can be disabled by passing
{any}`--no-deps` to {any}`pip install`.

## How it works

When a user does a `pip install` (e.g. `pip install tea`), pip needs to work
out the package's dependencies (e.g. `spoon`, `hot-water`, `tea-leaves` etc.)
and what the versions of each of those dependencies it should install.

At the start of a `pip install` run, pip does not have all the dependency
information of the requested packages. It needs to work out the dependencies
of the requested packages, the dependencies of those dependencies, and so on.
Over the course of the dependency resolution process, pip will need to download
distribution files of the packages which are used to get the dependencies of a
package.

## Backtracking

```{versionchanged} 20.3
pip's dependency resolver is now capable of backtracking.
```

During dependency resolution, pip needs to make assumptions about the package
versions it needs to install and, later, check these assumptions were not
incorrect. When pip finds that an assumption it made earlier is incorrect, it
has to backtrack, which means also discarding some of the work that has already
been done, and going back to choose another path.

This can look like pip downloading multiple versions of the same package,
since pip explicitly presents each download to the user. The backtracking of
choices made during is not unexpected behaviour or a bug. It is part of how
dependency resolution for Python packages works.

````{admonition} Example
The user requests `pip install tea`. The package `tea` declares a dependency on
`hot-water`, `spoon`, `cup`, amongst others.
pip starts by picking the most recent version of `tea` and get the list of
dependencies of that version of `tea`. It will then repeat the process for
those packages, picking the most recent version of `spoon` and then `cup`. Now,
pip notices that the version of `cup` it has chosen is not compatible with the
version of `spoon` it has chosen. Thus, pip will "go back" (backtrack) and try
to use another version of `cup`. If it is successful, it will continue onto the
next package (like `sugar`). Otherwise, it will continue to backtrack on `cup`
until it finds a version of `cup` that is compatible with all the other
packages.
This can look like:
```console
$ pip install tea
Collecting tea
Downloading tea-1.9.8-py2.py3-none-any.whl (346 kB)
|████████████████████████████████| 346 kB 10.4 MB/s
Collecting spoon==2.27.0
Downloading spoon-2.27.0-py2.py3-none-any.whl (312 kB)
|████████████████████████████████| 312 kB 19.2 MB/s
Collecting cup>=1.6.0
Downloading cup-3.22.0-py2.py3-none-any.whl (397 kB)
|████████████████████████████████| 397 kB 28.2 MB/s
INFO: pip is looking at multiple versions of this package to determine
which version is compatible with other requirements.
This could take a while.
Downloading cup-3.21.0-py2.py3-none-any.whl (395 kB)
|████████████████████████████████| 395 kB 27.0 MB/s
Downloading cup-3.20.0-py2.py3-none-any.whl (394 kB)
|████████████████████████████████| 394 kB 24.4 MB/s
Downloading cup-3.19.1-py2.py3-none-any.whl (394 kB)
|████████████████████████████████| 394 kB 21.3 MB/s
Downloading cup-3.19.0-py2.py3-none-any.whl (394 kB)
|████████████████████████████████| 394 kB 26.2 MB/s
Downloading cup-3.18.0-py2.py3-none-any.whl (393 kB)
|████████████████████████████████| 393 kB 22.1 MB/s
Downloading cup-3.17.0-py2.py3-none-any.whl (382 kB)
|████████████████████████████████| 382 kB 23.8 MB/s
Downloading cup-3.16.0-py2.py3-none-any.whl (376 kB)
|████████████████████████████████| 376 kB 27.5 MB/s
Downloading cup-3.15.1-py2.py3-none-any.whl (385 kB)
|████████████████████████████████| 385 kB 30.4 MB/s
INFO: pip is looking at multiple versions of this package to determine
which version is compatible with other requirements.
This could take a while.
Downloading cup-3.15.0-py2.py3-none-any.whl (378 kB)
|████████████████████████████████| 378 kB 21.4 MB/s
Downloading cup-3.14.0-py2.py3-none-any.whl (372 kB)
|████████████████████████████████| 372 kB 21.1 MB/s
```
These multiple `Downloading cup-{version}` lines show that pip is backtracking
choices it is making during dependency resolution.
````

If pip starts backtracking during dependency resolution, it does not know how
many choices it will reconsider, and how much computation would be needed.

For the user, this means it can take a long time to complete when pip starts
backtracking. In the case where a package has a lot of versions, arriving at a
good candidate can take a lot of time. The amount of time depends on the
package size, the number of versions pip must try, and various other factors.

Backtracking reduces the risk that installing a new package will accidentally
break an existing installed package, and so reduces the risk that your
environment gets messed up. To do this, pip has to do more work, to find out
which version of a package is a good candidate to install.
@@ -0,0 +1,19 @@
# Topic Guides

These pages provide detailed information on individual topics.

```{note}
This section of the documentation is currently being fleshed out. See
{issue}`9475` for more details.
```

```{toctree}
:maxdepth: 1
authentication
caching
configuration
dependency-resolution
repeatable-installs
vcs-support
```
@@ -0,0 +1,98 @@
# Repeatable Installs

pip can be used to achieve various levels of repeatable environments. This page
walks through increasingly stricter definitions of what "repeatable" means.

## Pinning the package versions

Pinning package versions of your dependencies in the requirements file
protects you from bugs or incompatibilities in newly released versions:

```
SomePackage == 1.2.3
DependencyOfSomePackage == 4.5.6
```

```{note}
Pinning refers to using the `==` operator to require the package to be a
specific version.
```

A requirements file, containing pinned package versions can be generated using
{ref}`pip freeze`. This would not only the top-level packages, but also all of
their transitive dependencies. Performing the installation using
{ref}`--no-deps <install_--no-deps>` would provide an extra dose of insurance
against installing anything not explicitly listed.

This strategy is easy to implement and works across OSes and architectures.
However, it trusts the locations you're fetching the packages from (like PyPI)
and the certificate authority chain. It also relies on those locations not
allowing packages to change without a version increase. (PyPI does protect
against this.)

## Hash-checking

Beyond pinning version numbers, you can add hashes against which to verify
downloaded packages:

```none
FooProject == 1.2 --hash=sha256:2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
```

This protects against a compromise of PyPI or the HTTPS certificate chain. It
also guards against a package changing without its version number changing (on
indexes that allow this). This approach is a good fit for automated server
deployments.

Hash-checking mode is a labour-saving alternative to running a private index
server containing approved packages: it removes the need to upload packages,
maintain ACLs, and keep an audit trail (which a VCS gives you on the
requirements file for free). It can also substitute for a vendored library,
providing easier upgrades and less VCS noise. It does not, of course,
provide the availability benefits of a private index or a vendored library.

[pip-tools] is a package that builds upon pip, and provides a good workflow for
managing and generating requirements files.

[pip-tools]: https://github.com/jazzband/pip-tools#readme

## Using a wheelhouse (AKA Installation Bundles)

{ref}`pip wheel` can be used to generate and package all of a project's
dependencies, with all the compilation performed, into a single directory that
can be converted into a single archive. This archive then allows installation
when index servers are unavailable and avoids time-consuming recompilation.

````{admonition} Example
Creating the bundle, on a modern Unix system:
```
$ tempdir=$(mktemp -d /tmp/wheelhouse-XXXXX)
$ python -m pip wheel -r requirements.txt --wheel-dir=$tempdir
$ cwd=`pwd`
$ (cd "$tempdir"; tar -cjvf "$cwd/bundled.tar.bz2" *)
```
Installing from the bundle, on a modern Unix system:
```
$ tempdir=$(mktemp -d /tmp/wheelhouse-XXXXX)
$ (cd $tempdir; tar -xvf /path/to/bundled.tar.bz2)
$ python -m pip install --force-reinstall --no-index --no-deps $tempdir/*
```
````

Note that such a wheelhouse contains compiled packages, which are typically
OS and architecture-specific, so these archives are not necessarily portable
across machines.

Hash-checking mode can also be used along with this method (since this uses a
requirements file as well), to ensure that future archives are built with
identical packages.

```{warning}
Beware of the `setup_requires` keyword arg in {file}`setup.py`. The (rare)
packages that use it will cause those dependencies to be downloaded by
setuptools directly, skipping pip's protections. If you need to use such a
package, see {ref}`Controlling setup_requires <controlling-setup-requires>`.
```
@@ -0,0 +1,162 @@
# VCS Support

pip supports installing from various version control systems (VCS).
This support requires a working executable to be available (for the version
control system being used). It is used through URL prefixes:

- Git -- `git+`
- Mercurial -- `hg+`
- Subversion -- `svn+`
- Bazaar -- `bzr+`

## Supported VCS

### Git

The supported schemes are `git+file`, `git+https`, `git+ssh`, `git+http`,
`git+git` and `git`. Here are some of the supported forms:

```none
git+ssh://git.example.com/MyProject#egg=MyProject
git+file:///home/user/projects/MyProject#egg=MyProject
git+https://git.example.com/MyProject#egg=MyProject
```

```{warning}
The use of `git`, `git+git`, and `git+http` schemes is discouraged.
The former two use [the Git Protocol], which lacks authentication, and HTTP is
insecure due to lack of TLS based encryption.
```

[the Git Protocol]: https://git-scm.com/book/en/v2/Git-on-the-Server-The-Protocols

It is also possible to specify a "git ref" such as branch name, a commit hash or
a tag name:

```none
git+https://git.example.com/MyProject.git@master#egg=MyProject
git+https://git.example.com/MyProject.git@v1.0#egg=MyProject
git+https://git.example.com/MyProject.git@da39a3ee5e6b4b0d3255bfef95601890afd80709#egg=MyProject
git+https://git.example.com/MyProject.git@refs/pull/123/head#egg=MyProject
```

When passing a commit hash, specifying a full hash is preferable to a partial
hash because a full hash allows pip to operate more efficiently (e.g. by
making fewer network calls).

### Mercurial

The supported schemes are `hg+file`, `hg+http`, `hg+https`, `hg+ssh`
and `hg+static-http`. Here are some of the supported forms:

```
hg+http://hg.myproject.org/MyProject#egg=MyProject
hg+https://hg.myproject.org/MyProject#egg=MyProject
hg+ssh://hg.myproject.org/MyProject#egg=MyProject
hg+file:///home/user/projects/MyProject#egg=MyProject
```

It is also possible to specify a revision number, a revision hash, a tag name
or a local branch name:

```none
hg+http://hg.example.com/MyProject@da39a3ee5e6b#egg=MyProject
hg+http://hg.example.com/MyProject@2019#egg=MyProject
hg+http://hg.example.com/MyProject@v1.0#egg=MyProject
hg+http://hg.example.com/MyProject@special_feature#egg=MyProject
```

### Subversion

The supported schemes are `svn`, `svn+svn`, `svn+http`, `svn+https` and
`svn+ssh`. Here are some of the supported forms:

```none
svn+https://svn.example.com/MyProject#egg=MyProject
svn+ssh://svn.example.com/MyProject#egg=MyProject
svn+ssh://user@svn.example.com/MyProject#egg=MyProject
```

You can also give specific revisions to an SVN URL, like so:

```none
-e svn+http://svn.example.com/svn/MyProject/trunk@2019#egg=MyProject
-e svn+http://svn.example.com/svn/MyProject/trunk@{20080101}#egg=MyProject
```

Note that you need to use [Editable VCS installs](#editable-vcs-installs) for
using specific revisions from Subversion.

### Bazaar

The supported schemes are `bzr+http`, `bzr+https`, `bzr+ssh`, `bzr+sftp`,
`bzr+ftp` and `bzr+lp`. Here are the supported forms:

```none
bzr+http://bzr.example.com/MyProject/trunk#egg=MyProject
bzr+sftp://user@example.com/MyProject/trunk#egg=MyProject
bzr+ssh://user@example.com/MyProject/trunk#egg=MyProject
bzr+ftp://user@example.com/MyProject/trunk#egg=MyProject
bzr+lp:MyProject#egg=MyProject
```

Tags or revisions can be installed like so:

```none
bzr+https://bzr.example.com/MyProject/trunk@2019#egg=MyProject
bzr+http://bzr.example.com/MyProject/trunk@v1.0#egg=MyProject
```

(editable-vcs-installs)=

## Editable VCS installs

VCS projects can be installed in {ref}`editable mode <editable-installs>` (using
the {ref}`--editable <install_--editable>` option) or not.

- The default clone location (for editable installs) is:

- `<venv path>/src/SomeProject` in virtual environments
- `<cwd>/src/SomeProject` for global Python installs

The {ref}`--src <install_--src>` option can be used to modify this location.

- For non-editable installs, the project is built locally in a temp dir and then
installed normally.

Note that if a satisfactory version of the package is already installed, the
VCS source will not overwrite it without an `--upgrade` flag. Further, pip
looks at the package version, at the target revision to determine what action to
take on the VCS requirement (not the commit itself).

The {ref}`pip freeze` subcommand will record the VCS requirement specifier
(referencing a specific commit) only if the install is done with the editable
option.

## URL fragments

pip looks at 2 fragments for VCS URLs:

- `egg`: For specifying the "project name" for use in pip's dependency
resolution logic. eg: `egg=project_name`
- `subdirectory`: For specifying the path to the Python package, when it is not
in the root of the VCS directory. eg: `pkg_dir`

````{admonition} Example
If your repository layout is:
```
pkg_dir
├── setup.py # setup.py for package "pkg"
└── some_module.py
other_dir
└── some_file
some_other_file
```
Then, to install from this repository, the syntax would be:
```{pip-cli}
$ pip install -e "vcs+protocol://repo_url/#egg=pkg&subdirectory=pkg_dir"
```
````

This file was deleted.

Large diffs are not rendered by default.

@@ -33,8 +33,7 @@
VERSION_FILE = "src/pip/__init__.py"


def run_with_protected_pip(session, *arguments):
# type: (nox.Session, *str) -> None
def run_with_protected_pip(session: nox.Session, *arguments: str) -> None:
"""Do a session.run("pip", *arguments), using a "protected" pip.
This invokes a wrapper script, that forwards calls to original virtualenv
@@ -48,8 +47,7 @@ def run_with_protected_pip(session, *arguments):
session.run(*command, env=env, silent=True)


def should_update_common_wheels():
# type: () -> bool
def should_update_common_wheels() -> bool:
# If the cache hasn't been created, create it.
if not os.path.exists(LOCATIONS["common-wheels"]):
return True
@@ -73,8 +71,7 @@ def should_update_common_wheels():
# `tox -e ...` until this note is removed.
# -----------------------------------------------------------------------------
@nox.session(python=["3.6", "3.7", "3.8", "3.9", "pypy3"])
def test(session):
# type: (nox.Session) -> None
def test(session: nox.Session) -> None:
# Get the common wheels.
if should_update_common_wheels():
# fmt: off
@@ -122,8 +119,7 @@ def test(session):


@nox.session
def docs(session):
# type: (nox.Session) -> None
def docs(session: nox.Session) -> None:
session.install("-e", ".")
session.install("-r", REQUIREMENTS["docs"])

@@ -150,8 +146,7 @@ def get_sphinx_build_command(kind):


@nox.session(name="docs-live")
def docs_live(session):
# type: (nox.Session) -> None
def docs_live(session: nox.Session) -> None:
session.install("-e", ".")
session.install("-r", REQUIREMENTS["docs"], "sphinx-autobuild")

@@ -166,8 +161,7 @@ def docs_live(session):


@nox.session
def lint(session):
# type: (nox.Session) -> None
def lint(session: nox.Session) -> None:
session.install("pre-commit")

if session.posargs:
@@ -179,8 +173,7 @@ def lint(session):


@nox.session
def vendoring(session):
# type: (nox.Session) -> None
def vendoring(session: nox.Session) -> None:
session.install("vendoring>=0.3.0")

if "--upgrade" not in session.posargs:
@@ -238,8 +231,7 @@ def pinned_requirements(path):
# Release Commands
# -----------------------------------------------------------------------------
@nox.session(name="prepare-release")
def prepare_release(session):
# type: (nox.Session) -> None
def prepare_release(session: nox.Session) -> None:
version = release.get_version_from_arguments(session)
if not version:
session.error("Usage: nox -s prepare-release -- <version>")
@@ -272,8 +264,7 @@ def prepare_release(session):


@nox.session(name="build-release")
def build_release(session):
# type: (nox.Session) -> None
def build_release(session: nox.Session) -> None:
version = release.get_version_from_arguments(session)
if not version:
session.error("Usage: nox -s build-release -- YY.N[.P]")
@@ -304,8 +295,7 @@ def build_release(session):
shutil.copy(dist, final)


def build_dists(session):
# type: (nox.Session) -> List[str]
def build_dists(session: nox.Session) -> List[str]:
"""Return dists with valid metadata."""
session.log(
"# Check if there's any Git-untracked files before building the wheel",
@@ -333,8 +323,7 @@ def build_dists(session):


@nox.session(name="upload-release")
def upload_release(session):
# type: (nox.Session) -> None
def upload_release(session: nox.Session) -> None:
version = release.get_version_from_arguments(session)
if not version:
session.error("Usage: nox -s upload-release -- YY.N[.P]")
@@ -54,7 +54,7 @@ follow_imports = skip
follow_imports = skip

[tool:pytest]
addopts = --ignore src/pip/_vendor --ignore tests/tests_cache -r aR
addopts = --ignore src/pip/_vendor --ignore tests/tests_cache -r aR --color=yes
markers =
network: tests that need network
incompatible_with_test_venv
@@ -4,17 +4,15 @@
from setuptools import find_packages, setup


def read(rel_path):
# type: (str) -> str
def read(rel_path: str) -> str:
here = os.path.abspath(os.path.dirname(__file__))
# intentionally *not* adding an encoding option to open, See:
# https://github.com/pypa/virtualenv/issues/201#issuecomment-3145690
with open(os.path.join(here, rel_path)) as fp:
return fp.read()


def get_version(rel_path):
# type: (str) -> str
def get_version(rel_path: str) -> str:
for line in read(rel_path).splitlines():
if line.startswith("__version__"):
# __version__ = "0.9"
@@ -1,10 +1,9 @@
from typing import List, Optional

__version__ = "21.1.3"
__version__ = "21.2"


def main(args=None):
# type: (Optional[List[str]]) -> int
def main(args: Optional[List[str]] = None) -> int:
"""This is an internal API only meant for use by pip's own console scripts.
For additional details, see https://github.com/pypa/pip/issues/7498.
@@ -1,10 +1,14 @@
from typing import List, Optional

import pip._internal.utils.inject_securetransport # noqa
from pip._internal.utils import _log

# init_logging() must be called before any call to logging.getLogger()
# which happens at import of most modules.
_log.init_logging()

def main(args=None):
# type: (Optional[List[str]]) -> int

def main(args: (Optional[List[str]]) = None) -> int:
"""This is preserved for old console scripts that may still be referencing
it.
@@ -14,11 +14,13 @@
from typing import TYPE_CHECKING, Iterable, Iterator, List, Optional, Set, Tuple, Type

from pip._vendor.certifi import where
from pip._vendor.pkg_resources import Requirement, VersionConflict, WorkingSet
from pip._vendor.packaging.requirements import Requirement
from pip._vendor.packaging.version import Version

from pip import __file__ as pip_location
from pip._internal.cli.spinners import open_spinner
from pip._internal.locations import get_platlib, get_prefixed_libs, get_purelib
from pip._internal.metadata import get_environment
from pip._internal.utils.subprocess import call_subprocess
from pip._internal.utils.temp_dir import TempDirectory, tempdir_kinds

@@ -167,14 +169,20 @@ def check_requirements(self, reqs):
missing = set()
conflicting = set()
if reqs:
ws = WorkingSet(self._lib_dirs)
for req in reqs:
try:
if ws.find(Requirement.parse(req)) is None:
missing.add(req)
except VersionConflict as e:
conflicting.add((str(e.args[0].as_requirement()),
str(e.args[1])))
env = get_environment(self._lib_dirs)
for req_str in reqs:
req = Requirement(req_str)
dist = env.get_distribution(req.name)
if not dist:
missing.add(req_str)
continue
if isinstance(dist.version, Version):
installed_req_str = f"{req.name}=={dist.version}"
else:
installed_req_str = f"{req.name}==={dist.version}"
if dist.version not in req.specifier:
conflicting.add((installed_req_str, req_str))
# FIXME: Consider direct URL?
return conflicting, missing

def install_requirements(
@@ -9,11 +9,10 @@

from pip._internal.cli.main_parser import create_main_parser
from pip._internal.commands import commands_dict, create_command
from pip._internal.utils.misc import get_installed_distributions
from pip._internal.metadata import get_default_environment


def autocomplete():
# type: () -> None
def autocomplete() -> None:
"""Entry Point for completion of main and subcommand options."""
# Don't complete if user hasn't sourced bash_completion file.
if "PIP_AUTO_COMPLETE" not in os.environ:
@@ -30,7 +29,7 @@ def autocomplete():
options = []

# subcommand
subcommand_name = None # type: Optional[str]
subcommand_name: Optional[str] = None
for word in cwords:
if word in subcommands:
subcommand_name = word
@@ -46,11 +45,13 @@ def autocomplete():
"uninstall",
]
if should_list_installed:
env = get_default_environment()
lc = current.lower()
installed = [
dist.key
for dist in get_installed_distributions(local_only=True)
if dist.key.startswith(lc) and dist.key not in cwords[1:]
dist.canonical_name
for dist in env.iter_installed_distributions(local_only=True)
if dist.canonical_name.startswith(lc)
and dist.canonical_name not in cwords[1:]
]
# if there are no dists installed, fall back to option completion
if installed:
@@ -107,8 +108,9 @@ def autocomplete():
sys.exit(1)


def get_path_completion_type(cwords, cword, opts):
# type: (List[str], int, Iterable[Any]) -> Optional[str]
def get_path_completion_type(
cwords: List[str], cword: int, opts: Iterable[Any]
) -> Optional[str]:
"""Get the type of path completion (``file``, ``dir``, ``path`` or None)
:param cwords: same as the environmental variable ``COMP_WORDS``
@@ -130,8 +132,7 @@ def get_path_completion_type(cwords, cword, opts):
return None


def auto_complete_paths(current, completion_type):
# type: (str, str) -> Iterable[str]
def auto_complete_paths(current: str, completion_type: str) -> Iterable[str]:
"""If ``completion_type`` is ``file`` or ``path``, list all regular files
and directories starting with ``current``; otherwise only list directories
starting with ``current``.
@@ -40,11 +40,10 @@


class Command(CommandContextMixIn):
usage = None # type: str
ignore_require_venv = False # type: bool
usage: str = ""
ignore_require_venv: bool = False

def __init__(self, name, summary, isolated=False):
# type: (str, str, bool) -> None
def __init__(self, name: str, summary: str, isolated: bool = False) -> None:
super().__init__()

self.name = name
@@ -59,7 +58,7 @@ def __init__(self, name, summary, isolated=False):
isolated=isolated,
)

self.tempdir_registry = None # type: Optional[TempDirRegistry]
self.tempdir_registry: Optional[TempDirRegistry] = None

# Commands should add options to this option group
optgroup_name = f"{self.name.capitalize()} Options"
@@ -74,12 +73,10 @@ def __init__(self, name, summary, isolated=False):

self.add_options()

def add_options(self):
# type: () -> None
def add_options(self) -> None:
pass

def handle_pip_version_check(self, options):
# type: (Values) -> None
def handle_pip_version_check(self, options: Values) -> None:
"""
This is a no-op so that commands by default do not do the pip version
check.
@@ -88,25 +85,21 @@ def handle_pip_version_check(self, options):
# are present.
assert not hasattr(options, "no_index")

def run(self, options, args):
# type: (Values, List[Any]) -> int
def run(self, options: Values, args: List[Any]) -> int:
raise NotImplementedError

def parse_args(self, args):
# type: (List[str]) -> Tuple[Any, Any]
def parse_args(self, args: List[str]) -> Tuple[Any, Any]:
# factored out for testability
return self.parser.parse_args(args)

def main(self, args):
# type: (List[str]) -> int
def main(self, args: List[str]) -> int:
try:
with self.main_context():
return self._main(args)
finally:
logging.shutdown()

def _main(self, args):
# type: (List[str]) -> int
def _main(self, args: List[str]) -> int:
# We must initialize this before the tempdir manager, otherwise the
# configuration would not be accessible by the time we clean up the
# tempdir manager.

Large diffs are not rendered by default.

@@ -5,15 +5,13 @@


class CommandContextMixIn:
def __init__(self):
# type: () -> None
def __init__(self) -> None:
super().__init__()
self._in_main_context = False
self._main_context = ExitStack()

@contextmanager
def main_context(self):
# type: () -> Iterator[None]
def main_context(self) -> Iterator[None]:
assert not self._in_main_context

self._in_main_context = True
@@ -23,8 +21,7 @@ def main_context(self):
finally:
self._in_main_context = False

def enter_context(self, context_provider):
# type: (ContextManager[_T]) -> _T
def enter_context(self, context_provider: ContextManager[_T]) -> _T:
assert self._in_main_context

return self._main_context.enter_context(context_provider)
@@ -42,8 +42,7 @@
# main, this should not be an issue in practice.


def main(args=None):
# type: (Optional[List[str]]) -> int
def main(args: Optional[List[str]] = None) -> int:
if args is None:
args = sys.argv[1:]

@@ -14,8 +14,7 @@
__all__ = ["create_main_parser", "parse_command"]


def create_main_parser():
# type: () -> ConfigOptionParser
def create_main_parser() -> ConfigOptionParser:
"""Creates and returns the main parser for pip's CLI"""

parser = ConfigOptionParser(
@@ -46,8 +45,7 @@ def create_main_parser():
return parser


def parse_command(args):
# type: (List[str]) -> Tuple[str, List[str]]
def parse_command(args: List[str]) -> Tuple[str, List[str]]:
parser = create_main_parser()

# Note: parser calls disable_interspersed_args(), so the result of this
@@ -18,20 +18,19 @@
class PrettyHelpFormatter(optparse.IndentedHelpFormatter):
"""A prettier/less verbose help formatter for optparse."""

def __init__(self, *args, **kwargs):
# type: (*Any, **Any) -> None
def __init__(self, *args: Any, **kwargs: Any) -> None:
# help position must be aligned with __init__.parseopts.description
kwargs["max_help_position"] = 30
kwargs["indent_increment"] = 1
kwargs["width"] = shutil.get_terminal_size()[0] - 2
super().__init__(*args, **kwargs)

def format_option_strings(self, option):
# type: (optparse.Option) -> str
def format_option_strings(self, option: optparse.Option) -> str:
return self._format_option_strings(option)

def _format_option_strings(self, option, mvarfmt=" <{}>", optsep=", "):
# type: (optparse.Option, str, str) -> str
def _format_option_strings(
self, option: optparse.Option, mvarfmt: str = " <{}>", optsep: str = ", "
) -> str:
"""
Return a comma-separated list of option strings and metavars.
@@ -55,23 +54,20 @@ def _format_option_strings(self, option, mvarfmt=" <{}>", optsep=", "):

return "".join(opts)

def format_heading(self, heading):
# type: (str) -> str
def format_heading(self, heading: str) -> str:
if heading == "Options":
return ""
return heading + ":\n"

def format_usage(self, usage):
# type: (str) -> str
def format_usage(self, usage: str) -> str:
"""
Ensure there is only one newline between usage and the first heading
if there is no description.
"""
msg = "\nUsage: {}\n".format(self.indent_lines(textwrap.dedent(usage), " "))
return msg

def format_description(self, description):
# type: (str) -> str
def format_description(self, description: str) -> str:
# leave full control over description to us
if description:
if hasattr(self.parser, "main"):
@@ -89,16 +85,14 @@ def format_description(self, description):
else:
return ""

def format_epilog(self, epilog):
# type: (str) -> str
def format_epilog(self, epilog: str) -> str:
# leave full control over epilog to us
if epilog:
return epilog
else:
return ""

def indent_lines(self, text, indent):
# type: (str, str) -> str
def indent_lines(self, text: str, indent: str) -> str:
new_lines = [indent + line for line in text.split("\n")]
return "\n".join(new_lines)

@@ -112,8 +106,7 @@ class UpdatingDefaultsHelpFormatter(PrettyHelpFormatter):
Also redact auth from url type options
"""

def expand_default(self, option):
# type: (optparse.Option) -> str
def expand_default(self, option: optparse.Option) -> str:
default_values = None
if self.parser is not None:
assert isinstance(self.parser, ConfigOptionParser)
@@ -137,8 +130,9 @@ def expand_default(self, option):


class CustomOptionParser(optparse.OptionParser):
def insert_option_group(self, idx, *args, **kwargs):
# type: (int, Any, Any) -> optparse.OptionGroup
def insert_option_group(
self, idx: int, *args: Any, **kwargs: Any
) -> optparse.OptionGroup:
"""Insert an OptionGroup at a given position."""
group = self.add_option_group(*args, **kwargs)

@@ -148,8 +142,7 @@ def insert_option_group(self, idx, *args, **kwargs):
return group

@property
def option_list_all(self):
# type: () -> List[optparse.Option]
def option_list_all(self) -> List[optparse.Option]:
"""Get a list of all options, including those in option groups."""
res = self.option_list[:]
for i in self.option_groups:
@@ -164,35 +157,32 @@ class ConfigOptionParser(CustomOptionParser):

def __init__(
self,
*args, # type: Any
name, # type: str
isolated=False, # type: bool
**kwargs, # type: Any
):
# type: (...) -> None
*args: Any,
name: str,
isolated: bool = False,
**kwargs: Any,
) -> None:
self.name = name
self.config = Configuration(isolated)

assert self.name
super().__init__(*args, **kwargs)

def check_default(self, option, key, val):
# type: (optparse.Option, str, Any) -> Any
def check_default(self, option: optparse.Option, key: str, val: Any) -> Any:
try:
return option.check_value(key, val)
except optparse.OptionValueError as exc:
print(f"An error occurred during configuration: {exc}")
sys.exit(3)

def _get_ordered_configuration_items(self):
# type: () -> Iterator[Tuple[str, Any]]
def _get_ordered_configuration_items(self) -> Iterator[Tuple[str, Any]]:
# Configuration gives keys in an unordered manner. Order them.
override_order = ["global", self.name, ":env:"]

# Pool the options into different groups
section_items = {
section_items: Dict[str, List[Tuple[str, Any]]] = {
name: [] for name in override_order
} # type: Dict[str, List[Tuple[str, Any]]]
}
for section_key, val in self.config.items():
# ignore empty values
if not val:
@@ -211,8 +201,7 @@ def _get_ordered_configuration_items(self):
for key, val in section_items[section]:
yield key, val

def _update_defaults(self, defaults):
# type: (Dict[str, Any]) -> Dict[str, Any]
def _update_defaults(self, defaults: Dict[str, Any]) -> Dict[str, Any]:
"""Updates the given defaults with values from the config files and
the environ. Does a little special handling for certain types of
options (lists)."""
@@ -276,8 +265,7 @@ def _update_defaults(self, defaults):
self.values = None
return defaults

def get_default_values(self):
# type: () -> optparse.Values
def get_default_values(self) -> optparse.Values:
"""Overriding to make updating the defaults after instantiation of
the option parser possible, _update_defaults() does the dirty work."""
if not self.process_default_values:
@@ -299,7 +287,6 @@ def get_default_values(self):
defaults[option.dest] = option.check_value(opt_str, default)
return optparse.Values(defaults)

def error(self, msg):
# type: (str) -> None
def error(self, msg: str) -> None:
self.print_usage(sys.stderr)
self.exit(UNKNOWN_ERROR, f"{msg}\n")
@@ -1,7 +1,7 @@
import itertools
import sys
from signal import SIGINT, default_int_handler, signal
from typing import Any, Dict, List
from typing import Any

from pip._vendor.progress.bar import Bar, FillingCirclesBar, IncrementalBar
from pip._vendor.progress.spinner import Spinner
@@ -18,8 +18,7 @@
colorama = None


def _select_progress_class(preferred, fallback):
# type: (Bar, Bar) -> Bar
def _select_progress_class(preferred: Bar, fallback: Bar) -> Bar:
encoding = getattr(preferred.file, "encoding", None)

# If we don't know what encoding this file is in, then we'll just assume
@@ -46,7 +45,7 @@ def _select_progress_class(preferred, fallback):
return preferred


_BaseBar = _select_progress_class(IncrementalBar, Bar) # type: Any
_BaseBar: Any = _select_progress_class(IncrementalBar, Bar)


class InterruptibleMixin:
@@ -67,8 +66,7 @@ class InterruptibleMixin:
download has already completed, for example.
"""

def __init__(self, *args, **kwargs):
# type: (List[Any], Dict[Any, Any]) -> None
def __init__(self, *args: Any, **kwargs: Any) -> None:
"""
Save the original SIGINT handler for later.
"""
@@ -85,8 +83,7 @@ def __init__(self, *args, **kwargs):
if self.original_handler is None:
self.original_handler = default_int_handler

def finish(self):
# type: () -> None
def finish(self) -> None:
"""
Restore the original SIGINT handler after finishing.
@@ -108,8 +105,7 @@ def handle_sigint(self, signum, frame): # type: ignore


class SilentBar(Bar):
def update(self):
# type: () -> None
def update(self) -> None:
pass


@@ -122,28 +118,24 @@ class BlueEmojiBar(IncrementalBar):


class DownloadProgressMixin:
def __init__(self, *args, **kwargs):
# type: (List[Any], Dict[Any, Any]) -> None
def __init__(self, *args: Any, **kwargs: Any) -> None:
# https://github.com/python/mypy/issues/5887
super().__init__(*args, **kwargs) # type: ignore
self.message = (" " * (get_indentation() + 2)) + self.message # type: str
self.message: str = (" " * (get_indentation() + 2)) + self.message

@property
def downloaded(self):
# type: () -> str
def downloaded(self) -> str:
return format_size(self.index) # type: ignore

@property
def download_speed(self):
# type: () -> str
def download_speed(self) -> str:
# Avoid zero division errors...
if self.avg == 0.0: # type: ignore
return "..."
return format_size(1 / self.avg) + "/s" # type: ignore

@property
def pretty_eta(self):
# type: () -> str
def pretty_eta(self) -> str:
if self.eta: # type: ignore
return f"eta {self.eta_td}" # type: ignore
return ""
@@ -158,8 +150,7 @@ def iter(self, it): # type: ignore


class WindowsMixin:
def __init__(self, *args, **kwargs):
# type: (List[Any], Dict[Any, Any]) -> None
def __init__(self, *args: Any, **kwargs: Any) -> None:
# The Windows terminal does not support the hide/show cursor ANSI codes
# even with colorama. So we'll ensure that hide_cursor is False on
# Windows.
@@ -221,14 +212,12 @@ class DownloadProgressSpinner(
file = sys.stdout
suffix = "%(downloaded)s %(download_speed)s"

def next_phase(self):
# type: () -> str
def next_phase(self) -> str:
if not hasattr(self, "_phaser"):
self._phaser = itertools.cycle(self.phases)
return next(self._phaser)

def update(self):
# type: () -> None
def update(self) -> None:
message = self.message % self
phase = self.next_phase()
suffix = self.suffix % self
@@ -50,14 +50,12 @@ class SessionCommandMixin(CommandContextMixIn):
A class mixin for command classes needing _build_session().
"""

def __init__(self):
# type: () -> None
def __init__(self) -> None:
super().__init__()
self._session = None # Optional[PipSession]
self._session: Optional[PipSession] = None

@classmethod
def _get_index_urls(cls, options):
# type: (Values) -> Optional[List[str]]
def _get_index_urls(cls, options: Values) -> Optional[List[str]]:
"""Return a list of index urls from user-provided options."""
index_urls = []
if not getattr(options, "no_index", False):
@@ -70,8 +68,7 @@ def _get_index_urls(cls, options):
# Return None rather than an empty list
return index_urls or None

def get_default_session(self, options):
# type: (Values) -> PipSession
def get_default_session(self, options: Values) -> PipSession:
"""Get a default-managed session."""
if self._session is None:
self._session = self.enter_context(self._build_session(options))
@@ -81,8 +78,12 @@ def get_default_session(self, options):
assert self._session is not None
return self._session

def _build_session(self, options, retries=None, timeout=None):
# type: (Values, Optional[int], Optional[int]) -> PipSession
def _build_session(
self,
options: Values,
retries: Optional[int] = None,
timeout: Optional[int] = None,
) -> PipSession:
assert not options.cache_dir or os.path.isabs(options.cache_dir)
session = PipSession(
cache=(
@@ -126,8 +127,7 @@ class IndexGroupCommand(Command, SessionCommandMixin):
This also corresponds to the commands that permit the pip version check.
"""

def handle_pip_version_check(self, options):
# type: (Values) -> None
def handle_pip_version_check(self, options: Values) -> None:
"""
Do the pip version check if not disabled.
@@ -154,8 +154,7 @@ def handle_pip_version_check(self, options):
]


def warn_if_run_as_root():
# type: () -> None
def warn_if_run_as_root() -> None:
"""Output a warning for sudo users on Unix.
In a virtual environment, sudo pip still writes to virtualenv.
@@ -184,19 +183,18 @@ def warn_if_run_as_root():
)


def with_cleanup(func):
# type: (Any) -> Any
def with_cleanup(func: Any) -> Any:
"""Decorator for common logic related to managing temporary
directories.
"""

def configure_tempdir_registry(registry):
# type: (TempDirectoryTypeRegistry) -> None
def configure_tempdir_registry(registry: TempDirectoryTypeRegistry) -> None:
for t in KEEPABLE_TEMPDIR_TYPES:
registry.set_delete(t, False)

def wrapper(self, options, args):
# type: (RequirementCommand, Values, List[Any]) -> Optional[int]
def wrapper(
self: RequirementCommand, options: Values, args: List[Any]
) -> Optional[int]:
assert self.tempdir_registry is not None
if options.no_clean:
configure_tempdir_registry(self.tempdir_registry)
@@ -214,15 +212,13 @@ def wrapper(self, options, args):


class RequirementCommand(IndexGroupCommand):
def __init__(self, *args, **kw):
# type: (Any, Any) -> None
def __init__(self, *args: Any, **kw: Any) -> None:
super().__init__(*args, **kw)

self.cmd_opts.add_option(cmdoptions.no_clean())

@staticmethod
def determine_resolver_variant(options):
# type: (Values) -> str
def determine_resolver_variant(options: Values) -> str:
"""Determines which resolver should be used, based on the given options."""
if "legacy-resolver" in options.deprecated_features_enabled:
return "legacy"
@@ -232,15 +228,14 @@ def determine_resolver_variant(options):
@classmethod
def make_requirement_preparer(
cls,
temp_build_dir, # type: TempDirectory
options, # type: Values
req_tracker, # type: RequirementTracker
session, # type: PipSession
finder, # type: PackageFinder
use_user_site, # type: bool
download_dir=None, # type: str
):
# type: (...) -> RequirementPreparer
temp_build_dir: TempDirectory,
options: Values,
req_tracker: RequirementTracker,
session: PipSession,
finder: PackageFinder,
use_user_site: bool,
download_dir: Optional[str] = None,
) -> RequirementPreparer:
"""
Create a RequirementPreparer instance for the given parameters.
"""
@@ -283,19 +278,18 @@ def make_requirement_preparer(
@classmethod
def make_resolver(
cls,
preparer, # type: RequirementPreparer
finder, # type: PackageFinder
options, # type: Values
wheel_cache=None, # type: Optional[WheelCache]
use_user_site=False, # type: bool
ignore_installed=True, # type: bool
ignore_requires_python=False, # type: bool
force_reinstall=False, # type: bool
upgrade_strategy="to-satisfy-only", # type: str
use_pep517=None, # type: Optional[bool]
py_version_info=None, # type: Optional[Tuple[int, ...]]
):
# type: (...) -> BaseResolver
preparer: RequirementPreparer,
finder: PackageFinder,
options: Values,
wheel_cache: Optional[WheelCache] = None,
use_user_site: bool = False,
ignore_installed: bool = True,
ignore_requires_python: bool = False,
force_reinstall: bool = False,
upgrade_strategy: str = "to-satisfy-only",
use_pep517: Optional[bool] = None,
py_version_info: Optional[Tuple[int, ...]] = None,
) -> BaseResolver:
"""
Create a Resolver instance for the given parameters.
"""
@@ -342,16 +336,15 @@ def make_resolver(

def get_requirements(
self,
args, # type: List[str]
options, # type: Values
finder, # type: PackageFinder
session, # type: PipSession
):
# type: (...) -> List[InstallRequirement]
args: List[str],
options: Values,
finder: PackageFinder,
session: PipSession,
) -> List[InstallRequirement]:
"""
Parse command-line arguments into the corresponding requirements.
"""
requirements = [] # type: List[InstallRequirement]
requirements: List[InstallRequirement] = []
for filename in options.constraints:
for parsed_req in parse_requirements(
filename,
@@ -421,8 +414,7 @@ def get_requirements(
return requirements

@staticmethod
def trace_basic_info(finder):
# type: (PackageFinder) -> None
def trace_basic_info(finder: PackageFinder) -> None:
"""
Trace basic information about the provided objects.
"""
@@ -434,12 +426,11 @@ def trace_basic_info(finder):

def _build_package_finder(
self,
options, # type: Values
session, # type: PipSession
target_python=None, # type: Optional[TargetPython]
ignore_requires_python=None, # type: Optional[bool]
):
# type: (...) -> PackageFinder
options: Values,
session: PipSession,
target_python: Optional[TargetPython] = None,
ignore_requires_python: Optional[bool] = None,
) -> PackageFinder:
"""
Create a package finder appropriate to this requirement command.
@@ -14,25 +14,22 @@


class SpinnerInterface:
def spin(self):
# type: () -> None
def spin(self) -> None:
raise NotImplementedError()

def finish(self, final_status):
# type: (str) -> None
def finish(self, final_status: str) -> None:
raise NotImplementedError()


class InteractiveSpinner(SpinnerInterface):
def __init__(
self,
message,
file=None,
spin_chars="-\\|/",
message: str,
file: IO[str] = None,
spin_chars: str = "-\\|/",
# Empirically, 8 updates/second looks nice
min_update_interval_seconds=0.125,
min_update_interval_seconds: float = 0.125,
):
# type: (str, IO[str], str, float) -> None
self._message = message
if file is None:
file = sys.stdout
@@ -45,8 +42,7 @@ def __init__(
self._file.write(" " * get_indentation() + self._message + " ... ")
self._width = 0

def _write(self, status):
# type: (str) -> None
def _write(self, status: str) -> None:
assert not self._finished
# Erase what we wrote before by backspacing to the beginning, writing
# spaces to overwrite the old text, and then backspacing again
@@ -58,16 +54,14 @@ def _write(self, status):
self._file.flush()
self._rate_limiter.reset()

def spin(self):
# type: () -> None
def spin(self) -> None:
if self._finished:
return
if not self._rate_limiter.ready():
return
self._write(next(self._spin_cycle))

def finish(self, final_status):
# type: (str) -> None
def finish(self, final_status: str) -> None:
if self._finished:
return
self._write(final_status)
@@ -81,62 +75,54 @@ def finish(self, final_status):
# act as a keep-alive for systems like Travis-CI that take lack-of-output as
# an indication that a task has frozen.
class NonInteractiveSpinner(SpinnerInterface):
def __init__(self, message, min_update_interval_seconds=60):
# type: (str, float) -> None
def __init__(self, message: str, min_update_interval_seconds: float = 60.0) -> None:
self._message = message
self._finished = False
self._rate_limiter = RateLimiter(min_update_interval_seconds)
self._update("started")

def _update(self, status):
# type: (str) -> None
def _update(self, status: str) -> None:
assert not self._finished
self._rate_limiter.reset()
logger.info("%s: %s", self._message, status)

def spin(self):
# type: () -> None
def spin(self) -> None:
if self._finished:
return
if not self._rate_limiter.ready():
return
self._update("still running...")

def finish(self, final_status):
# type: (str) -> None
def finish(self, final_status: str) -> None:
if self._finished:
return
self._update(f"finished with status '{final_status}'")
self._finished = True


class RateLimiter:
def __init__(self, min_update_interval_seconds):
# type: (float) -> None
def __init__(self, min_update_interval_seconds: float) -> None:
self._min_update_interval_seconds = min_update_interval_seconds
self._last_update = 0 # type: float
self._last_update: float = 0

def ready(self):
# type: () -> bool
def ready(self) -> bool:
now = time.time()
delta = now - self._last_update
return delta >= self._min_update_interval_seconds

def reset(self):
# type: () -> None
def reset(self) -> None:
self._last_update = time.time()


@contextlib.contextmanager
def open_spinner(message):
# type: (str) -> Iterator[SpinnerInterface]
def open_spinner(message: str) -> Iterator[SpinnerInterface]:
# Interactive spinner goes directly to sys.stdout rather than being routed
# through the logging system, but it acts like it has level INFO,
# i.e. it's only displayed if we're at level INFO or better.
# Non-interactive spinner goes through the logging system, so it is always
# in sync with logging configuration.
if sys.stdout.isatty() and logger.getEffectiveLevel() <= logging.INFO:
spinner = InteractiveSpinner(message) # type: SpinnerInterface
spinner: SpinnerInterface = InteractiveSpinner(message)
else:
spinner = NonInteractiveSpinner(message)
try:
@@ -153,8 +139,7 @@ def open_spinner(message):


@contextlib.contextmanager
def hidden_cursor(file):
# type: (IO[str]) -> Iterator[None]
def hidden_cursor(file: IO[str]) -> Iterator[None]:
# The Windows terminal does not support the hide/show cursor ANSI codes,
# even via colorama. So don't even try.
if WINDOWS:
@@ -4,7 +4,7 @@

import importlib
from collections import OrderedDict, namedtuple
from typing import Any, Optional
from typing import Any, Dict, Optional

from pip._internal.cli.base_command import Command

@@ -18,7 +18,7 @@
# in a test-related module).
# Finally, we need to pass an iterable of pairs here rather than a dict
# so that the ordering won't be lost when using Python 2.7.
commands_dict = OrderedDict([
commands_dict: Dict[str, CommandInfo] = OrderedDict([
('install', CommandInfo(
'pip._internal.commands.install', 'InstallCommand',
'Install packages.',
@@ -59,6 +59,10 @@
'pip._internal.commands.cache', 'CacheCommand',
"Inspect and manage pip's wheel cache.",
)),
('index', CommandInfo(
'pip._internal.commands.index', 'IndexCommand',
"Inspect information available from package indexes.",
)),
('wheel', CommandInfo(
'pip._internal.commands.wheel', 'WheelCommand',
'Build wheels from your requirements.',
@@ -79,11 +83,10 @@
'pip._internal.commands.help', 'HelpCommand',
'Show help for commands.',
)),
]) # type: OrderedDict[str, CommandInfo]
])


def create_command(name, **kwargs):
# type: (str, **Any) -> Command
def create_command(name: str, **kwargs: Any) -> Command:
"""
Create an instance of the Command class with the given name.
"""
@@ -95,8 +98,7 @@ def create_command(name, **kwargs):
return command


def get_similar_commands(name):
# type: (str) -> Optional[str]
def get_similar_commands(name: str) -> Optional[str]:
"""Command name auto-correct."""
from difflib import get_close_matches

@@ -1,4 +1,3 @@
import logging
import os
import textwrap
from optparse import Values
@@ -8,8 +7,9 @@
from pip._internal.cli.base_command import Command
from pip._internal.cli.status_codes import ERROR, SUCCESS
from pip._internal.exceptions import CommandError, PipError
from pip._internal.utils.logging import getLogger

logger = logging.getLogger(__name__)
logger = getLogger(__name__)


class CacheCommand(Command):
@@ -36,8 +36,7 @@ class CacheCommand(Command):
%prog purge
"""

def add_options(self):
# type: () -> None
def add_options(self) -> None:

self.cmd_opts.add_option(
'--format',
@@ -50,8 +49,7 @@ def add_options(self):

self.parser.insert_option_group(0, self.cmd_opts)

def run(self, options, args):
# type: (Values, List[Any]) -> int
def run(self, options: Values, args: List[Any]) -> int:
handlers = {
"dir": self.get_cache_dir,
"info": self.get_cache_info,
@@ -84,15 +82,13 @@ def run(self, options, args):

return SUCCESS

def get_cache_dir(self, options, args):
# type: (Values, List[Any]) -> None
def get_cache_dir(self, options: Values, args: List[Any]) -> None:
if args:
raise CommandError('Too many arguments')

logger.info(options.cache_dir)

def get_cache_info(self, options, args):
# type: (Values, List[Any]) -> None
def get_cache_info(self, options: Values, args: List[Any]) -> None:
if args:
raise CommandError('Too many arguments')

@@ -124,8 +120,7 @@ def get_cache_info(self, options, args):

logger.info(message)

def list_cache_items(self, options, args):
# type: (Values, List[Any]) -> None
def list_cache_items(self, options: Values, args: List[Any]) -> None:
if len(args) > 1:
raise CommandError('Too many arguments')

@@ -140,8 +135,7 @@ def list_cache_items(self, options, args):
else:
self.format_for_abspath(files)

def format_for_human(self, files):
# type: (List[str]) -> None
def format_for_human(self, files: List[str]) -> None:
if not files:
logger.info('Nothing cached.')
return
@@ -154,8 +148,7 @@ def format_for_human(self, files):
logger.info('Cache contents:\n')
logger.info('\n'.join(sorted(results)))

def format_for_abspath(self, files):
# type: (List[str]) -> None
def format_for_abspath(self, files: List[str]) -> None:
if not files:
return

@@ -165,8 +158,7 @@ def format_for_abspath(self, files):

logger.info('\n'.join(sorted(results)))

def remove_cache_items(self, options, args):
# type: (Values, List[Any]) -> None
def remove_cache_items(self, options: Values, args: List[Any]) -> None:
if len(args) > 1:
raise CommandError('Too many arguments')

@@ -184,27 +176,23 @@ def remove_cache_items(self, options, args):

for filename in files:
os.unlink(filename)
logger.debug('Removed %s', filename)
logger.info('Files removed: %s', len(files))
logger.verbose("Removed %s", filename)
logger.info("Files removed: %s", len(files))

def purge_cache(self, options, args):
# type: (Values, List[Any]) -> None
def purge_cache(self, options: Values, args: List[Any]) -> None:
if args:
raise CommandError('Too many arguments')

return self.remove_cache_items(options, ['*'])

def _cache_dir(self, options, subdir):
# type: (Values, str) -> str
def _cache_dir(self, options: Values, subdir: str) -> str:
return os.path.join(options.cache_dir, subdir)

def _find_http_files(self, options):
# type: (Values) -> List[str]
def _find_http_files(self, options: Values) -> List[str]:
http_dir = self._cache_dir(options, 'http')
return filesystem.find_files(http_dir, '*')

def _find_wheels(self, options, pattern):
# type: (Values, str) -> List[str]
def _find_wheels(self, options: Values, pattern: str) -> List[str]:
wheel_dir = self._cache_dir(options, 'wheels')

# The wheel filename format, as specified in PEP 427, is:
@@ -19,8 +19,7 @@ class CheckCommand(Command):
usage = """
%prog [options]"""

def run(self, options, args):
# type: (Values, List[Any]) -> int
def run(self, options: Values, args: List[Any]) -> int:

package_set, parsing_probs = create_package_set_from_installed()
missing, conflicting = check_package_set(package_set)