Path: blob/main/test/lib/python3.9/site-packages/pip/_internal/distributions/sdist.py
4805 views
import logging1from typing import Iterable, Set, Tuple23from pip._internal.build_env import BuildEnvironment4from pip._internal.distributions.base import AbstractDistribution5from pip._internal.exceptions import InstallationError6from pip._internal.index.package_finder import PackageFinder7from pip._internal.metadata import BaseDistribution8from pip._internal.utils.subprocess import runner_with_spinner_message910logger = logging.getLogger(__name__)111213class SourceDistribution(AbstractDistribution):14"""Represents a source distribution.1516The preparation step for these needs metadata for the packages to be17generated, either using PEP 517 or using the legacy `setup.py egg_info`.18"""1920def get_metadata_distribution(self) -> BaseDistribution:21return self.req.get_dist()2223def prepare_distribution_metadata(24self,25finder: PackageFinder,26build_isolation: bool,27check_build_deps: bool,28) -> None:29# Load pyproject.toml, to determine whether PEP 517 is to be used30self.req.load_pyproject_toml()3132# Set up the build isolation, if this requirement should be isolated33should_isolate = self.req.use_pep517 and build_isolation34if should_isolate:35# Setup an isolated environment and install the build backend static36# requirements in it.37self._prepare_build_backend(finder)38# Check that if the requirement is editable, it either supports PEP 660 or39# has a setup.py or a setup.cfg. This cannot be done earlier because we need40# to setup the build backend to verify it supports build_editable, nor can41# it be done later, because we want to avoid installing build requirements42# needlessly. Doing it here also works around setuptools generating43# UNKNOWN.egg-info when running get_requires_for_build_wheel on a directory44# without setup.py nor setup.cfg.45self.req.isolated_editable_sanity_check()46# Install the dynamic build requirements.47self._install_build_reqs(finder)48# Check if the current environment provides build dependencies49should_check_deps = self.req.use_pep517 and check_build_deps50if should_check_deps:51pyproject_requires = self.req.pyproject_requires52assert pyproject_requires is not None53conflicting, missing = self.req.build_env.check_requirements(54pyproject_requires55)56if conflicting:57self._raise_conflicts("the backend dependencies", conflicting)58if missing:59self._raise_missing_reqs(missing)60self.req.prepare_metadata()6162def _prepare_build_backend(self, finder: PackageFinder) -> None:63# Isolate in a BuildEnvironment and install the build-time64# requirements.65pyproject_requires = self.req.pyproject_requires66assert pyproject_requires is not None6768self.req.build_env = BuildEnvironment()69self.req.build_env.install_requirements(70finder, pyproject_requires, "overlay", kind="build dependencies"71)72conflicting, missing = self.req.build_env.check_requirements(73self.req.requirements_to_check74)75if conflicting:76self._raise_conflicts("PEP 517/518 supported requirements", conflicting)77if missing:78logger.warning(79"Missing build requirements in pyproject.toml for %s.",80self.req,81)82logger.warning(83"The project does not specify a build backend, and "84"pip cannot fall back to setuptools without %s.",85" and ".join(map(repr, sorted(missing))),86)8788def _get_build_requires_wheel(self) -> Iterable[str]:89with self.req.build_env:90runner = runner_with_spinner_message("Getting requirements to build wheel")91backend = self.req.pep517_backend92assert backend is not None93with backend.subprocess_runner(runner):94return backend.get_requires_for_build_wheel()9596def _get_build_requires_editable(self) -> Iterable[str]:97with self.req.build_env:98runner = runner_with_spinner_message(99"Getting requirements to build editable"100)101backend = self.req.pep517_backend102assert backend is not None103with backend.subprocess_runner(runner):104return backend.get_requires_for_build_editable()105106def _install_build_reqs(self, finder: PackageFinder) -> None:107# Install any extra build dependencies that the backend requests.108# This must be done in a second pass, as the pyproject.toml109# dependencies must be installed before we can call the backend.110if (111self.req.editable112and self.req.permit_editable_wheels113and self.req.supports_pyproject_editable()114):115build_reqs = self._get_build_requires_editable()116else:117build_reqs = self._get_build_requires_wheel()118conflicting, missing = self.req.build_env.check_requirements(build_reqs)119if conflicting:120self._raise_conflicts("the backend dependencies", conflicting)121self.req.build_env.install_requirements(122finder, missing, "normal", kind="backend dependencies"123)124125def _raise_conflicts(126self, conflicting_with: str, conflicting_reqs: Set[Tuple[str, str]]127) -> None:128format_string = (129"Some build dependencies for {requirement} "130"conflict with {conflicting_with}: {description}."131)132error_message = format_string.format(133requirement=self.req,134conflicting_with=conflicting_with,135description=", ".join(136f"{installed} is incompatible with {wanted}"137for installed, wanted in sorted(conflicting_reqs)138),139)140raise InstallationError(error_message)141142def _raise_missing_reqs(self, missing: Set[str]) -> None:143format_string = (144"Some build dependencies for {requirement} are missing: {missing}."145)146error_message = format_string.format(147requirement=self.req, missing=", ".join(map(repr, sorted(missing)))148)149raise InstallationError(error_message)150151152