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