m2m模型翻译
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

156 lines
6.6 KiB

6 months ago
  1. import logging
  2. from typing import Iterable, Optional, Set, Tuple
  3. from pip._internal.build_env import BuildEnvironment
  4. from pip._internal.distributions.base import AbstractDistribution
  5. from pip._internal.exceptions import InstallationError
  6. from pip._internal.index.package_finder import PackageFinder
  7. from pip._internal.metadata import BaseDistribution
  8. from pip._internal.utils.subprocess import runner_with_spinner_message
  9. logger = logging.getLogger(__name__)
  10. class SourceDistribution(AbstractDistribution):
  11. """Represents a source distribution.
  12. The preparation step for these needs metadata for the packages to be
  13. generated, either using PEP 517 or using the legacy `setup.py egg_info`.
  14. """
  15. @property
  16. def build_tracker_id(self) -> Optional[str]:
  17. """Identify this requirement uniquely by its link."""
  18. assert self.req.link
  19. return self.req.link.url_without_fragment
  20. def get_metadata_distribution(self) -> BaseDistribution:
  21. return self.req.get_dist()
  22. def prepare_distribution_metadata(
  23. self,
  24. finder: PackageFinder,
  25. build_isolation: bool,
  26. check_build_deps: bool,
  27. ) -> None:
  28. # Load pyproject.toml, to determine whether PEP 517 is to be used
  29. self.req.load_pyproject_toml()
  30. # Set up the build isolation, if this requirement should be isolated
  31. should_isolate = self.req.use_pep517 and build_isolation
  32. if should_isolate:
  33. # Setup an isolated environment and install the build backend static
  34. # requirements in it.
  35. self._prepare_build_backend(finder)
  36. # Check that if the requirement is editable, it either supports PEP 660 or
  37. # has a setup.py or a setup.cfg. This cannot be done earlier because we need
  38. # to setup the build backend to verify it supports build_editable, nor can
  39. # it be done later, because we want to avoid installing build requirements
  40. # needlessly. Doing it here also works around setuptools generating
  41. # UNKNOWN.egg-info when running get_requires_for_build_wheel on a directory
  42. # without setup.py nor setup.cfg.
  43. self.req.isolated_editable_sanity_check()
  44. # Install the dynamic build requirements.
  45. self._install_build_reqs(finder)
  46. # Check if the current environment provides build dependencies
  47. should_check_deps = self.req.use_pep517 and check_build_deps
  48. if should_check_deps:
  49. pyproject_requires = self.req.pyproject_requires
  50. assert pyproject_requires is not None
  51. conflicting, missing = self.req.build_env.check_requirements(
  52. pyproject_requires
  53. )
  54. if conflicting:
  55. self._raise_conflicts("the backend dependencies", conflicting)
  56. if missing:
  57. self._raise_missing_reqs(missing)
  58. self.req.prepare_metadata()
  59. def _prepare_build_backend(self, finder: PackageFinder) -> None:
  60. # Isolate in a BuildEnvironment and install the build-time
  61. # requirements.
  62. pyproject_requires = self.req.pyproject_requires
  63. assert pyproject_requires is not None
  64. self.req.build_env = BuildEnvironment()
  65. self.req.build_env.install_requirements(
  66. finder, pyproject_requires, "overlay", kind="build dependencies"
  67. )
  68. conflicting, missing = self.req.build_env.check_requirements(
  69. self.req.requirements_to_check
  70. )
  71. if conflicting:
  72. self._raise_conflicts("PEP 517/518 supported requirements", conflicting)
  73. if missing:
  74. logger.warning(
  75. "Missing build requirements in pyproject.toml for %s.",
  76. self.req,
  77. )
  78. logger.warning(
  79. "The project does not specify a build backend, and "
  80. "pip cannot fall back to setuptools without %s.",
  81. " and ".join(map(repr, sorted(missing))),
  82. )
  83. def _get_build_requires_wheel(self) -> Iterable[str]:
  84. with self.req.build_env:
  85. runner = runner_with_spinner_message("Getting requirements to build wheel")
  86. backend = self.req.pep517_backend
  87. assert backend is not None
  88. with backend.subprocess_runner(runner):
  89. return backend.get_requires_for_build_wheel()
  90. def _get_build_requires_editable(self) -> Iterable[str]:
  91. with self.req.build_env:
  92. runner = runner_with_spinner_message(
  93. "Getting requirements to build editable"
  94. )
  95. backend = self.req.pep517_backend
  96. assert backend is not None
  97. with backend.subprocess_runner(runner):
  98. return backend.get_requires_for_build_editable()
  99. def _install_build_reqs(self, finder: PackageFinder) -> None:
  100. # Install any extra build dependencies that the backend requests.
  101. # This must be done in a second pass, as the pyproject.toml
  102. # dependencies must be installed before we can call the backend.
  103. if (
  104. self.req.editable
  105. and self.req.permit_editable_wheels
  106. and self.req.supports_pyproject_editable()
  107. ):
  108. build_reqs = self._get_build_requires_editable()
  109. else:
  110. build_reqs = self._get_build_requires_wheel()
  111. conflicting, missing = self.req.build_env.check_requirements(build_reqs)
  112. if conflicting:
  113. self._raise_conflicts("the backend dependencies", conflicting)
  114. self.req.build_env.install_requirements(
  115. finder, missing, "normal", kind="backend dependencies"
  116. )
  117. def _raise_conflicts(
  118. self, conflicting_with: str, conflicting_reqs: Set[Tuple[str, str]]
  119. ) -> None:
  120. format_string = (
  121. "Some build dependencies for {requirement} "
  122. "conflict with {conflicting_with}: {description}."
  123. )
  124. error_message = format_string.format(
  125. requirement=self.req,
  126. conflicting_with=conflicting_with,
  127. description=", ".join(
  128. f"{installed} is incompatible with {wanted}"
  129. for installed, wanted in sorted(conflicting_reqs)
  130. ),
  131. )
  132. raise InstallationError(error_message)
  133. def _raise_missing_reqs(self, missing: Set[str]) -> None:
  134. format_string = (
  135. "Some build dependencies for {requirement} are missing: {missing}."
  136. )
  137. error_message = format_string.format(
  138. requirement=self.req, missing=", ".join(map(repr, sorted(missing)))
  139. )
  140. raise InstallationError(error_message)