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