pip 25.1.1__py3-none-any.whl → 25.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (236) hide show
  1. pip/__init__.py +3 -3
  2. pip/_internal/__init__.py +2 -2
  3. pip/_internal/build_env.py +186 -94
  4. pip/_internal/cache.py +17 -15
  5. pip/_internal/cli/autocompletion.py +13 -4
  6. pip/_internal/cli/base_command.py +18 -7
  7. pip/_internal/cli/cmdoptions.py +57 -80
  8. pip/_internal/cli/command_context.py +4 -3
  9. pip/_internal/cli/index_command.py +11 -9
  10. pip/_internal/cli/main.py +3 -2
  11. pip/_internal/cli/main_parser.py +4 -3
  12. pip/_internal/cli/parser.py +24 -20
  13. pip/_internal/cli/progress_bars.py +19 -12
  14. pip/_internal/cli/req_command.py +57 -33
  15. pip/_internal/cli/spinners.py +81 -5
  16. pip/_internal/commands/__init__.py +5 -3
  17. pip/_internal/commands/cache.py +18 -15
  18. pip/_internal/commands/check.py +1 -2
  19. pip/_internal/commands/completion.py +1 -2
  20. pip/_internal/commands/configuration.py +26 -18
  21. pip/_internal/commands/debug.py +8 -6
  22. pip/_internal/commands/download.py +6 -10
  23. pip/_internal/commands/freeze.py +2 -3
  24. pip/_internal/commands/hash.py +1 -2
  25. pip/_internal/commands/help.py +1 -2
  26. pip/_internal/commands/index.py +15 -9
  27. pip/_internal/commands/inspect.py +4 -4
  28. pip/_internal/commands/install.py +63 -53
  29. pip/_internal/commands/list.py +35 -26
  30. pip/_internal/commands/lock.py +4 -8
  31. pip/_internal/commands/search.py +14 -12
  32. pip/_internal/commands/show.py +14 -11
  33. pip/_internal/commands/uninstall.py +1 -2
  34. pip/_internal/commands/wheel.py +7 -13
  35. pip/_internal/configuration.py +40 -27
  36. pip/_internal/distributions/base.py +6 -4
  37. pip/_internal/distributions/installed.py +8 -4
  38. pip/_internal/distributions/sdist.py +33 -27
  39. pip/_internal/distributions/wheel.py +6 -4
  40. pip/_internal/exceptions.py +78 -42
  41. pip/_internal/index/collector.py +24 -29
  42. pip/_internal/index/package_finder.py +73 -64
  43. pip/_internal/index/sources.py +17 -14
  44. pip/_internal/locations/__init__.py +18 -16
  45. pip/_internal/locations/_distutils.py +12 -11
  46. pip/_internal/locations/_sysconfig.py +5 -4
  47. pip/_internal/locations/base.py +4 -3
  48. pip/_internal/main.py +2 -2
  49. pip/_internal/metadata/__init__.py +14 -7
  50. pip/_internal/metadata/_json.py +5 -4
  51. pip/_internal/metadata/base.py +22 -27
  52. pip/_internal/metadata/importlib/_compat.py +6 -4
  53. pip/_internal/metadata/importlib/_dists.py +20 -19
  54. pip/_internal/metadata/importlib/_envs.py +9 -6
  55. pip/_internal/metadata/pkg_resources.py +11 -14
  56. pip/_internal/models/direct_url.py +24 -21
  57. pip/_internal/models/format_control.py +5 -5
  58. pip/_internal/models/installation_report.py +4 -3
  59. pip/_internal/models/link.py +39 -34
  60. pip/_internal/models/pylock.py +27 -22
  61. pip/_internal/models/search_scope.py +6 -7
  62. pip/_internal/models/selection_prefs.py +3 -3
  63. pip/_internal/models/target_python.py +10 -9
  64. pip/_internal/models/wheel.py +12 -71
  65. pip/_internal/network/auth.py +20 -22
  66. pip/_internal/network/cache.py +28 -17
  67. pip/_internal/network/download.py +169 -141
  68. pip/_internal/network/lazy_wheel.py +15 -10
  69. pip/_internal/network/session.py +32 -27
  70. pip/_internal/network/utils.py +2 -2
  71. pip/_internal/network/xmlrpc.py +2 -2
  72. pip/_internal/operations/build/build_tracker.py +10 -8
  73. pip/_internal/operations/build/wheel.py +7 -6
  74. pip/_internal/operations/build/wheel_editable.py +7 -6
  75. pip/_internal/operations/check.py +21 -26
  76. pip/_internal/operations/freeze.py +12 -9
  77. pip/_internal/operations/install/wheel.py +49 -41
  78. pip/_internal/operations/prepare.py +42 -31
  79. pip/_internal/pyproject.py +7 -69
  80. pip/_internal/req/__init__.py +12 -12
  81. pip/_internal/req/constructors.py +68 -62
  82. pip/_internal/req/req_dependency_group.py +7 -11
  83. pip/_internal/req/req_file.py +32 -36
  84. pip/_internal/req/req_install.py +64 -170
  85. pip/_internal/req/req_set.py +4 -5
  86. pip/_internal/req/req_uninstall.py +20 -17
  87. pip/_internal/resolution/base.py +3 -3
  88. pip/_internal/resolution/legacy/resolver.py +21 -20
  89. pip/_internal/resolution/resolvelib/base.py +16 -13
  90. pip/_internal/resolution/resolvelib/candidates.py +49 -37
  91. pip/_internal/resolution/resolvelib/factory.py +72 -50
  92. pip/_internal/resolution/resolvelib/found_candidates.py +11 -9
  93. pip/_internal/resolution/resolvelib/provider.py +24 -20
  94. pip/_internal/resolution/resolvelib/reporter.py +26 -11
  95. pip/_internal/resolution/resolvelib/requirements.py +8 -6
  96. pip/_internal/resolution/resolvelib/resolver.py +41 -29
  97. pip/_internal/self_outdated_check.py +19 -9
  98. pip/_internal/utils/appdirs.py +1 -2
  99. pip/_internal/utils/compat.py +7 -1
  100. pip/_internal/utils/compatibility_tags.py +17 -16
  101. pip/_internal/utils/deprecation.py +11 -9
  102. pip/_internal/utils/direct_url_helpers.py +2 -2
  103. pip/_internal/utils/egg_link.py +6 -5
  104. pip/_internal/utils/entrypoints.py +3 -2
  105. pip/_internal/utils/filesystem.py +20 -5
  106. pip/_internal/utils/filetypes.py +4 -6
  107. pip/_internal/utils/glibc.py +6 -5
  108. pip/_internal/utils/hashes.py +9 -6
  109. pip/_internal/utils/logging.py +8 -5
  110. pip/_internal/utils/misc.py +37 -45
  111. pip/_internal/utils/packaging.py +3 -2
  112. pip/_internal/utils/retry.py +7 -4
  113. pip/_internal/utils/subprocess.py +20 -17
  114. pip/_internal/utils/temp_dir.py +10 -12
  115. pip/_internal/utils/unpacking.py +31 -4
  116. pip/_internal/utils/urls.py +1 -1
  117. pip/_internal/utils/virtualenv.py +3 -2
  118. pip/_internal/utils/wheel.py +3 -4
  119. pip/_internal/vcs/bazaar.py +26 -8
  120. pip/_internal/vcs/git.py +59 -24
  121. pip/_internal/vcs/mercurial.py +34 -11
  122. pip/_internal/vcs/subversion.py +27 -16
  123. pip/_internal/vcs/versioncontrol.py +56 -51
  124. pip/_internal/wheel_builder.py +30 -101
  125. pip/_vendor/README.rst +180 -0
  126. pip/_vendor/cachecontrol/LICENSE.txt +13 -0
  127. pip/_vendor/cachecontrol/__init__.py +1 -1
  128. pip/_vendor/certifi/LICENSE +20 -0
  129. pip/_vendor/certifi/__init__.py +1 -1
  130. pip/_vendor/certifi/cacert.pem +164 -261
  131. pip/_vendor/certifi/core.py +1 -32
  132. pip/_vendor/dependency_groups/LICENSE.txt +9 -0
  133. pip/_vendor/distlib/LICENSE.txt +284 -0
  134. pip/_vendor/distlib/__init__.py +2 -2
  135. pip/_vendor/distlib/scripts.py +1 -1
  136. pip/_vendor/distro/LICENSE +202 -0
  137. pip/_vendor/idna/LICENSE.md +31 -0
  138. pip/_vendor/msgpack/COPYING +14 -0
  139. pip/_vendor/msgpack/__init__.py +2 -2
  140. pip/_vendor/packaging/LICENSE +3 -0
  141. pip/_vendor/packaging/LICENSE.APACHE +177 -0
  142. pip/_vendor/packaging/LICENSE.BSD +23 -0
  143. pip/_vendor/pkg_resources/LICENSE +17 -0
  144. pip/_vendor/pkg_resources/__init__.py +1 -1
  145. pip/_vendor/platformdirs/LICENSE +21 -0
  146. pip/_vendor/platformdirs/api.py +1 -1
  147. pip/_vendor/platformdirs/macos.py +10 -8
  148. pip/_vendor/platformdirs/version.py +16 -3
  149. pip/_vendor/pygments/LICENSE +25 -0
  150. pip/_vendor/pygments/__init__.py +1 -1
  151. pip/_vendor/pyproject_hooks/LICENSE +21 -0
  152. pip/_vendor/requests/LICENSE +175 -0
  153. pip/_vendor/requests/__version__.py +2 -2
  154. pip/_vendor/requests/adapters.py +17 -40
  155. pip/_vendor/requests/compat.py +12 -0
  156. pip/_vendor/requests/models.py +3 -1
  157. pip/_vendor/requests/sessions.py +1 -1
  158. pip/_vendor/requests/utils.py +6 -16
  159. pip/_vendor/resolvelib/LICENSE +13 -0
  160. pip/_vendor/resolvelib/__init__.py +3 -3
  161. pip/_vendor/resolvelib/reporters.py +1 -1
  162. pip/_vendor/resolvelib/resolvers/__init__.py +4 -4
  163. pip/_vendor/resolvelib/resolvers/abstract.py +3 -3
  164. pip/_vendor/resolvelib/resolvers/resolution.py +96 -10
  165. pip/_vendor/rich/LICENSE +19 -0
  166. pip/_vendor/rich/__main__.py +12 -40
  167. pip/_vendor/rich/_inspect.py +1 -1
  168. pip/_vendor/rich/_ratio.py +1 -7
  169. pip/_vendor/rich/align.py +1 -7
  170. pip/_vendor/rich/box.py +1 -7
  171. pip/_vendor/rich/console.py +25 -20
  172. pip/_vendor/rich/control.py +1 -7
  173. pip/_vendor/rich/diagnose.py +1 -0
  174. pip/_vendor/rich/emoji.py +1 -6
  175. pip/_vendor/rich/live.py +32 -7
  176. pip/_vendor/rich/live_render.py +1 -7
  177. pip/_vendor/rich/logging.py +1 -1
  178. pip/_vendor/rich/panel.py +3 -4
  179. pip/_vendor/rich/progress.py +15 -15
  180. pip/_vendor/rich/spinner.py +7 -13
  181. pip/_vendor/rich/style.py +7 -11
  182. pip/_vendor/rich/syntax.py +24 -5
  183. pip/_vendor/rich/traceback.py +32 -17
  184. pip/_vendor/tomli/LICENSE +21 -0
  185. pip/_vendor/tomli/__init__.py +1 -1
  186. pip/_vendor/tomli/_parser.py +28 -21
  187. pip/_vendor/tomli/_re.py +8 -5
  188. pip/_vendor/tomli_w/LICENSE +21 -0
  189. pip/_vendor/truststore/LICENSE +21 -0
  190. pip/_vendor/truststore/__init__.py +1 -1
  191. pip/_vendor/truststore/_api.py +15 -7
  192. pip/_vendor/truststore/_openssl.py +3 -1
  193. pip/_vendor/urllib3/LICENSE.txt +21 -0
  194. pip/_vendor/vendor.txt +11 -12
  195. {pip-25.1.1.dist-info → pip-25.3.dist-info}/METADATA +32 -11
  196. {pip-25.1.1.dist-info → pip-25.3.dist-info}/RECORD +221 -192
  197. {pip-25.1.1.dist-info → pip-25.3.dist-info}/WHEEL +1 -2
  198. pip-25.3.dist-info/entry_points.txt +4 -0
  199. {pip-25.1.1.dist-info → pip-25.3.dist-info}/licenses/AUTHORS.txt +21 -0
  200. pip-25.3.dist-info/licenses/src/pip/_vendor/cachecontrol/LICENSE.txt +13 -0
  201. pip-25.3.dist-info/licenses/src/pip/_vendor/certifi/LICENSE +20 -0
  202. pip-25.3.dist-info/licenses/src/pip/_vendor/dependency_groups/LICENSE.txt +9 -0
  203. pip-25.3.dist-info/licenses/src/pip/_vendor/distlib/LICENSE.txt +284 -0
  204. pip-25.3.dist-info/licenses/src/pip/_vendor/distro/LICENSE +202 -0
  205. pip-25.3.dist-info/licenses/src/pip/_vendor/idna/LICENSE.md +31 -0
  206. pip-25.3.dist-info/licenses/src/pip/_vendor/msgpack/COPYING +14 -0
  207. pip-25.3.dist-info/licenses/src/pip/_vendor/packaging/LICENSE +3 -0
  208. pip-25.3.dist-info/licenses/src/pip/_vendor/packaging/LICENSE.APACHE +177 -0
  209. pip-25.3.dist-info/licenses/src/pip/_vendor/packaging/LICENSE.BSD +23 -0
  210. pip-25.3.dist-info/licenses/src/pip/_vendor/pkg_resources/LICENSE +17 -0
  211. pip-25.3.dist-info/licenses/src/pip/_vendor/platformdirs/LICENSE +21 -0
  212. pip-25.3.dist-info/licenses/src/pip/_vendor/pygments/LICENSE +25 -0
  213. pip-25.3.dist-info/licenses/src/pip/_vendor/pyproject_hooks/LICENSE +21 -0
  214. pip-25.3.dist-info/licenses/src/pip/_vendor/requests/LICENSE +175 -0
  215. pip-25.3.dist-info/licenses/src/pip/_vendor/resolvelib/LICENSE +13 -0
  216. pip-25.3.dist-info/licenses/src/pip/_vendor/rich/LICENSE +19 -0
  217. pip-25.3.dist-info/licenses/src/pip/_vendor/tomli/LICENSE +21 -0
  218. pip-25.3.dist-info/licenses/src/pip/_vendor/tomli_w/LICENSE +21 -0
  219. pip-25.3.dist-info/licenses/src/pip/_vendor/truststore/LICENSE +21 -0
  220. pip-25.3.dist-info/licenses/src/pip/_vendor/urllib3/LICENSE.txt +21 -0
  221. pip/_internal/operations/build/metadata_legacy.py +0 -73
  222. pip/_internal/operations/build/wheel_legacy.py +0 -118
  223. pip/_internal/operations/install/editable_legacy.py +0 -46
  224. pip/_internal/utils/setuptools_build.py +0 -147
  225. pip/_vendor/distlib/database.py +0 -1329
  226. pip/_vendor/distlib/index.py +0 -508
  227. pip/_vendor/distlib/locators.py +0 -1295
  228. pip/_vendor/distlib/manifest.py +0 -384
  229. pip/_vendor/distlib/markers.py +0 -162
  230. pip/_vendor/distlib/metadata.py +0 -1031
  231. pip/_vendor/distlib/version.py +0 -750
  232. pip/_vendor/distlib/wheel.py +0 -1100
  233. pip/_vendor/typing_extensions.py +0 -4584
  234. pip-25.1.1.dist-info/entry_points.txt +0 -3
  235. pip-25.1.1.dist-info/top_level.txt +0 -1
  236. {pip-25.1.1.dist-info → pip-25.3.dist-info}/licenses/LICENSE.txt +0 -0
@@ -1,11 +1,13 @@
1
+ from __future__ import annotations
2
+
1
3
  import abc
2
- from typing import TYPE_CHECKING, Optional
4
+ from typing import TYPE_CHECKING
3
5
 
4
6
  from pip._internal.metadata.base import BaseDistribution
5
7
  from pip._internal.req import InstallRequirement
6
8
 
7
9
  if TYPE_CHECKING:
8
- from pip._internal.index.package_finder import PackageFinder
10
+ from pip._internal.build_env import BuildEnvironmentInstaller
9
11
 
10
12
 
11
13
  class AbstractDistribution(metaclass=abc.ABCMeta):
@@ -32,7 +34,7 @@ class AbstractDistribution(metaclass=abc.ABCMeta):
32
34
  self.req = req
33
35
 
34
36
  @abc.abstractproperty
35
- def build_tracker_id(self) -> Optional[str]:
37
+ def build_tracker_id(self) -> str | None:
36
38
  """A string that uniquely identifies this requirement to the build tracker.
37
39
 
38
40
  If None, then this dist has no work to do in the build tracker, and
@@ -46,7 +48,7 @@ class AbstractDistribution(metaclass=abc.ABCMeta):
46
48
  @abc.abstractmethod
47
49
  def prepare_distribution_metadata(
48
50
  self,
49
- finder: "PackageFinder",
51
+ build_env_installer: BuildEnvironmentInstaller,
50
52
  build_isolation: bool,
51
53
  check_build_deps: bool,
52
54
  ) -> None:
@@ -1,9 +1,13 @@
1
- from typing import Optional
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING
2
4
 
3
5
  from pip._internal.distributions.base import AbstractDistribution
4
- from pip._internal.index.package_finder import PackageFinder
5
6
  from pip._internal.metadata import BaseDistribution
6
7
 
8
+ if TYPE_CHECKING:
9
+ from pip._internal.build_env import BuildEnvironmentInstaller
10
+
7
11
 
8
12
  class InstalledDistribution(AbstractDistribution):
9
13
  """Represents an installed package.
@@ -13,7 +17,7 @@ class InstalledDistribution(AbstractDistribution):
13
17
  """
14
18
 
15
19
  @property
16
- def build_tracker_id(self) -> Optional[str]:
20
+ def build_tracker_id(self) -> str | None:
17
21
  return None
18
22
 
19
23
  def get_metadata_distribution(self) -> BaseDistribution:
@@ -22,7 +26,7 @@ class InstalledDistribution(AbstractDistribution):
22
26
 
23
27
  def prepare_distribution_metadata(
24
28
  self,
25
- finder: PackageFinder,
29
+ build_env_installer: BuildEnvironmentInstaller,
26
30
  build_isolation: bool,
27
31
  check_build_deps: bool,
28
32
  ) -> None:
@@ -1,5 +1,8 @@
1
+ from __future__ import annotations
2
+
1
3
  import logging
2
- from typing import TYPE_CHECKING, Iterable, Optional, Set, Tuple
4
+ from collections.abc import Iterable
5
+ from typing import TYPE_CHECKING
3
6
 
4
7
  from pip._internal.build_env import BuildEnvironment
5
8
  from pip._internal.distributions.base import AbstractDistribution
@@ -8,7 +11,7 @@ from pip._internal.metadata import BaseDistribution
8
11
  from pip._internal.utils.subprocess import runner_with_spinner_message
9
12
 
10
13
  if TYPE_CHECKING:
11
- from pip._internal.index.package_finder import PackageFinder
14
+ from pip._internal.build_env import BuildEnvironmentInstaller
12
15
 
13
16
  logger = logging.getLogger(__name__)
14
17
 
@@ -17,11 +20,11 @@ class SourceDistribution(AbstractDistribution):
17
20
  """Represents a source distribution.
18
21
 
19
22
  The preparation step for these needs metadata for the packages to be
20
- generated, either using PEP 517 or using the legacy `setup.py egg_info`.
23
+ generated.
21
24
  """
22
25
 
23
26
  @property
24
- def build_tracker_id(self) -> Optional[str]:
27
+ def build_tracker_id(self) -> str | None:
25
28
  """Identify this requirement uniquely by its link."""
26
29
  assert self.req.link
27
30
  return self.req.link.url_without_fragment
@@ -31,32 +34,31 @@ class SourceDistribution(AbstractDistribution):
31
34
 
32
35
  def prepare_distribution_metadata(
33
36
  self,
34
- finder: "PackageFinder",
37
+ build_env_installer: BuildEnvironmentInstaller,
35
38
  build_isolation: bool,
36
39
  check_build_deps: bool,
37
40
  ) -> None:
38
- # Load pyproject.toml, to determine whether PEP 517 is to be used
41
+ # Load pyproject.toml
39
42
  self.req.load_pyproject_toml()
40
43
 
41
44
  # Set up the build isolation, if this requirement should be isolated
42
- should_isolate = self.req.use_pep517 and build_isolation
43
- if should_isolate:
45
+ if build_isolation:
44
46
  # Setup an isolated environment and install the build backend static
45
47
  # requirements in it.
46
- self._prepare_build_backend(finder)
47
- # Check that if the requirement is editable, it either supports PEP 660 or
48
- # has a setup.py or a setup.cfg. This cannot be done earlier because we need
49
- # to setup the build backend to verify it supports build_editable, nor can
50
- # it be done later, because we want to avoid installing build requirements
51
- # needlessly. Doing it here also works around setuptools generating
52
- # UNKNOWN.egg-info when running get_requires_for_build_wheel on a directory
53
- # without setup.py nor setup.cfg.
54
- self.req.isolated_editable_sanity_check()
48
+ self._prepare_build_backend(build_env_installer)
49
+ # Check that the build backend supports PEP 660. This cannot be done
50
+ # earlier because we need to setup the build backend to verify it
51
+ # supports build_editable, nor can it be done later, because we want
52
+ # to avoid installing build requirements needlessly.
53
+ self.req.editable_sanity_check()
55
54
  # Install the dynamic build requirements.
56
- self._install_build_reqs(finder)
55
+ self._install_build_reqs(build_env_installer)
56
+ else:
57
+ # When not using build isolation, we still need to check that
58
+ # the build backend supports PEP 660.
59
+ self.req.editable_sanity_check()
57
60
  # Check if the current environment provides build dependencies
58
- should_check_deps = self.req.use_pep517 and check_build_deps
59
- if should_check_deps:
61
+ if check_build_deps:
60
62
  pyproject_requires = self.req.pyproject_requires
61
63
  assert pyproject_requires is not None
62
64
  conflicting, missing = self.req.build_env.check_requirements(
@@ -68,15 +70,17 @@ class SourceDistribution(AbstractDistribution):
68
70
  self._raise_missing_reqs(missing)
69
71
  self.req.prepare_metadata()
70
72
 
71
- def _prepare_build_backend(self, finder: "PackageFinder") -> None:
73
+ def _prepare_build_backend(
74
+ self, build_env_installer: BuildEnvironmentInstaller
75
+ ) -> None:
72
76
  # Isolate in a BuildEnvironment and install the build-time
73
77
  # requirements.
74
78
  pyproject_requires = self.req.pyproject_requires
75
79
  assert pyproject_requires is not None
76
80
 
77
- self.req.build_env = BuildEnvironment()
81
+ self.req.build_env = BuildEnvironment(build_env_installer)
78
82
  self.req.build_env.install_requirements(
79
- finder, pyproject_requires, "overlay", kind="build dependencies"
83
+ pyproject_requires, "overlay", kind="build dependencies", for_req=self.req
80
84
  )
81
85
  conflicting, missing = self.req.build_env.check_requirements(
82
86
  self.req.requirements_to_check
@@ -112,7 +116,9 @@ class SourceDistribution(AbstractDistribution):
112
116
  with backend.subprocess_runner(runner):
113
117
  return backend.get_requires_for_build_editable()
114
118
 
115
- def _install_build_reqs(self, finder: "PackageFinder") -> None:
119
+ def _install_build_reqs(
120
+ self, build_env_installer: BuildEnvironmentInstaller
121
+ ) -> None:
116
122
  # Install any extra build dependencies that the backend requests.
117
123
  # This must be done in a second pass, as the pyproject.toml
118
124
  # dependencies must be installed before we can call the backend.
@@ -128,11 +134,11 @@ class SourceDistribution(AbstractDistribution):
128
134
  if conflicting:
129
135
  self._raise_conflicts("the backend dependencies", conflicting)
130
136
  self.req.build_env.install_requirements(
131
- finder, missing, "normal", kind="backend dependencies"
137
+ missing, "normal", kind="backend dependencies", for_req=self.req
132
138
  )
133
139
 
134
140
  def _raise_conflicts(
135
- self, conflicting_with: str, conflicting_reqs: Set[Tuple[str, str]]
141
+ self, conflicting_with: str, conflicting_reqs: set[tuple[str, str]]
136
142
  ) -> None:
137
143
  format_string = (
138
144
  "Some build dependencies for {requirement} "
@@ -148,7 +154,7 @@ class SourceDistribution(AbstractDistribution):
148
154
  )
149
155
  raise InstallationError(error_message)
150
156
 
151
- def _raise_missing_reqs(self, missing: Set[str]) -> None:
157
+ def _raise_missing_reqs(self, missing: set[str]) -> None:
152
158
  format_string = (
153
159
  "Some build dependencies for {requirement} are missing: {missing}."
154
160
  )
@@ -1,4 +1,6 @@
1
- from typing import TYPE_CHECKING, Optional
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING
2
4
 
3
5
  from pip._vendor.packaging.utils import canonicalize_name
4
6
 
@@ -10,7 +12,7 @@ from pip._internal.metadata import (
10
12
  )
11
13
 
12
14
  if TYPE_CHECKING:
13
- from pip._internal.index.package_finder import PackageFinder
15
+ from pip._internal.build_env import BuildEnvironmentInstaller
14
16
 
15
17
 
16
18
  class WheelDistribution(AbstractDistribution):
@@ -20,7 +22,7 @@ class WheelDistribution(AbstractDistribution):
20
22
  """
21
23
 
22
24
  @property
23
- def build_tracker_id(self) -> Optional[str]:
25
+ def build_tracker_id(self) -> str | None:
24
26
  return None
25
27
 
26
28
  def get_metadata_distribution(self) -> BaseDistribution:
@@ -35,7 +37,7 @@ class WheelDistribution(AbstractDistribution):
35
37
 
36
38
  def prepare_distribution_metadata(
37
39
  self,
38
- finder: "PackageFinder",
40
+ build_env_installer: BuildEnvironmentInstaller,
39
41
  build_isolation: bool,
40
42
  check_build_deps: bool,
41
43
  ) -> None:
@@ -5,6 +5,8 @@ operate. This is expected to be importable from any/all files within the
5
5
  subpackage and, thus, should not depend on them.
6
6
  """
7
7
 
8
+ from __future__ import annotations
9
+
8
10
  import configparser
9
11
  import contextlib
10
12
  import locale
@@ -12,8 +14,9 @@ import logging
12
14
  import pathlib
13
15
  import re
14
16
  import sys
17
+ from collections.abc import Iterator
15
18
  from itertools import chain, groupby, repeat
16
- from typing import TYPE_CHECKING, Dict, Iterator, List, Literal, Optional, Union
19
+ from typing import TYPE_CHECKING, Literal
17
20
 
18
21
  from pip._vendor.packaging.requirements import InvalidRequirement
19
22
  from pip._vendor.packaging.version import InvalidVersion
@@ -27,7 +30,7 @@ if TYPE_CHECKING:
27
30
  from pip._vendor.requests.models import Request, Response
28
31
 
29
32
  from pip._internal.metadata import BaseDistribution
30
- from pip._internal.models.link import Link
33
+ from pip._internal.network.download import _FileDownload
31
34
  from pip._internal.req.req_install import InstallRequirement
32
35
 
33
36
  logger = logging.getLogger(__name__)
@@ -41,7 +44,7 @@ def _is_kebab_case(s: str) -> bool:
41
44
 
42
45
 
43
46
  def _prefix_with_indent(
44
- s: Union[Text, str],
47
+ s: Text | str,
45
48
  console: Console,
46
49
  *,
47
50
  prefix: str,
@@ -77,13 +80,13 @@ class DiagnosticPipError(PipError):
77
80
  def __init__(
78
81
  self,
79
82
  *,
80
- kind: 'Literal["error", "warning"]' = "error",
81
- reference: Optional[str] = None,
82
- message: Union[str, Text],
83
- context: Optional[Union[str, Text]],
84
- hint_stmt: Optional[Union[str, Text]],
85
- note_stmt: Optional[Union[str, Text]] = None,
86
- link: Optional[str] = None,
83
+ kind: Literal["error", "warning"] = "error",
84
+ reference: str | None = None,
85
+ message: str | Text,
86
+ context: str | Text | None,
87
+ hint_stmt: str | Text | None,
88
+ note_stmt: str | Text | None = None,
89
+ link: str | None = None,
87
90
  ) -> None:
88
91
  # Ensure a proper reference is provided.
89
92
  if reference is None:
@@ -187,6 +190,23 @@ class InstallationError(PipError):
187
190
  """General exception during installation"""
188
191
 
189
192
 
193
+ class FailedToPrepareCandidate(InstallationError):
194
+ """Raised when we fail to prepare a candidate (i.e. fetch and generate metadata).
195
+
196
+ This is intentionally not a diagnostic error, since the output will be presented
197
+ above this error, when this occurs. This should instead present information to the
198
+ user.
199
+ """
200
+
201
+ def __init__(
202
+ self, *, package_name: str, requirement_chain: str, failed_step: str
203
+ ) -> None:
204
+ super().__init__(f"Failed to build '{package_name}' when {failed_step.lower()}")
205
+ self.package_name = package_name
206
+ self.requirement_chain = requirement_chain
207
+ self.failed_step = failed_step
208
+
209
+
190
210
  class MissingPyProjectBuildRequires(DiagnosticPipError):
191
211
  """Raised when pyproject.toml has `build-system`, but no `build-system.requires`."""
192
212
 
@@ -232,7 +252,7 @@ class NoneMetadataError(PipError):
232
252
 
233
253
  def __init__(
234
254
  self,
235
- dist: "BaseDistribution",
255
+ dist: BaseDistribution,
236
256
  metadata_name: str,
237
257
  ) -> None:
238
258
  """
@@ -293,8 +313,8 @@ class NetworkConnectionError(PipError):
293
313
  def __init__(
294
314
  self,
295
315
  error_msg: str,
296
- response: Optional["Response"] = None,
297
- request: Optional["Request"] = None,
316
+ response: Response | None = None,
317
+ request: Request | None = None,
298
318
  ) -> None:
299
319
  """
300
320
  Initialize NetworkConnectionError with `request` and `response`
@@ -343,7 +363,7 @@ class MetadataInconsistent(InstallationError):
343
363
  """
344
364
 
345
365
  def __init__(
346
- self, ireq: "InstallRequirement", field: str, f_val: str, m_val: str
366
+ self, ireq: InstallRequirement, field: str, f_val: str, m_val: str
347
367
  ) -> None:
348
368
  self.ireq = ireq
349
369
  self.field = field
@@ -360,7 +380,7 @@ class MetadataInconsistent(InstallationError):
360
380
  class MetadataInvalid(InstallationError):
361
381
  """Metadata is invalid."""
362
382
 
363
- def __init__(self, ireq: "InstallRequirement", error: str) -> None:
383
+ def __init__(self, ireq: InstallRequirement, error: str) -> None:
364
384
  self.ireq = ireq
365
385
  self.error = error
366
386
 
@@ -378,10 +398,10 @@ class InstallationSubprocessError(DiagnosticPipError, InstallationError):
378
398
  *,
379
399
  command_description: str,
380
400
  exit_code: int,
381
- output_lines: Optional[List[str]],
401
+ output_lines: list[str] | None,
382
402
  ) -> None:
383
403
  if output_lines is None:
384
- output_prompt = Text("See above for output.")
404
+ output_prompt = Text("No available output.")
385
405
  else:
386
406
  output_prompt = (
387
407
  Text.from_markup(f"[red][{len(output_lines)} lines of output][/]\n")
@@ -409,7 +429,7 @@ class InstallationSubprocessError(DiagnosticPipError, InstallationError):
409
429
  return f"{self.command_description} exited with {self.exit_code}"
410
430
 
411
431
 
412
- class MetadataGenerationFailed(InstallationSubprocessError, InstallationError):
432
+ class MetadataGenerationFailed(DiagnosticPipError, InstallationError):
413
433
  reference = "metadata-generation-failed"
414
434
 
415
435
  def __init__(
@@ -417,7 +437,7 @@ class MetadataGenerationFailed(InstallationSubprocessError, InstallationError):
417
437
  *,
418
438
  package_details: str,
419
439
  ) -> None:
420
- super(InstallationSubprocessError, self).__init__(
440
+ super().__init__(
421
441
  message="Encountered error while generating package metadata.",
422
442
  context=escape(package_details),
423
443
  hint_stmt="See above for details.",
@@ -432,9 +452,9 @@ class HashErrors(InstallationError):
432
452
  """Multiple HashError instances rolled into one for reporting"""
433
453
 
434
454
  def __init__(self) -> None:
435
- self.errors: List[HashError] = []
455
+ self.errors: list[HashError] = []
436
456
 
437
- def append(self, error: "HashError") -> None:
457
+ def append(self, error: HashError) -> None:
438
458
  self.errors.append(error)
439
459
 
440
460
  def __str__(self) -> str:
@@ -468,7 +488,7 @@ class HashError(InstallationError):
468
488
 
469
489
  """
470
490
 
471
- req: Optional["InstallRequirement"] = None
491
+ req: InstallRequirement | None = None
472
492
  head = ""
473
493
  order: int = -1
474
494
 
@@ -590,7 +610,7 @@ class HashMismatch(HashError):
590
610
  "someone may have tampered with them."
591
611
  )
592
612
 
593
- def __init__(self, allowed: Dict[str, List[str]], gots: Dict[str, "_Hash"]) -> None:
613
+ def __init__(self, allowed: dict[str, list[str]], gots: dict[str, _Hash]) -> None:
594
614
  """
595
615
  :param allowed: A dict of algorithm names pointing to lists of allowed
596
616
  hex digests
@@ -615,12 +635,12 @@ class HashMismatch(HashError):
615
635
 
616
636
  """
617
637
 
618
- def hash_then_or(hash_name: str) -> "chain[str]":
638
+ def hash_then_or(hash_name: str) -> chain[str]:
619
639
  # For now, all the decent hashes have 6-char names, so we can get
620
640
  # away with hard-coding space literals.
621
641
  return chain([hash_name], repeat(" or"))
622
642
 
623
- lines: List[str] = []
643
+ lines: list[str] = []
624
644
  for hash_name, expecteds in self.allowed.items():
625
645
  prefix = hash_then_or(hash_name)
626
646
  lines.extend((f" Expected {next(prefix)} {e}") for e in expecteds)
@@ -641,8 +661,8 @@ class ConfigurationFileCouldNotBeLoaded(ConfigurationError):
641
661
  def __init__(
642
662
  self,
643
663
  reason: str = "could not be loaded",
644
- fname: Optional[str] = None,
645
- error: Optional[configparser.Error] = None,
664
+ fname: str | None = None,
665
+ error: configparser.Error | None = None,
646
666
  ) -> None:
647
667
  super().__init__(error)
648
668
  self.reason = reason
@@ -677,7 +697,7 @@ class ExternallyManagedEnvironment(DiagnosticPipError):
677
697
 
678
698
  reference = "externally-managed-environment"
679
699
 
680
- def __init__(self, error: Optional[str]) -> None:
700
+ def __init__(self, error: str | None) -> None:
681
701
  if error is None:
682
702
  context = Text(_DEFAULT_EXTERNALLY_MANAGED_ERROR)
683
703
  else:
@@ -704,7 +724,7 @@ class ExternallyManagedEnvironment(DiagnosticPipError):
704
724
  try:
705
725
  category = locale.LC_MESSAGES
706
726
  except AttributeError:
707
- lang: Optional[str] = None
727
+ lang: str | None = None
708
728
  else:
709
729
  lang, _ = locale.getlocale(category)
710
730
  if lang is not None:
@@ -719,8 +739,8 @@ class ExternallyManagedEnvironment(DiagnosticPipError):
719
739
  @classmethod
720
740
  def from_config(
721
741
  cls,
722
- config: Union[pathlib.Path, str],
723
- ) -> "ExternallyManagedEnvironment":
742
+ config: pathlib.Path | str,
743
+ ) -> ExternallyManagedEnvironment:
724
744
  parser = configparser.ConfigParser(interpolation=None)
725
745
  try:
726
746
  parser.read(config, encoding="utf-8")
@@ -741,7 +761,7 @@ class ExternallyManagedEnvironment(DiagnosticPipError):
741
761
  class UninstallMissingRecord(DiagnosticPipError):
742
762
  reference = "uninstall-no-record-file"
743
763
 
744
- def __init__(self, *, distribution: "BaseDistribution") -> None:
764
+ def __init__(self, *, distribution: BaseDistribution) -> None:
745
765
  installer = distribution.installer
746
766
  if not installer or installer == "pip":
747
767
  dep = f"{distribution.raw_name}=={distribution.version}"
@@ -768,7 +788,7 @@ class UninstallMissingRecord(DiagnosticPipError):
768
788
  class LegacyDistutilsInstall(DiagnosticPipError):
769
789
  reference = "uninstall-distutils-installed-package"
770
790
 
771
- def __init__(self, *, distribution: "BaseDistribution") -> None:
791
+ def __init__(self, *, distribution: BaseDistribution) -> None:
772
792
  super().__init__(
773
793
  message=Text(f"Cannot uninstall {distribution}"),
774
794
  context=(
@@ -786,8 +806,8 @@ class InvalidInstalledPackage(DiagnosticPipError):
786
806
  def __init__(
787
807
  self,
788
808
  *,
789
- dist: "BaseDistribution",
790
- invalid_exc: Union[InvalidRequirement, InvalidVersion],
809
+ dist: BaseDistribution,
810
+ invalid_exc: InvalidRequirement | InvalidVersion,
791
811
  ) -> None:
792
812
  installed_location = dist.installed_location
793
813
 
@@ -816,17 +836,19 @@ class IncompleteDownloadError(DiagnosticPipError):
816
836
 
817
837
  reference = "incomplete-download"
818
838
 
819
- def __init__(
820
- self, link: "Link", received: int, expected: int, *, retries: int
821
- ) -> None:
839
+ def __init__(self, download: _FileDownload) -> None:
822
840
  # Dodge circular import.
823
841
  from pip._internal.utils.misc import format_size
824
842
 
825
- download_status = f"{format_size(received)}/{format_size(expected)}"
826
- if retries:
827
- retry_status = f"after {retries} attempts "
843
+ assert download.size is not None
844
+ download_status = (
845
+ f"{format_size(download.bytes_received)}/{format_size(download.size)}"
846
+ )
847
+ if download.reattempts:
848
+ retry_status = f"after {download.reattempts + 1} attempts "
828
849
  hint = "Use --resume-retries to configure resume attempt limit."
829
850
  else:
851
+ # Download retrying is not enabled.
830
852
  retry_status = ""
831
853
  hint = "Consider using --resume-retries to enable download resumption."
832
854
  message = Text(
@@ -836,7 +858,7 @@ class IncompleteDownloadError(DiagnosticPipError):
836
858
 
837
859
  super().__init__(
838
860
  message=message,
839
- context=f"URL: {link.redacted_url}",
861
+ context=f"URL: {download.link.redacted_url}",
840
862
  hint_stmt=hint,
841
863
  note_stmt="This is an issue with network connectivity, not pip.",
842
864
  )
@@ -860,3 +882,17 @@ class ResolutionTooDeepError(DiagnosticPipError):
860
882
  ),
861
883
  link="https://pip.pypa.io/en/stable/topics/dependency-resolution/#handling-resolution-too-deep-errors",
862
884
  )
885
+
886
+
887
+ class InstallWheelBuildError(DiagnosticPipError):
888
+ reference = "failed-wheel-build-for-install"
889
+
890
+ def __init__(self, failed: list[InstallRequirement]) -> None:
891
+ super().__init__(
892
+ message=(
893
+ "Failed to build installable wheels for some "
894
+ "pyproject.toml based projects"
895
+ ),
896
+ context=", ".join(r.name for r in failed), # type: ignore
897
+ hint_stmt=None,
898
+ )