Home | History | Annotate | Download | only in ensurepip
      1 #!/usr/bin/env python2
      2 from __future__ import print_function
      3 
      4 import os
      5 import os.path
      6 import pkgutil
      7 import shutil
      8 import sys
      9 import tempfile
     10 
     11 
     12 __all__ = ["version", "bootstrap"]
     13 
     14 
     15 _SETUPTOOLS_VERSION = "28.8.0"
     16 
     17 _PIP_VERSION = "9.0.1"
     18 
     19 _PROJECTS = [
     20     ("setuptools", _SETUPTOOLS_VERSION),
     21     ("pip", _PIP_VERSION),
     22 ]
     23 
     24 
     25 def _run_pip(args, additional_paths=None):
     26     # Add our bundled software to the sys.path so we can import it
     27     if additional_paths is not None:
     28         sys.path = additional_paths + sys.path
     29 
     30     # Install the bundled software
     31     import pip
     32     pip.main(args)
     33 
     34 
     35 def version():
     36     """
     37     Returns a string specifying the bundled version of pip.
     38     """
     39     return _PIP_VERSION
     40 
     41 
     42 def _disable_pip_configuration_settings():
     43     # We deliberately ignore all pip environment variables
     44     # when invoking pip
     45     # See http://bugs.python.org/issue19734 for details
     46     keys_to_remove = [k for k in os.environ if k.startswith("PIP_")]
     47     for k in keys_to_remove:
     48         del os.environ[k]
     49     # We also ignore the settings in the default pip configuration file
     50     # See http://bugs.python.org/issue20053 for details
     51     os.environ['PIP_CONFIG_FILE'] = os.devnull
     52 
     53 
     54 def bootstrap(root=None, upgrade=False, user=False,
     55               altinstall=False, default_pip=True,
     56               verbosity=0):
     57     """
     58     Bootstrap pip into the current Python installation (or the given root
     59     directory).
     60 
     61     Note that calling this function will alter both sys.path and os.environ.
     62     """
     63     if altinstall and default_pip:
     64         raise ValueError("Cannot use altinstall and default_pip together")
     65 
     66     _disable_pip_configuration_settings()
     67 
     68     # By default, installing pip and setuptools installs all of the
     69     # following scripts (X.Y == running Python version):
     70     #
     71     #   pip, pipX, pipX.Y, easy_install, easy_install-X.Y
     72     #
     73     # pip 1.5+ allows ensurepip to request that some of those be left out
     74     if altinstall:
     75         # omit pip, pipX and easy_install
     76         os.environ["ENSUREPIP_OPTIONS"] = "altinstall"
     77     elif not default_pip:
     78         # omit pip and easy_install
     79         os.environ["ENSUREPIP_OPTIONS"] = "install"
     80 
     81     tmpdir = tempfile.mkdtemp()
     82     try:
     83         # Put our bundled wheels into a temporary directory and construct the
     84         # additional paths that need added to sys.path
     85         additional_paths = []
     86         for project, version in _PROJECTS:
     87             wheel_name = "{}-{}-py2.py3-none-any.whl".format(project, version)
     88             whl = pkgutil.get_data(
     89                 "ensurepip",
     90                 "_bundled/{}".format(wheel_name),
     91             )
     92             with open(os.path.join(tmpdir, wheel_name), "wb") as fp:
     93                 fp.write(whl)
     94 
     95             additional_paths.append(os.path.join(tmpdir, wheel_name))
     96 
     97         # Construct the arguments to be passed to the pip command
     98         args = ["install", "--no-index", "--find-links", tmpdir]
     99         if root:
    100             args += ["--root", root]
    101         if upgrade:
    102             args += ["--upgrade"]
    103         if user:
    104             args += ["--user"]
    105         if verbosity:
    106             args += ["-" + "v" * verbosity]
    107 
    108         _run_pip(args + [p[0] for p in _PROJECTS], additional_paths)
    109     finally:
    110         shutil.rmtree(tmpdir, ignore_errors=True)
    111 
    112 
    113 def _uninstall_helper(verbosity=0):
    114     """Helper to support a clean default uninstall process on Windows
    115 
    116     Note that calling this function may alter os.environ.
    117     """
    118     # Nothing to do if pip was never installed, or has been removed
    119     try:
    120         import pip
    121     except ImportError:
    122         return
    123 
    124     # If the pip version doesn't match the bundled one, leave it alone
    125     if pip.__version__ != _PIP_VERSION:
    126         msg = ("ensurepip will only uninstall a matching version "
    127                "({!r} installed, {!r} bundled)")
    128         print(msg.format(pip.__version__, _PIP_VERSION), file=sys.stderr)
    129         return
    130 
    131     _disable_pip_configuration_settings()
    132 
    133     # Construct the arguments to be passed to the pip command
    134     args = ["uninstall", "-y", "--disable-pip-version-check"]
    135     if verbosity:
    136         args += ["-" + "v" * verbosity]
    137 
    138     _run_pip(args + [p[0] for p in reversed(_PROJECTS)])
    139 
    140 
    141 def _main(argv=None):
    142     import argparse
    143     parser = argparse.ArgumentParser(prog="python -m ensurepip")
    144     parser.add_argument(
    145         "--version",
    146         action="version",
    147         version="pip {}".format(version()),
    148         help="Show the version of pip that is bundled with this Python.",
    149     )
    150     parser.add_argument(
    151         "-v", "--verbose",
    152         action="count",
    153         default=0,
    154         dest="verbosity",
    155         help=("Give more output. Option is additive, and can be used up to 3 "
    156               "times."),
    157     )
    158     parser.add_argument(
    159         "-U", "--upgrade",
    160         action="store_true",
    161         default=False,
    162         help="Upgrade pip and dependencies, even if already installed.",
    163     )
    164     parser.add_argument(
    165         "--user",
    166         action="store_true",
    167         default=False,
    168         help="Install using the user scheme.",
    169     )
    170     parser.add_argument(
    171         "--root",
    172         default=None,
    173         help="Install everything relative to this alternate root directory.",
    174     )
    175     parser.add_argument(
    176         "--altinstall",
    177         action="store_true",
    178         default=False,
    179         help=("Make an alternate install, installing only the X.Y versioned"
    180               "scripts (Default: pipX, pipX.Y, easy_install-X.Y)"),
    181     )
    182     parser.add_argument(
    183         "--default-pip",
    184         action="store_true",
    185         default=True,
    186         dest="default_pip",
    187         help=argparse.SUPPRESS,
    188     )
    189     parser.add_argument(
    190         "--no-default-pip",
    191         action="store_false",
    192         dest="default_pip",
    193         help=("Make a non default install, installing only the X and X.Y "
    194               "versioned scripts."),
    195     )
    196 
    197     args = parser.parse_args(argv)
    198 
    199     bootstrap(
    200         root=args.root,
    201         upgrade=args.upgrade,
    202         user=args.user,
    203         verbosity=args.verbosity,
    204         altinstall=args.altinstall,
    205         default_pip=args.default_pip,
    206     )
    207