Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move __pip-runner__ script into a module #11262

Merged
merged 3 commits into from
Jul 16, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions src/pip/__pip-runner__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
"""Execute exactly this copy of pip, within a different environment.

This file is named as it is, to ensure that this module can't be imported via
an import statement.
"""

import importlib.util
import runpy
import sys
import types
from importlib.machinery import ModuleSpec
from os.path import dirname, join
from typing import Optional, Sequence, Union

PIP_SOURCES_ROOT = dirname(dirname(dirname(__file__)))


class PipImportRedirectingFinder:
@classmethod
def find_spec(
self,
fullname: str,
path: Optional[Sequence[Union[bytes, str]]] = None,
target: Optional[types.ModuleType] = None,
) -> Optional[ModuleSpec]:
if not fullname.startswith("pip."):
return None

# Import pip from the source directory of this file
location = join(PIP_SOURCES_ROOT, *fullname.split("."))
return importlib.util.spec_from_file_location(fullname, location)


sys.meta_path.insert(0, PipImportRedirectingFinder())

assert __name__ == "__main__", "Cannot run __pip-runner__.py as a non-main module"
runpy.run_module("pip", run_name="__main__")
64 changes: 16 additions & 48 deletions src/pip/_internal/build_env.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
"""Build Environment used for isolation during sdist building
"""

import contextlib
import logging
import os
import pathlib
Expand All @@ -10,7 +9,7 @@
from collections import OrderedDict
from sysconfig import get_paths
from types import TracebackType
from typing import TYPE_CHECKING, Generator, Iterable, List, Optional, Set, Tuple, Type
from typing import TYPE_CHECKING, Iterable, List, Optional, Set, Tuple, Type

from pip._vendor.certifi import where
from pip._vendor.packaging.requirements import Requirement
Expand All @@ -28,29 +27,6 @@

logger = logging.getLogger(__name__)

PIP_RUNNER = """
import importlib.util
import os
import runpy
import sys


class PipImportRedirectingFinder:

@classmethod
def find_spec(cls, fullname, path=None, target=None):
if not fullname.startswith("pip."):
return None

# Import pip from the current source directory
location = os.path.join({source!r}, *fullname.split("."))
return importlib.util.spec_from_file_location(fullname, location)


sys.meta_path.insert(0, PipImportRedirectingFinder())
runpy.run_module("pip", run_name="__main__")
"""


class _Prefix:
def __init__(self, path: str) -> None:
Expand All @@ -63,26 +39,20 @@ def __init__(self, path: str) -> None:
self.lib_dirs = get_prefixed_libs(path)


@contextlib.contextmanager
def _create_runnable_pip() -> Generator[str, None, None]:
"""Create a "pip runner" file.
def _get_runnable_pip() -> str:
"""Get a file to pass to a Python executable, to run the currently-running pip.

The runner file ensures that import for pip happens using the currently-running pip.
It will be used to install requirements into the build environment.
This is used to run a pip subprocess, for installing requirements into the build
environment.
"""
source = pathlib.Path(pip_location).resolve().parent

# Return the current instance if `source` is not a directory. It likely
# means that this copy of pip is already standalone.
if not source.is_dir():
yield str(source)
return
# This would happen if someone is using pip from inside a zip file. In that
# case, we can use that directly.
return str(source)

with TempDirectory(kind="standalone-pip") as tmp_dir:
pip_runner = os.path.join(tmp_dir.path, "__pip-runner__.py")
with open(pip_runner, "w", encoding="utf8") as f:
f.write(PIP_RUNNER.format(source=os.fsdecode(source)))
yield pip_runner
return os.fsdecode(source / "__pip-runner__.py")


class BuildEnvironment:
Expand Down Expand Up @@ -223,15 +193,13 @@ def install_requirements(
prefix.setup = True
if not requirements:
return
with contextlib.ExitStack() as ctx:
pip_runnable = ctx.enter_context(_create_runnable_pip())
self._install_requirements(
pip_runnable,
finder,
requirements,
prefix,
kind=kind,
)
self._install_requirements(
_get_runnable_pip(),
finder,
requirements,
prefix,
kind=kind,
)

@staticmethod
def _install_requirements(
Expand Down