-
Notifications
You must be signed in to change notification settings - Fork 3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Improve
protected_pip.py
by adding additional context
This additional context provided by the various comments within the lightly-refactored implementation should make it easier to understand what this file is for, how it works and when it is useful.
- Loading branch information
Showing
1 changed file
with
51 additions
and
28 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,38 +1,61 @@ | ||
"""Maintain and use a protected copy of pip for use during development. | ||
The protected copy of pip can be used to manipulate the environment while keeping a | ||
potentially-non-functional installation of in-development pip in the development virtual | ||
environment. | ||
This allows for setting up the test environments and exercising the in-development code, | ||
even when it is not functional-enough to install the packages for setting up the | ||
environment that it is being used it. | ||
""" | ||
|
||
import os | ||
import pathlib | ||
import shutil | ||
import subprocess | ||
import sys | ||
from glob import glob | ||
from typing import Iterable, Union | ||
from typing import List | ||
|
||
VIRTUAL_ENV = os.environ["VIRTUAL_ENV"] | ||
TOX_PIP_DIR = os.path.join(VIRTUAL_ENV, "pip") | ||
|
||
|
||
def pip(args: Iterable[Union[str, pathlib.Path]]) -> None: | ||
# First things first, get a recent (stable) version of pip. | ||
if not os.path.exists(TOX_PIP_DIR): | ||
subprocess.check_call( | ||
[ | ||
sys.executable, | ||
"-m", | ||
"pip", | ||
"--disable-pip-version-check", | ||
"install", | ||
"-t", | ||
TOX_PIP_DIR, | ||
"pip", | ||
] | ||
) | ||
shutil.rmtree(glob(os.path.join(TOX_PIP_DIR, "pip-*.dist-info"))[0]) | ||
# And use that version. | ||
pypath_env = os.environ.get("PYTHONPATH") | ||
pypath = pypath_env.split(os.pathsep) if pypath_env is not None else [] | ||
pypath.insert(0, TOX_PIP_DIR) | ||
os.environ["PYTHONPATH"] = os.pathsep.join(pypath) | ||
subprocess.check_call([sys.executable, "-m", "pip", *(os.fspath(a) for a in args)]) | ||
PROTECTED_PIP_DIR = os.path.join(VIRTUAL_ENV, "pip") | ||
|
||
|
||
def _setup_protected_pip() -> None: | ||
# This setup happens before any development version of pip is installed in this | ||
# environment. So, at this point, the existing pip installation should be from a | ||
# stable release and can be safely used to create the protected copy. | ||
subprocess.check_call( | ||
[ | ||
sys.executable, | ||
"-m", | ||
"pip", | ||
"--disable-pip-version-check", | ||
"install", | ||
"-t", | ||
PROTECTED_PIP_DIR, | ||
"pip", | ||
] | ||
) | ||
# Make it impossible for pip (and other Python tooling) to discover this protected | ||
# installation of pip using the metadata, by deleting the metadata. | ||
shutil.rmtree(glob(os.path.join(PROTECTED_PIP_DIR, "pip-*.dist-info"))[0]) | ||
|
||
|
||
def main(args: List[str]) -> None: | ||
# If we don't have a protected pip, let's set it up. | ||
if not os.path.exists(PROTECTED_PIP_DIR): | ||
_setup_protected_pip() | ||
|
||
# Run Python, with the protected pip copy on PYTHONPATH. | ||
pypath_env = os.environ.get("PYTHONPATH", "") | ||
old_PYTHONPATH_entries = pypath_env.split(os.pathsep) if pypath_env else [] | ||
new_PYTHONPATH = os.pathsep.join([PROTECTED_PIP_DIR] + old_PYTHONPATH_entries) | ||
|
||
subprocess.check_call( | ||
[sys.executable, "-m", "pip"] + args, | ||
env={"PYTHONPATH": new_PYTHONPATH}, | ||
) | ||
|
||
|
||
if __name__ == "__main__": | ||
pip(sys.argv[1:]) | ||
main(sys.argv[1:]) |