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