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