Commit 8aaff54d authored by Donald Stufft's avatar Donald Stufft

Implement PEP 477 - Backport ensurepip (PEP 453) to 2.7

* Backports ensurepip to the 2.7 branch
* Backports some of the improved documentation to the 2.7 branch.
* Adds a private backport of the 3.x mock library as test._mock_backport
  to enable saner testing of ensurepip.

Key Differences from 3.x:

* Ensurepip does not have any Makefile integration, specifically
  it is not ran by default in the Makefile.
* There is no venv module in 2.7, so downstream distributors can
  completely disable ensurepip, ideally with a message redirecting
  to the correct way to install pip.
* To match the ``python`` command in 2.7, ensurepip will install
  the unversioned ``pip`` command as well.
* No-op and hide --default-pip and add --no-default-pip to restore
  the 3.x behavor on 2.7.
parent 04eee639
......@@ -26,6 +26,7 @@
**.psd = BIN
**.tar = BIN
**.wav = BIN
**.whl = BIN
**.xar = BIN
**.zip = BIN
......
***********************************
Software Packaging and Distribution
***********************************
These libraries help you with publishing and installing Python software.
While these modules are designed to work in conjunction with the
`Python Package Index <https://pypi.python.org>`__, they can also be used
with a local index server, or without any index server at all.
.. toctree::
distutils.rst
ensurepip.rst
:mod:`ensurepip` --- Bootstrapping the ``pip`` installer
========================================================
.. module:: ensurepip
:synopsis: Bootstrapping the ``pip`` installer into an existing Python
installation or virtual environment.
.. versionadded:: 2.7.9
The :mod:`ensurepip` package provides support for bootstrapping the ``pip``
installer into an existing Python installation or virtual environment. This
bootstrapping approach reflects the fact that ``pip`` is an independent
project with its own release cycle, and the latest available stable version
is bundled with maintenance and feature releases of the CPython reference
interpreter.
In most cases, end users of Python shouldn't need to invoke this module
directly (as ``pip`` should be bootstrapped by default), but it may be
needed if installing ``pip`` was skipped when installing Python (or
when creating a virtual environment) or after explicitly uninstalling ``pip``.
.. note::
This module *does not* access the internet. All of the components
needed to bootstrap ``pip`` are included as internal parts of the
package.
.. seealso::
:ref:`installing-index`
The end user guide for installing Python packages
:pep:`453`: Explicit bootstrapping of pip in Python installations
The original rationale and specification for this module.
:pep:`477`: Backport ensurepip (PEP 453) to Python 2.7
The rationale and specification for backporting PEP 453 to Python 2.7.
Command line interface
----------------------
The command line interface is invoked using the interpreter's ``-m`` switch.
The simplest possible invocation is::
python -m ensurepip
This invocation will install ``pip`` if it is not already installed,
but otherwise does nothing. To ensure the installed version of ``pip``
is at least as recent as the one bundled with ``ensurepip``, pass the
``--upgrade`` option::
python -m ensurepip --upgrade
By default, ``pip`` is installed into the current virtual environment
(if one is active) or into the system site packages (if there is no
active virtual environment). The installation location can be controlled
through two additional command line options:
* ``--root <dir>``: Installs ``pip`` relative to the given root directory
rather than the root of the currently active virtual environment (if any)
or the default root for the current Python installation.
* ``--user``: Installs ``pip`` into the user site packages directory rather
than globally for the current Python installation (this option is not
permitted inside an active virtual environment).
By default, the scripts ``pip``, ``pipX``, and ``pipX.Y`` will be installed
(where X.Y stands for the version of Python used to invoke ``ensurepip``). The
scripts installed can be controlled through two additional command line
options:
* ``--altinstall``: if an alternate installation is requested, the ``pip`` and
``pipX`` script will *not* be installed.
* ``--no-default-pip``: if a non-default installation is request, the ``pip``
script will *not* be installed.
Module API
----------
:mod:`ensurepip` exposes two functions for programmatic use:
.. function:: version()
Returns a string specifying the bundled version of pip that will be
installed when bootstrapping an environment.
.. function:: bootstrap(root=None, upgrade=False, user=False, \
altinstall=False, default_pip=True, \
verbosity=0)
Bootstraps ``pip`` into the current or designated environment.
*root* specifies an alternative root directory to install relative to.
If *root* is None, then installation uses the default install location
for the current environment.
*upgrade* indicates whether or not to upgrade an existing installation
of an earlier version of ``pip`` to the bundled version.
*user* indicates whether to use the user scheme rather than installing
globally.
By default, the scripts ``pip``, ``pipX``, and ``pipX.Y`` will be installed
(where X.Y stands for the current version of Python).
If *altinstall* is set, then ``pip`` and ``pipX`` will *not* be installed.
If *default_pip* is set to ``False``, then ``pip`` will *not* be installed.
Setting both *altinstall* and *default_pip* will trigger
:exc:`ValueError`.
*verbosity* controls the level of output to :data:`sys.stdout` from the
bootstrapping operation.
.. note::
The bootstrapping process has side effects on both ``sys.path`` and
``os.environ``. Invoking the command line interface in a subprocess
instead allows these side effects to be avoided.
.. note::
The bootstrapping process may install additional modules required by
``pip``, but other software should not assume those dependencies will
always be present by default (as the dependencies may be removed in a
future version of ``pip``).
......@@ -63,6 +63,7 @@ the `Python Package Index <https://pypi.python.org/pypi>`_.
tk.rst
development.rst
debug.rst
distribution.rst
python.rst
custominterp.rst
restricted.rst
......
......@@ -28,4 +28,3 @@ overview:
site.rst
user.rst
fpectl.rst
distutils.rst
......@@ -2575,6 +2575,65 @@ with the first of those changes appearing in the Python 2.7.7 release.
Gaynor; :issue:`21305`.)
PEP 477: Backport ensurepip (PEP 453) to Python 2.7
---------------------------------------------------
:pep:`477` approves the inclusion of the :pep:`453` ensurepip module and the
improved documentation that was enabled by it in the Python 2.7 maintenance
releases, appearing first in the the Python 2.7.9 release.
Bootstrapping pip By Default
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The new :mod:`ensurepip` module (defined in :pep:`453`) provides a standard
cross-platform mechanism to bootstrap the pip installer into Python
installations. The version of ``pip`` included with Python 2.7.9 is ``pip``
1.5.6, and future 2.7.x maintenance releases will update the bundled version to
the latest version of ``pip`` that is available at the time of creating the
release candidate.
By default, the commands ``pip``, ``pipX`` and ``pipX.Y`` will be installed on
all platforms (where X.Y stands for the version of the Python installation),
along with the ``pip`` Python package and its dependencies.
On Windows and Mac OS X, the CPython installers now default to installing
``pip`` along with CPython itself (users may opt out of installing it
during the installation process). Window users will need to opt in to the
automatic ``PATH`` modifications to have ``pip`` available from the command
line by default, otherwise it can still be accessed through the Python
launcher for Windows as ``py -m pip``.
As `discussed in the PEP`__, platform packagers may choose not to install
these commands by default, as long as, when invoked, they provide clear and
simple directions on how to install them on that platform (usually using
the system package manager).
__ https://www.python.org/dev/peps/pep-0477/#disabling-ensurepip-by-downstream-distributors
Documentation Changes
~~~~~~~~~~~~~~~~~~~~~
As part of this change, the :ref:`installing-index` and
:ref:`distributing-index` sections of the documentation have been
completely redesigned as short getting started and FAQ documents. Most
packaging documentation has now been moved out to the Python Packaging
Authority maintained `Python Packaging User Guide
<http://packaging.python.org>`__ and the documentation of the individual
projects.
However, as this migration is currently still incomplete, the legacy
versions of those guides remaining available as :ref:`install-index`
and :ref:`distutils-index`.
.. seealso::
:pep:`453` -- Explicit bootstrapping of pip in Python installations
PEP written by Donald Stufft and Nick Coghlan, implemented by
Donald Stufft, Nick Coghlan, Martin von Löwis and Ned Deily.
.. ======================================================================
.. _acks27:
......
#!/usr/bin/env python2
from __future__ import print_function
import os
import os.path
import pkgutil
import shutil
import sys
import tempfile
__all__ = ["version", "bootstrap"]
_SETUPTOOLS_VERSION = "3.6"
_PIP_VERSION = "1.5.6"
# pip currently requires ssl support, so we try to provide a nicer
# error message when that is missing (http://bugs.python.org/issue19744)
_MISSING_SSL_MESSAGE = ("pip {} requires SSL/TLS".format(_PIP_VERSION))
try:
import ssl
except ImportError:
ssl = None
def _require_ssl_for_pip():
raise RuntimeError(_MISSING_SSL_MESSAGE)
else:
def _require_ssl_for_pip():
pass
_PROJECTS = [
("setuptools", _SETUPTOOLS_VERSION),
("pip", _PIP_VERSION),
]
def _run_pip(args, additional_paths=None):
# Add our bundled software to the sys.path so we can import it
if additional_paths is not None:
sys.path = additional_paths + sys.path
# Install the bundled software
import pip
pip.main(args)
def version():
"""
Returns a string specifying the bundled version of pip.
"""
return _PIP_VERSION
def _disable_pip_configuration_settings():
# We deliberately ignore all pip environment variables
# when invoking pip
# See http://bugs.python.org/issue19734 for details
keys_to_remove = [k for k in os.environ if k.startswith("PIP_")]
for k in keys_to_remove:
del os.environ[k]
# We also ignore the settings in the default pip configuration file
# See http://bugs.python.org/issue20053 for details
os.environ['PIP_CONFIG_FILE'] = os.devnull
def bootstrap(root=None, upgrade=False, user=False,
altinstall=False, default_pip=True,
verbosity=0):
"""
Bootstrap pip into the current Python installation (or the given root
directory).
Note that calling this function will alter both sys.path and os.environ.
"""
if altinstall and default_pip:
raise ValueError("Cannot use altinstall and default_pip together")
_require_ssl_for_pip()
_disable_pip_configuration_settings()
# By default, installing pip and setuptools installs all of the
# following scripts (X.Y == running Python version):
#
# pip, pipX, pipX.Y, easy_install, easy_install-X.Y
#
# pip 1.5+ allows ensurepip to request that some of those be left out
if altinstall:
# omit pip, pipX and easy_install
os.environ["ENSUREPIP_OPTIONS"] = "altinstall"
elif not default_pip:
# omit pip and easy_install
os.environ["ENSUREPIP_OPTIONS"] = "install"
tmpdir = tempfile.mkdtemp()
try:
# Put our bundled wheels into a temporary directory and construct the
# additional paths that need added to sys.path
additional_paths = []
for project, version in _PROJECTS:
wheel_name = "{}-{}-py2.py3-none-any.whl".format(project, version)
whl = pkgutil.get_data(
"ensurepip",
"_bundled/{}".format(wheel_name),
)
with open(os.path.join(tmpdir, wheel_name), "wb") as fp:
fp.write(whl)
additional_paths.append(os.path.join(tmpdir, wheel_name))
# Construct the arguments to be passed to the pip command
args = ["install", "--no-index", "--find-links", tmpdir]
if root:
args += ["--root", root]
if upgrade:
args += ["--upgrade"]
if user:
args += ["--user"]
if verbosity:
args += ["-" + "v" * verbosity]
_run_pip(args + [p[0] for p in _PROJECTS], additional_paths)
finally:
shutil.rmtree(tmpdir, ignore_errors=True)
def _uninstall_helper(verbosity=0):
"""Helper to support a clean default uninstall process on Windows
Note that calling this function may alter os.environ.
"""
# Nothing to do if pip was never installed, or has been removed
try:
import pip
except ImportError:
return
# If the pip version doesn't match the bundled one, leave it alone
if pip.__version__ != _PIP_VERSION:
msg = ("ensurepip will only uninstall a matching version "
"({!r} installed, {!r} bundled)")
print(msg.format(pip.__version__, _PIP_VERSION), file=sys.stderr)
return
_require_ssl_for_pip()
_disable_pip_configuration_settings()
# Construct the arguments to be passed to the pip command
args = ["uninstall", "-y"]
if verbosity:
args += ["-" + "v" * verbosity]
_run_pip(args + [p[0] for p in reversed(_PROJECTS)])
def _main(argv=None):
if ssl is None:
print("Ignoring ensurepip failure: {}".format(_MISSING_SSL_MESSAGE),
file=sys.stderr)
return
import argparse
parser = argparse.ArgumentParser(prog="python -m ensurepip")
parser.add_argument(
"--version",
action="version",
version="pip {}".format(version()),
help="Show the version of pip that is bundled with this Python.",
)
parser.add_argument(
"-v", "--verbose",
action="count",
default=0,
dest="verbosity",
help=("Give more output. Option is additive, and can be used up to 3 "
"times."),
)
parser.add_argument(
"-U", "--upgrade",
action="store_true",
default=False,
help="Upgrade pip and dependencies, even if already installed.",
)
parser.add_argument(
"--user",
action="store_true",
default=False,
help="Install using the user scheme.",
)
parser.add_argument(
"--root",
default=None,
help="Install everything relative to this alternate root directory.",
)
parser.add_argument(
"--altinstall",
action="store_true",
default=False,
help=("Make an alternate install, installing only the X.Y versioned"
"scripts (Default: pipX, pipX.Y, easy_install-X.Y)"),
)
parser.add_argument(
"--default-pip",
action="store_true",
default=True,
dest="default_pip",
help=argparse.SUPPRESS,
)
parser.add_argument(
"--no-default-pip",
action="store_false",
dest="default_pip",
help=("Make a non default install, installing only the X and X.Y "
"versioned scripts."),
)
args = parser.parse_args(argv)
bootstrap(
root=args.root,
upgrade=args.upgrade,
user=args.user,
verbosity=args.verbosity,
altinstall=args.altinstall,
default_pip=args.default_pip,
)
import ensurepip
if __name__ == "__main__":
ensurepip._main()
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
"""Basic pip uninstallation support, helper for the Windows uninstaller"""
import argparse
import ensurepip
def _main(argv=None):
parser = argparse.ArgumentParser(prog="python -m ensurepip._uninstall")
parser.add_argument(
"--version",
action="version",
version="pip {}".format(ensurepip.version()),
help="Show the version of pip this will attempt to uninstall.",
)
parser.add_argument(
"-v", "--verbose",
action="count",
default=0,
dest="verbosity",
help=("Give more output. Option is additive, and can be used up to 3 "
"times."),
)
args = parser.parse_args(argv)
ensurepip._uninstall_helper(verbosity=args.verbosity)
if __name__ == "__main__":
_main()
This diff is collapsed.
This diff is collapsed.
......@@ -947,6 +947,7 @@ LIBSUBDIRS= lib-tk lib-tk/test lib-tk/test/test_tkinter \
test/tracedmodules \
encodings compiler hotshot \
email email/mime email/test email/test/data \
ensurepip ensurepip/_bundled \
json json/tests \
sqlite3 sqlite3/test \
logging bsddb bsddb/test csv importlib wsgiref \
......
#!/usr/bin/env python2
"""
Checks that the version of the projects bundled in ensurepip are the latest
versions available.
"""
import ensurepip
import json
import urllib2
import sys
def main():
outofdate = False
for project, version in ensurepip._PROJECTS:
data = json.loads(urllib2.urlopen(
"https://pypi.python.org/pypi/{}/json".format(project),
).read().decode("utf8"))
upstream_version = data["info"]["version"]
if version != upstream_version:
outofdate = True
print("The latest version of {} on PyPI is {}, but ensurepip "
"has {}".format(project, upstream_version, version))
if outofdate:
sys.exit(1)
if __name__ == "__main__":
main()
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment