diff --git a/Doc/library/development.rst b/Doc/library/development.rst
index 2368769..06e7048 100644
--- a/Doc/library/development.rst
+++ b/Doc/library/development.rst
@@ -23,4 +23,3 @@ The list of modules described in this chapter is:
unittest.mock-examples.rst
2to3.rst
test.rst
- venv.rst
diff --git a/Doc/library/distribution.rst b/Doc/library/distribution.rst
new file mode 100644
index 0000000..fb3f5df
--- /dev/null
+++ b/Doc/library/distribution.rst
@@ -0,0 +1,14 @@
+***********************************
+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 `__, they can also be used
+with a local index server, or without any index server at all.
+
+.. toctree::
+
+ distutils.rst
+ ensurepip.rst
+ venv.rst
diff --git a/Doc/library/ensurepip.rst b/Doc/library/ensurepip.rst
new file mode 100644
index 0000000..7a75ee3
--- /dev/null
+++ b/Doc/library/ensurepip.rst
@@ -0,0 +1,92 @@
+:mod:`ensurepip` --- Bootstrapping the ``pip`` installer
+========================================================
+
+.. module:: ensurepip
+ :synopsis: Bootstrapping the ``pip`` installer into an existing Python
+ installation or virtual environment.
+
+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``.
+
+.. versionadded:: 3.4
+
+.. 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:`install-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.
+
+
+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 ``: 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).
+
+
+Module API
+----------
+
+:mod:`ensurepip` expose 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, 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.
+
+ *verbosity* controls the level of output to :data:`sys.stdout` from the
+ bootstrapping operation.
diff --git a/Doc/library/index.rst b/Doc/library/index.rst
index 1b25c6e..81289a5 100644
--- a/Doc/library/index.rst
+++ b/Doc/library/index.rst
@@ -65,6 +65,7 @@ the `Python Package Index `_.
tk.rst
development.rst
debug.rst
+ distribution.rst
python.rst
custominterp.rst
modules.rst
diff --git a/Doc/library/python.rst b/Doc/library/python.rst
index b67fbfc..f307d7d 100644
--- a/Doc/library/python.rst
+++ b/Doc/library/python.rst
@@ -25,4 +25,3 @@ overview:
inspect.rst
site.rst
fpectl.rst
- distutils.rst
diff --git a/Lib/ensurepip/__init__.py b/Lib/ensurepip/__init__.py
new file mode 100644
index 0000000..9288ea4
--- /dev/null
+++ b/Lib/ensurepip/__init__.py
@@ -0,0 +1,74 @@
+import os.path
+import pkgutil
+import sys
+import tempfile
+
+# TODO: Remove the --pre flag when a pip 1.5 final copy is available
+
+
+__all__ = ["version", "bootstrap"]
+
+
+_SETUPTOOLS_VERSION = "1.1.6"
+
+_PIP_VERSION = "1.5.dev1"
+
+_PROJECTS = [
+ ("setuptools", _SETUPTOOLS_VERSION),
+ ("pip", _PIP_VERSION),
+]
+
+
+def _run_pip(basepath, args):
+ # Add our bundled software to the sys.path so we can import it
+ for project, version in _PROJECTS:
+ sys.path.insert(0, os.path.join(
+ basepath,
+ "{}-{}-py2.py3-none-any.whl".format(project, version),
+ ))
+
+ # Install the bundled software
+ import pip
+ pip.main(args)
+
+
+def version():
+ """
+ Returns a string specifying the bundled version of pip.
+ """
+ return _PIP_VERSION
+
+
+def bootstrap(root=None, upgrade=False, user=False, verbosity=0):
+ """
+ Bootstrap pip into the current Python installation (or the given root
+ directory).
+ """
+ with tempfile.TemporaryDirectory() as tmpdir:
+ # Put our bundled wheels into a temporary directory
+ 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)
+
+ # Construct the arguments to be passed to the pip command
+ args = [
+ "install", "--use-wheel", "--no-index", "--find-links",
+ tmpdir,
+ # Temporary until pip 1.5 is final
+ "--pre",
+ ]
+ if root:
+ args += ["--root", root]
+ if upgrade:
+ args += ["--upgrade"]
+ if user:
+ args += ["--user"]
+ if verbosity:
+ args += ["-" + "v" * verbosity]
+
+ _run_pip(tmpdir, args + [p[0] for p in _PROJECTS])
diff --git a/Lib/ensurepip/__main__.py b/Lib/ensurepip/__main__.py
new file mode 100644
index 0000000..abd995d
--- /dev/null
+++ b/Lib/ensurepip/__main__.py
@@ -0,0 +1,50 @@
+import argparse
+import ensurepip
+
+
+def main():
+ parser = argparse.ArgumentParser(prog="python -m ensurepip")
+ parser.add_argument(
+ "--version",
+ action="version",
+ version="pip {}".format(ensurepip.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.",
+ )
+
+ args = parser.parse_args()
+
+ ensurepip.bootstrap(
+ root=args.root,
+ upgrade=args.upgrade,
+ user=args.user,
+ verbosity=args.verbosity,
+ )
+
+
+if __name__ == "__main__":
+ main()
diff --git a/Lib/ensurepip/_bundled/pip-1.5.dev1-py2.py3-none-any.whl b/Lib/ensurepip/_bundled/pip-1.5.dev1-py2.py3-none-any.whl
new file mode 100644
index 0000000..62cc73a
Binary files /dev/null and b/Lib/ensurepip/_bundled/pip-1.5.dev1-py2.py3-none-any.whl differ
diff --git a/Lib/ensurepip/_bundled/setuptools-1.1.6-py2.py3-none-any.whl b/Lib/ensurepip/_bundled/setuptools-1.1.6-py2.py3-none-any.whl
new file mode 100644
index 0000000..941c4e4
Binary files /dev/null and b/Lib/ensurepip/_bundled/setuptools-1.1.6-py2.py3-none-any.whl differ
diff --git a/Lib/test/test_ensurepip.py b/Lib/test/test_ensurepip.py
new file mode 100644
index 0000000..0be0bfd
--- /dev/null
+++ b/Lib/test/test_ensurepip.py
@@ -0,0 +1,102 @@
+import unittest
+import unittest.mock
+import ensurepip
+import test.support
+
+
+class TestEnsurePipVersion(unittest.TestCase):
+
+ def test_returns_version(self):
+ self.assertEqual(ensurepip._PIP_VERSION, ensurepip.version())
+
+
+class TestBootstrap(unittest.TestCase):
+
+ @unittest.mock.patch("ensurepip._run_pip")
+ def test_basic_bootstraping(self, run_pip):
+ ensurepip.bootstrap()
+
+ run_pip.assert_called_once_with(
+ unittest.mock.ANY,
+ [
+ "install", "--use-wheel", "--no-index", "--find-links",
+ unittest.mock.ANY, "--pre", "setuptools", "pip",
+ ],
+ )
+
+ @unittest.mock.patch("ensurepip._run_pip")
+ def test_bootstraping_with_root(self, run_pip):
+ ensurepip.bootstrap(root="/foo/bar/")
+
+ run_pip.assert_called_once_with(
+ unittest.mock.ANY,
+ [
+ "install", "--use-wheel", "--no-index", "--find-links",
+ unittest.mock.ANY, "--pre", "--root", "/foo/bar/",
+ "setuptools", "pip",
+ ],
+ )
+
+ @unittest.mock.patch("ensurepip._run_pip")
+ def test_bootstraping_with_user(self, run_pip):
+ ensurepip.bootstrap(user=True)
+
+ run_pip.assert_called_once_with(
+ unittest.mock.ANY,
+ [
+ "install", "--use-wheel", "--no-index", "--find-links",
+ unittest.mock.ANY, "--pre", "--user", "setuptools", "pip",
+ ],
+ )
+
+ @unittest.mock.patch("ensurepip._run_pip")
+ def test_bootstraping_with_upgrade(self, run_pip):
+ ensurepip.bootstrap(upgrade=True)
+
+ run_pip.assert_called_once_with(
+ unittest.mock.ANY,
+ [
+ "install", "--use-wheel", "--no-index", "--find-links",
+ unittest.mock.ANY, "--pre", "--upgrade", "setuptools", "pip",
+ ],
+ )
+
+ @unittest.mock.patch("ensurepip._run_pip")
+ def test_bootstraping_with_verbosity_1(self, run_pip):
+ ensurepip.bootstrap(verbosity=1)
+
+ run_pip.assert_called_once_with(
+ unittest.mock.ANY,
+ [
+ "install", "--use-wheel", "--no-index", "--find-links",
+ unittest.mock.ANY, "--pre", "-v", "setuptools", "pip",
+ ],
+ )
+
+ @unittest.mock.patch("ensurepip._run_pip")
+ def test_bootstraping_with_verbosity_2(self, run_pip):
+ ensurepip.bootstrap(verbosity=2)
+
+ run_pip.assert_called_once_with(
+ unittest.mock.ANY,
+ [
+ "install", "--use-wheel", "--no-index", "--find-links",
+ unittest.mock.ANY, "--pre", "-vv", "setuptools", "pip",
+ ],
+ )
+
+ @unittest.mock.patch("ensurepip._run_pip")
+ def test_bootstraping_with_verbosity_3(self, run_pip):
+ ensurepip.bootstrap(verbosity=3)
+
+ run_pip.assert_called_once_with(
+ unittest.mock.ANY,
+ [
+ "install", "--use-wheel", "--no-index", "--find-links",
+ unittest.mock.ANY, "--pre", "-vvv", "setuptools", "pip",
+ ],
+ )
+
+
+if __name__ == "__main__":
+ test.support.run_unittest(__name__)
diff --git a/Tools/scripts/checkpip.py b/Tools/scripts/checkpip.py
new file mode 100644
index 0000000..f77481c
--- /dev/null
+++ b/Tools/scripts/checkpip.py
@@ -0,0 +1,25 @@
+#/usr/bin/env python3
+"""
+Checks that the version of the projects bundled in ensurepip are the latest
+versions available.
+"""
+import ensurepip
+import json
+import urllib.request
+
+
+def main():
+ for project, version in ensurepip._PROJECTS:
+ data = json.loads(urllib.request.urlopen(
+ "https://pypi.python.org/pypi/{}/json".format(project),
+ cadefault=True,
+ ).read().decode("utf8"))
+ upstream_version = data["info"]["version"]
+
+ if version != upstream_version:
+ print("The latest version of {} on PyPI is {}, but ensurepip "
+ "has {}".format(project, upstream_version, version))
+
+
+if __name__ == "__main__":
+ main()