blob: 526dfd004a41d8daa7492de7a56ddad9627b638b [file] [log] [blame]
Nick Coghland0cf0632013-11-11 22:11:55 +10001import os
2import os.path
3import pkgutil
4import sys
5import tempfile
6
Nick Coghland0cf0632013-11-11 22:11:55 +10007
8__all__ = ["version", "bootstrap"]
9
10
Pradyun Gedam01e0f432019-03-06 17:12:21 +053011_SETUPTOOLS_VERSION = "40.8.0"
Nick Coghland0cf0632013-11-11 22:11:55 +100012
Pradyun Gedam01e0f432019-03-06 17:12:21 +053013_PIP_VERSION = "19.0.3"
Nick Coghland0cf0632013-11-11 22:11:55 +100014
15_PROJECTS = [
16 ("setuptools", _SETUPTOOLS_VERSION),
17 ("pip", _PIP_VERSION),
18]
19
20
Nick Coghlanfdf3a622013-11-30 17:15:09 +100021def _run_pip(args, additional_paths=None):
Nick Coghland0cf0632013-11-11 22:11:55 +100022 # Add our bundled software to the sys.path so we can import it
Nick Coghlanfdf3a622013-11-30 17:15:09 +100023 if additional_paths is not None:
24 sys.path = additional_paths + sys.path
Nick Coghland0cf0632013-11-11 22:11:55 +100025
26 # Install the bundled software
Paul Moore0399cf92018-04-20 21:06:51 +010027 import pip._internal
28 return pip._internal.main(args)
Nick Coghland0cf0632013-11-11 22:11:55 +100029
30
31def version():
32 """
33 Returns a string specifying the bundled version of pip.
34 """
35 return _PIP_VERSION
36
Nick Coghlan6edd82a2014-02-04 23:02:36 +100037def _disable_pip_configuration_settings():
Nick Coghlaned9af522013-12-23 17:39:12 +100038 # 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]
Nick Coghlan6edd82a2014-02-04 23:02:36 +100044 # 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
Nick Coghlaned9af522013-12-23 17:39:12 +100047
Nick Coghland0cf0632013-11-11 22:11:55 +100048
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).
Nick Coghlan6256fcb2013-12-23 16:16:07 +100055
56 Note that calling this function will alter both sys.path and os.environ.
Nick Coghland0cf0632013-11-11 22:11:55 +100057 """
Igor Filatov9adda0c2017-09-21 13:07:45 +030058 # 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 """
Nick Coghland0cf0632013-11-11 22:11:55 +100073 if altinstall and default_pip:
74 raise ValueError("Cannot use altinstall and default_pip together")
75
Nick Coghlan6edd82a2014-02-04 23:02:36 +100076 _disable_pip_configuration_settings()
Nick Coghlan6256fcb2013-12-23 16:16:07 +100077
Nick Coghland0cf0632013-11-11 22:11:55 +100078 # 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
Donald Stufftf7f58f82014-01-02 09:33:35 -0500107 args = ["install", "--no-index", "--find-links", tmpdir]
Nick Coghland0cf0632013-11-11 22:11:55 +1000108 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
Igor Filatov9adda0c2017-09-21 13:07:45 +0300117 return _run_pip(args + [p[0] for p in _PROJECTS], additional_paths)
Nick Coghlanfdf3a622013-11-30 17:15:09 +1000118
Nick Coghlanf71cae02013-12-23 18:20:34 +1000119def _uninstall_helper(*, verbosity=0):
Nick Coghlaned9af522013-12-23 17:39:12 +1000120 """Helper to support a clean default uninstall process on Windows
121
122 Note that calling this function may alter os.environ.
123 """
Nick Coghlanfdf3a622013-11-30 17:15:09 +1000124 # 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:
Nick Coghlana46cf122014-02-28 23:35:05 +1000132 msg = ("ensurepip will only uninstall a matching version "
Nick Coghlanfdf3a622013-11-30 17:15:09 +1000133 "({!r} installed, {!r} bundled)")
Nick Coghlana46cf122014-02-28 23:35:05 +1000134 print(msg.format(pip.__version__, _PIP_VERSION), file=sys.stderr)
135 return
Nick Coghlanfdf3a622013-11-30 17:15:09 +1000136
Nick Coghlan6edd82a2014-02-04 23:02:36 +1000137 _disable_pip_configuration_settings()
Nick Coghlaned9af522013-12-23 17:39:12 +1000138
Nick Coghlanfdf3a622013-11-30 17:15:09 +1000139 # Construct the arguments to be passed to the pip command
Donald Stufft71a85892015-06-02 10:37:08 -0400140 args = ["uninstall", "-y", "--disable-pip-version-check"]
Nick Coghlanfdf3a622013-11-30 17:15:09 +1000141 if verbosity:
142 args += ["-" + "v" * verbosity]
143
Igor Filatov9adda0c2017-09-21 13:07:45 +0300144 return _run_pip(args + [p[0] for p in reversed(_PROJECTS)])
Nick Coghlanf71cae02013-12-23 18:20:34 +1000145
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,
Wieland Hoffmanne9537ad2018-05-30 09:45:55 +0200185 help=("Make an alternate install, installing only the X.Y versioned "
186 "scripts (Default: pipX, pipX.Y, easy_install-X.Y)."),
Nick Coghlanf71cae02013-12-23 18:20:34 +1000187 )
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 "
Wieland Hoffmanne9537ad2018-05-30 09:45:55 +0200193 "and easy_install in addition to the versioned scripts."),
Nick Coghlanf71cae02013-12-23 18:20:34 +1000194 )
195
196 args = parser.parse_args(argv)
197
Igor Filatov9adda0c2017-09-21 13:07:45 +0300198 return _bootstrap(
Nick Coghlanf71cae02013-12-23 18:20:34 +1000199 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 )