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
@@ -10,11 +10,14 @@ for sub-dependencies
10
10
  a. "first found, wins" (where the order is breadth first)
11
11
  """
12
12
 
13
+ from __future__ import annotations
14
+
13
15
  import logging
14
16
  import sys
15
17
  from collections import defaultdict
18
+ from collections.abc import Iterable
16
19
  from itertools import chain
17
- from typing import DefaultDict, Iterable, List, Optional, Set, Tuple
20
+ from typing import Optional
18
21
 
19
22
  from pip._vendor.packaging import specifiers
20
23
  from pip._vendor.packaging.requirements import Requirement
@@ -49,12 +52,12 @@ from pip._internal.utils.packaging import check_requires_python
49
52
 
50
53
  logger = logging.getLogger(__name__)
51
54
 
52
- DiscoveredDependencies = DefaultDict[Optional[str], List[InstallRequirement]]
55
+ DiscoveredDependencies = defaultdict[Optional[str], list[InstallRequirement]]
53
56
 
54
57
 
55
58
  def _check_dist_requires_python(
56
59
  dist: BaseDistribution,
57
- version_info: Tuple[int, int, int],
60
+ version_info: tuple[int, int, int],
58
61
  ignore_requires_python: bool = False,
59
62
  ) -> None:
60
63
  """
@@ -117,7 +120,7 @@ class Resolver(BaseResolver):
117
120
  self,
118
121
  preparer: RequirementPreparer,
119
122
  finder: PackageFinder,
120
- wheel_cache: Optional[WheelCache],
123
+ wheel_cache: WheelCache | None,
121
124
  make_install_req: InstallRequirementProvider,
122
125
  use_user_site: bool,
123
126
  ignore_dependencies: bool,
@@ -125,7 +128,7 @@ class Resolver(BaseResolver):
125
128
  ignore_requires_python: bool,
126
129
  force_reinstall: bool,
127
130
  upgrade_strategy: str,
128
- py_version_info: Optional[Tuple[int, ...]] = None,
131
+ py_version_info: tuple[int, ...] | None = None,
129
132
  ) -> None:
130
133
  super().__init__()
131
134
  assert upgrade_strategy in self._allowed_strategies
@@ -152,7 +155,7 @@ class Resolver(BaseResolver):
152
155
  self._discovered_dependencies: DiscoveredDependencies = defaultdict(list)
153
156
 
154
157
  def resolve(
155
- self, root_reqs: List[InstallRequirement], check_supported_wheels: bool
158
+ self, root_reqs: list[InstallRequirement], check_supported_wheels: bool
156
159
  ) -> RequirementSet:
157
160
  """Resolve what operations need to be done
158
161
 
@@ -174,7 +177,7 @@ class Resolver(BaseResolver):
174
177
  # exceptions cannot be checked ahead of time, because
175
178
  # _populate_link() needs to be called before we can make decisions
176
179
  # based on link type.
177
- discovered_reqs: List[InstallRequirement] = []
180
+ discovered_reqs: list[InstallRequirement] = []
178
181
  hash_errors = HashErrors()
179
182
  for req in chain(requirement_set.all_requirements, discovered_reqs):
180
183
  try:
@@ -192,9 +195,9 @@ class Resolver(BaseResolver):
192
195
  self,
193
196
  requirement_set: RequirementSet,
194
197
  install_req: InstallRequirement,
195
- parent_req_name: Optional[str] = None,
196
- extras_requested: Optional[Iterable[str]] = None,
197
- ) -> Tuple[List[InstallRequirement], Optional[InstallRequirement]]:
198
+ parent_req_name: str | None = None,
199
+ extras_requested: Iterable[str] | None = None,
200
+ ) -> tuple[list[InstallRequirement], InstallRequirement | None]:
198
201
  """Add install_req as a requirement to install.
199
202
 
200
203
  :param parent_req_name: The name of the requirement that needed this
@@ -242,8 +245,8 @@ class Resolver(BaseResolver):
242
245
  return [install_req], None
243
246
 
244
247
  try:
245
- existing_req: Optional[InstallRequirement] = (
246
- requirement_set.get_requirement(install_req.name)
248
+ existing_req: InstallRequirement | None = requirement_set.get_requirement(
249
+ install_req.name
247
250
  )
248
251
  except KeyError:
249
252
  existing_req = None
@@ -323,9 +326,7 @@ class Resolver(BaseResolver):
323
326
  req.should_reinstall = True
324
327
  req.satisfied_by = None
325
328
 
326
- def _check_skip_installed(
327
- self, req_to_install: InstallRequirement
328
- ) -> Optional[str]:
329
+ def _check_skip_installed(self, req_to_install: InstallRequirement) -> str | None:
329
330
  """Check if req_to_install should be skipped.
330
331
 
331
332
  This will check if the req is installed, and whether we should upgrade
@@ -377,7 +378,7 @@ class Resolver(BaseResolver):
377
378
  self._set_req_to_reinstall(req_to_install)
378
379
  return None
379
380
 
380
- def _find_requirement_link(self, req: InstallRequirement) -> Optional[Link]:
381
+ def _find_requirement_link(self, req: InstallRequirement) -> Link | None:
381
382
  upgrade = self._is_upgrade_allowed(req)
382
383
  best_candidate = self.finder.find_requirement(req, upgrade)
383
384
  if not best_candidate:
@@ -488,7 +489,7 @@ class Resolver(BaseResolver):
488
489
  self,
489
490
  requirement_set: RequirementSet,
490
491
  req_to_install: InstallRequirement,
491
- ) -> List[InstallRequirement]:
492
+ ) -> list[InstallRequirement]:
492
493
  """Prepare a single requirements file.
493
494
 
494
495
  :return: A list of additional InstallRequirements to also install.
@@ -511,7 +512,7 @@ class Resolver(BaseResolver):
511
512
  ignore_requires_python=self.ignore_requires_python,
512
513
  )
513
514
 
514
- more_reqs: List[InstallRequirement] = []
515
+ more_reqs: list[InstallRequirement] = []
515
516
 
516
517
  def add_req(subreq: Requirement, extras_requested: Iterable[str]) -> None:
517
518
  # This idiosyncratically converts the Requirement to str and let
@@ -569,7 +570,7 @@ class Resolver(BaseResolver):
569
570
 
570
571
  def get_installation_order(
571
572
  self, req_set: RequirementSet
572
- ) -> List[InstallRequirement]:
573
+ ) -> list[InstallRequirement]:
573
574
  """Create the installation order.
574
575
 
575
576
  The installation order is topological - requirements are installed
@@ -580,7 +581,7 @@ class Resolver(BaseResolver):
580
581
  # installs the user specified things in the order given, except when
581
582
  # dependencies must come earlier to achieve topological order.
582
583
  order = []
583
- ordered_reqs: Set[InstallRequirement] = set()
584
+ ordered_reqs: set[InstallRequirement] = set()
584
585
 
585
586
  def schedule(req: InstallRequirement) -> None:
586
587
  if req.satisfied_by or req in ordered_reqs:
@@ -1,5 +1,8 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Iterable
1
4
  from dataclasses import dataclass
2
- from typing import FrozenSet, Iterable, Optional, Tuple
5
+ from typing import Optional
3
6
 
4
7
  from pip._vendor.packaging.specifiers import SpecifierSet
5
8
  from pip._vendor.packaging.utils import NormalizedName
@@ -9,10 +12,10 @@ from pip._internal.models.link import Link, links_equivalent
9
12
  from pip._internal.req.req_install import InstallRequirement
10
13
  from pip._internal.utils.hashes import Hashes
11
14
 
12
- CandidateLookup = Tuple[Optional["Candidate"], Optional[InstallRequirement]]
15
+ CandidateLookup = tuple[Optional["Candidate"], Optional[InstallRequirement]]
13
16
 
14
17
 
15
- def format_name(project: NormalizedName, extras: FrozenSet[NormalizedName]) -> str:
18
+ def format_name(project: NormalizedName, extras: frozenset[NormalizedName]) -> str:
16
19
  if not extras:
17
20
  return project
18
21
  extras_expr = ",".join(sorted(extras))
@@ -23,21 +26,21 @@ def format_name(project: NormalizedName, extras: FrozenSet[NormalizedName]) -> s
23
26
  class Constraint:
24
27
  specifier: SpecifierSet
25
28
  hashes: Hashes
26
- links: FrozenSet[Link]
29
+ links: frozenset[Link]
27
30
 
28
31
  @classmethod
29
- def empty(cls) -> "Constraint":
32
+ def empty(cls) -> Constraint:
30
33
  return Constraint(SpecifierSet(), Hashes(), frozenset())
31
34
 
32
35
  @classmethod
33
- def from_ireq(cls, ireq: InstallRequirement) -> "Constraint":
36
+ def from_ireq(cls, ireq: InstallRequirement) -> Constraint:
34
37
  links = frozenset([ireq.link]) if ireq.link else frozenset()
35
38
  return Constraint(ireq.specifier, ireq.hashes(trust_internet=False), links)
36
39
 
37
40
  def __bool__(self) -> bool:
38
41
  return bool(self.specifier) or bool(self.hashes) or bool(self.links)
39
42
 
40
- def __and__(self, other: InstallRequirement) -> "Constraint":
43
+ def __and__(self, other: InstallRequirement) -> Constraint:
41
44
  if not isinstance(other, InstallRequirement):
42
45
  return NotImplemented
43
46
  specifier = self.specifier & other.specifier
@@ -47,7 +50,7 @@ class Constraint:
47
50
  links = links.union([other.link])
48
51
  return Constraint(specifier, hashes, links)
49
52
 
50
- def is_satisfied_by(self, candidate: "Candidate") -> bool:
53
+ def is_satisfied_by(self, candidate: Candidate) -> bool:
51
54
  # Reject if there are any mismatched URL constraints on this package.
52
55
  if self.links and not all(_match_link(link, candidate) for link in self.links):
53
56
  return False
@@ -77,7 +80,7 @@ class Requirement:
77
80
  """
78
81
  raise NotImplementedError("Subclass should override")
79
82
 
80
- def is_satisfied_by(self, candidate: "Candidate") -> bool:
83
+ def is_satisfied_by(self, candidate: Candidate) -> bool:
81
84
  return False
82
85
 
83
86
  def get_candidate_lookup(self) -> CandidateLookup:
@@ -87,7 +90,7 @@ class Requirement:
87
90
  raise NotImplementedError("Subclass should override")
88
91
 
89
92
 
90
- def _match_link(link: Link, candidate: "Candidate") -> bool:
93
+ def _match_link(link: Link, candidate: Candidate) -> bool:
91
94
  if candidate.source_link:
92
95
  return links_equivalent(link, candidate.source_link)
93
96
  return False
@@ -126,13 +129,13 @@ class Candidate:
126
129
  raise NotImplementedError("Override in subclass")
127
130
 
128
131
  @property
129
- def source_link(self) -> Optional[Link]:
132
+ def source_link(self) -> Link | None:
130
133
  raise NotImplementedError("Override in subclass")
131
134
 
132
- def iter_dependencies(self, with_requires: bool) -> Iterable[Optional[Requirement]]:
135
+ def iter_dependencies(self, with_requires: bool) -> Iterable[Requirement | None]:
133
136
  raise NotImplementedError("Override in subclass")
134
137
 
135
- def get_install_requirement(self) -> Optional[InstallRequirement]:
138
+ def get_install_requirement(self) -> InstallRequirement | None:
136
139
  raise NotImplementedError("Override in subclass")
137
140
 
138
141
  def format_for_error(self) -> str:
@@ -1,12 +1,16 @@
1
+ from __future__ import annotations
2
+
1
3
  import logging
2
4
  import sys
3
- from typing import TYPE_CHECKING, Any, FrozenSet, Iterable, Optional, Tuple, Union, cast
5
+ from collections.abc import Iterable
6
+ from typing import TYPE_CHECKING, Any, Union, cast
4
7
 
5
8
  from pip._vendor.packaging.requirements import InvalidRequirement
6
9
  from pip._vendor.packaging.utils import NormalizedName, canonicalize_name
7
10
  from pip._vendor.packaging.version import Version
8
11
 
9
12
  from pip._internal.exceptions import (
13
+ FailedToPrepareCandidate,
10
14
  HashError,
11
15
  InstallationSubprocessError,
12
16
  InvalidInstalledPackage,
@@ -41,7 +45,7 @@ BaseCandidate = Union[
41
45
  REQUIRES_PYTHON_IDENTIFIER = cast(NormalizedName, "<Python from Requires-Python>")
42
46
 
43
47
 
44
- def as_base_candidate(candidate: Candidate) -> Optional[BaseCandidate]:
48
+ def as_base_candidate(candidate: Candidate) -> BaseCandidate | None:
45
49
  """The runtime version of BaseCandidate."""
46
50
  base_candidate_classes = (
47
51
  AlreadyInstalledCandidate,
@@ -65,10 +69,8 @@ def make_install_req_from_link(
65
69
  line,
66
70
  user_supplied=template.user_supplied,
67
71
  comes_from=template.comes_from,
68
- use_pep517=template.use_pep517,
69
72
  isolated=template.isolated,
70
73
  constraint=template.constraint,
71
- global_options=template.global_options,
72
74
  hash_options=template.hash_options,
73
75
  config_settings=template.config_settings,
74
76
  )
@@ -82,15 +84,17 @@ def make_install_req_from_editable(
82
84
  link: Link, template: InstallRequirement
83
85
  ) -> InstallRequirement:
84
86
  assert template.editable, "template not editable"
87
+ if template.name:
88
+ req_string = f"{template.name} @ {link.url}"
89
+ else:
90
+ req_string = link.url
85
91
  ireq = install_req_from_editable(
86
- link.url,
92
+ req_string,
87
93
  user_supplied=template.user_supplied,
88
94
  comes_from=template.comes_from,
89
- use_pep517=template.use_pep517,
90
95
  isolated=template.isolated,
91
96
  constraint=template.constraint,
92
97
  permit_editable_wheels=template.permit_editable_wheels,
93
- global_options=template.global_options,
94
98
  hash_options=template.hash_options,
95
99
  config_settings=template.config_settings,
96
100
  )
@@ -111,10 +115,8 @@ def _make_install_req_from_dist(
111
115
  line,
112
116
  user_supplied=template.user_supplied,
113
117
  comes_from=template.comes_from,
114
- use_pep517=template.use_pep517,
115
118
  isolated=template.isolated,
116
119
  constraint=template.constraint,
117
- global_options=template.global_options,
118
120
  hash_options=template.hash_options,
119
121
  config_settings=template.config_settings,
120
122
  )
@@ -146,9 +148,9 @@ class _InstallRequirementBackedCandidate(Candidate):
146
148
  link: Link,
147
149
  source_link: Link,
148
150
  ireq: InstallRequirement,
149
- factory: "Factory",
150
- name: Optional[NormalizedName] = None,
151
- version: Optional[Version] = None,
151
+ factory: Factory,
152
+ name: NormalizedName | None = None,
153
+ version: Version | None = None,
152
154
  ) -> None:
153
155
  self._link = link
154
156
  self._source_link = source_link
@@ -157,7 +159,7 @@ class _InstallRequirementBackedCandidate(Candidate):
157
159
  self._name = name
158
160
  self._version = version
159
161
  self.dist = self._prepare()
160
- self._hash: Optional[int] = None
162
+ self._hash: int | None = None
161
163
 
162
164
  def __str__(self) -> str:
163
165
  return f"{self.name} {self.version}"
@@ -178,7 +180,7 @@ class _InstallRequirementBackedCandidate(Candidate):
178
180
  return False
179
181
 
180
182
  @property
181
- def source_link(self) -> Optional[Link]:
183
+ def source_link(self) -> Link | None:
182
184
  return self._source_link
183
185
 
184
186
  @property
@@ -241,14 +243,24 @@ class _InstallRequirementBackedCandidate(Candidate):
241
243
  e.req = self._ireq
242
244
  raise
243
245
  except InstallationSubprocessError as exc:
244
- # The output has been presented already, so don't duplicate it.
245
- exc.context = "See above for output."
246
- raise
246
+ if isinstance(self._ireq.comes_from, InstallRequirement):
247
+ request_chain = self._ireq.comes_from.from_path()
248
+ else:
249
+ request_chain = self._ireq.comes_from
250
+
251
+ if request_chain is None:
252
+ request_chain = "directly requested"
253
+
254
+ raise FailedToPrepareCandidate(
255
+ package_name=self._ireq.name or str(self._link),
256
+ requirement_chain=request_chain,
257
+ failed_step=exc.command_description,
258
+ )
247
259
 
248
260
  self._check_metadata_consistency(dist)
249
261
  return dist
250
262
 
251
- def iter_dependencies(self, with_requires: bool) -> Iterable[Optional[Requirement]]:
263
+ def iter_dependencies(self, with_requires: bool) -> Iterable[Requirement | None]:
252
264
  # Emit the Requires-Python requirement first to fail fast on
253
265
  # unsupported candidates and avoid pointless downloads/preparation.
254
266
  yield self._factory.make_requires_python_requirement(self.dist.requires_python)
@@ -256,7 +268,7 @@ class _InstallRequirementBackedCandidate(Candidate):
256
268
  for r in requires:
257
269
  yield from self._factory.make_requirements_from_spec(str(r), self._ireq)
258
270
 
259
- def get_install_requirement(self) -> Optional[InstallRequirement]:
271
+ def get_install_requirement(self) -> InstallRequirement | None:
260
272
  return self._ireq
261
273
 
262
274
 
@@ -267,9 +279,9 @@ class LinkCandidate(_InstallRequirementBackedCandidate):
267
279
  self,
268
280
  link: Link,
269
281
  template: InstallRequirement,
270
- factory: "Factory",
271
- name: Optional[NormalizedName] = None,
272
- version: Optional[Version] = None,
282
+ factory: Factory,
283
+ name: NormalizedName | None = None,
284
+ version: Version | None = None,
273
285
  ) -> None:
274
286
  source_link = link
275
287
  cache_entry = factory.get_wheel_cache_entry(source_link, name)
@@ -280,7 +292,7 @@ class LinkCandidate(_InstallRequirementBackedCandidate):
280
292
  assert ireq.link == link
281
293
  if ireq.link.is_wheel and not ireq.link.is_file:
282
294
  wheel = Wheel(ireq.link.filename)
283
- wheel_name = canonicalize_name(wheel.name)
295
+ wheel_name = wheel.name
284
296
  assert name == wheel_name, f"{name!r} != {wheel_name!r} for wheel"
285
297
  # Version may not be present for PEP 508 direct URLs
286
298
  if version is not None:
@@ -324,9 +336,9 @@ class EditableCandidate(_InstallRequirementBackedCandidate):
324
336
  self,
325
337
  link: Link,
326
338
  template: InstallRequirement,
327
- factory: "Factory",
328
- name: Optional[NormalizedName] = None,
329
- version: Optional[Version] = None,
339
+ factory: Factory,
340
+ name: NormalizedName | None = None,
341
+ version: Version | None = None,
330
342
  ) -> None:
331
343
  super().__init__(
332
344
  link=link,
@@ -349,7 +361,7 @@ class AlreadyInstalledCandidate(Candidate):
349
361
  self,
350
362
  dist: BaseDistribution,
351
363
  template: InstallRequirement,
352
- factory: "Factory",
364
+ factory: Factory,
353
365
  ) -> None:
354
366
  self.dist = dist
355
367
  self._ireq = _make_install_req_from_dist(dist, template)
@@ -398,7 +410,7 @@ class AlreadyInstalledCandidate(Candidate):
398
410
  def format_for_error(self) -> str:
399
411
  return f"{self.name} {self.version} (Installed)"
400
412
 
401
- def iter_dependencies(self, with_requires: bool) -> Iterable[Optional[Requirement]]:
413
+ def iter_dependencies(self, with_requires: bool) -> Iterable[Requirement | None]:
402
414
  if not with_requires:
403
415
  return
404
416
 
@@ -408,7 +420,7 @@ class AlreadyInstalledCandidate(Candidate):
408
420
  except InvalidRequirement as exc:
409
421
  raise InvalidInstalledPackage(dist=self.dist, invalid_exc=exc) from None
410
422
 
411
- def get_install_requirement(self) -> Optional[InstallRequirement]:
423
+ def get_install_requirement(self) -> InstallRequirement | None:
412
424
  return None
413
425
 
414
426
 
@@ -440,9 +452,9 @@ class ExtrasCandidate(Candidate):
440
452
  def __init__(
441
453
  self,
442
454
  base: BaseCandidate,
443
- extras: FrozenSet[str],
455
+ extras: frozenset[str],
444
456
  *,
445
- comes_from: Optional[InstallRequirement] = None,
457
+ comes_from: InstallRequirement | None = None,
446
458
  ) -> None:
447
459
  """
448
460
  :param comes_from: the InstallRequirement that led to this candidate if it
@@ -498,10 +510,10 @@ class ExtrasCandidate(Candidate):
498
510
  return self.base.is_editable
499
511
 
500
512
  @property
501
- def source_link(self) -> Optional[Link]:
513
+ def source_link(self) -> Link | None:
502
514
  return self.base.source_link
503
515
 
504
- def iter_dependencies(self, with_requires: bool) -> Iterable[Optional[Requirement]]:
516
+ def iter_dependencies(self, with_requires: bool) -> Iterable[Requirement | None]:
505
517
  factory = self.base._factory
506
518
 
507
519
  # Add a dependency on the exact base
@@ -529,7 +541,7 @@ class ExtrasCandidate(Candidate):
529
541
  valid_extras,
530
542
  )
531
543
 
532
- def get_install_requirement(self) -> Optional[InstallRequirement]:
544
+ def get_install_requirement(self) -> InstallRequirement | None:
533
545
  # We don't return anything here, because we always
534
546
  # depend on the base candidate, and we'll get the
535
547
  # install requirement from that.
@@ -540,7 +552,7 @@ class RequiresPythonCandidate(Candidate):
540
552
  is_installed = False
541
553
  source_link = None
542
554
 
543
- def __init__(self, py_version_info: Optional[Tuple[int, ...]]) -> None:
555
+ def __init__(self, py_version_info: tuple[int, ...] | None) -> None:
544
556
  if py_version_info is not None:
545
557
  version_info = normalize_version_info(py_version_info)
546
558
  else:
@@ -572,8 +584,8 @@ class RequiresPythonCandidate(Candidate):
572
584
  def format_for_error(self) -> str:
573
585
  return f"Python {self.version}"
574
586
 
575
- def iter_dependencies(self, with_requires: bool) -> Iterable[Optional[Requirement]]:
587
+ def iter_dependencies(self, with_requires: bool) -> Iterable[Requirement | None]:
576
588
  return ()
577
589
 
578
- def get_install_requirement(self) -> Optional[InstallRequirement]:
590
+ def get_install_requirement(self) -> InstallRequirement | None:
579
591
  return None