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,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  import functools
2
4
  import logging
3
5
  import os
@@ -5,9 +7,10 @@ import shutil
5
7
  import sys
6
8
  import uuid
7
9
  import zipfile
10
+ from collections.abc import Collection, Iterable
8
11
  from optparse import Values
9
12
  from pathlib import Path
10
- from typing import Any, Collection, Dict, Iterable, List, Optional, Sequence, Union
13
+ from typing import Any
11
14
 
12
15
  from pip._vendor.packaging.markers import Marker
13
16
  from pip._vendor.packaging.requirements import Requirement
@@ -31,12 +34,6 @@ from pip._internal.models.direct_url import DirectUrl
31
34
  from pip._internal.models.link import Link
32
35
  from pip._internal.operations.build.metadata import generate_metadata
33
36
  from pip._internal.operations.build.metadata_editable import generate_editable_metadata
34
- from pip._internal.operations.build.metadata_legacy import (
35
- generate_metadata as generate_metadata_legacy,
36
- )
37
- from pip._internal.operations.install.editable_legacy import (
38
- install_editable as install_editable_legacy,
39
- )
40
37
  from pip._internal.operations.install.wheel import install_wheel
41
38
  from pip._internal.pyproject import load_pyproject_toml, make_pyproject_path
42
39
  from pip._internal.req.req_uninstall import UninstallPathSet
@@ -71,17 +68,15 @@ class InstallRequirement:
71
68
 
72
69
  def __init__(
73
70
  self,
74
- req: Optional[Requirement],
75
- comes_from: Optional[Union[str, "InstallRequirement"]],
71
+ req: Requirement | None,
72
+ comes_from: str | InstallRequirement | None,
76
73
  editable: bool = False,
77
- link: Optional[Link] = None,
78
- markers: Optional[Marker] = None,
79
- use_pep517: Optional[bool] = None,
74
+ link: Link | None = None,
75
+ markers: Marker | None = None,
80
76
  isolated: bool = False,
81
77
  *,
82
- global_options: Optional[List[str]] = None,
83
- hash_options: Optional[Dict[str, List[str]]] = None,
84
- config_settings: Optional[Dict[str, Union[str, List[str]]]] = None,
78
+ hash_options: dict[str, list[str]] | None = None,
79
+ config_settings: dict[str, str | list[str]] | None = None,
85
80
  constraint: bool = False,
86
81
  extras: Collection[str] = (),
87
82
  user_supplied: bool = False,
@@ -99,7 +94,7 @@ class InstallRequirement:
99
94
  # populating source_dir is done by the RequirementPreparer. Note this
100
95
  # is not necessarily the directory where pyproject.toml or setup.py is
101
96
  # located - that one is obtained via unpacked_source_directory.
102
- self.source_dir: Optional[str] = None
97
+ self.source_dir: str | None = None
103
98
  if self.editable:
104
99
  assert link
105
100
  if link.is_file:
@@ -115,14 +110,14 @@ class InstallRequirement:
115
110
  # When this InstallRequirement is a wheel obtained from the cache of locally
116
111
  # built wheels, this is the source link corresponding to the cache entry, which
117
112
  # was used to download and build the cached wheel.
118
- self.cached_wheel_source_link: Optional[Link] = None
113
+ self.cached_wheel_source_link: Link | None = None
119
114
 
120
115
  # Information about the location of the artifact that was downloaded . This
121
116
  # property is guaranteed to be set in resolver results.
122
- self.download_info: Optional[DirectUrl] = None
117
+ self.download_info: DirectUrl | None = None
123
118
 
124
119
  # Path to any downloaded or already-existing package.
125
- self.local_file_path: Optional[str] = None
120
+ self.local_file_path: str | None = None
126
121
  if self.link and self.link.is_file:
127
122
  self.local_file_path = self.link.file_path
128
123
 
@@ -137,16 +132,15 @@ class InstallRequirement:
137
132
  self.markers = markers
138
133
 
139
134
  # This holds the Distribution object if this requirement is already installed.
140
- self.satisfied_by: Optional[BaseDistribution] = None
135
+ self.satisfied_by: BaseDistribution | None = None
141
136
  # Whether the installation process should try to uninstall an existing
142
137
  # distribution before installing this requirement.
143
138
  self.should_reinstall = False
144
139
  # Temporary build location
145
- self._temp_build_dir: Optional[TempDirectory] = None
140
+ self._temp_build_dir: TempDirectory | None = None
146
141
  # Set to True after successful installation
147
- self.install_succeeded: Optional[bool] = None
142
+ self.install_succeeded: bool | None = None
148
143
  # Supplied options
149
- self.global_options = global_options if global_options else []
150
144
  self.hash_options = hash_options if hash_options else {}
151
145
  self.config_settings = config_settings
152
146
  # Set to True after successful preparation of this requirement
@@ -163,39 +157,26 @@ class InstallRequirement:
163
157
  # gets stored. We need this to pass to build_wheel, so the backend
164
158
  # can ensure that the wheel matches the metadata (see the PEP for
165
159
  # details).
166
- self.metadata_directory: Optional[str] = None
160
+ self.metadata_directory: str | None = None
161
+
162
+ # The cached metadata distribution that this requirement represents.
163
+ # See get_dist / set_dist.
164
+ self._distribution: BaseDistribution | None = None
167
165
 
168
166
  # The static build requirements (from pyproject.toml)
169
- self.pyproject_requires: Optional[List[str]] = None
167
+ self.pyproject_requires: list[str] | None = None
170
168
 
171
169
  # Build requirements that we will check are available
172
- self.requirements_to_check: List[str] = []
170
+ self.requirements_to_check: list[str] = []
173
171
 
174
172
  # The PEP 517 backend we should use to build the project
175
- self.pep517_backend: Optional[BuildBackendHookCaller] = None
176
-
177
- # Are we using PEP 517 for this requirement?
178
- # After pyproject.toml has been loaded, the only valid values are True
179
- # and False. Before loading, None is valid (meaning "use the default").
180
- # Setting an explicit value before loading pyproject.toml is supported,
181
- # but after loading this flag should be treated as read only.
182
- self.use_pep517 = use_pep517
183
-
184
- # If config settings are provided, enforce PEP 517.
185
- if self.config_settings:
186
- if self.use_pep517 is False:
187
- logger.warning(
188
- "--no-use-pep517 ignored for %s "
189
- "because --config-settings are specified.",
190
- self,
191
- )
192
- self.use_pep517 = True
173
+ self.pep517_backend: BuildBackendHookCaller | None = None
193
174
 
194
175
  # This requirement needs more preparation before it can be built
195
176
  self.needs_more_preparation = False
196
177
 
197
178
  # This requirement needs to be unpacked before it can be installed.
198
- self._archive_source: Optional[Path] = None
179
+ self._archive_source: Path | None = None
199
180
 
200
181
  def __str__(self) -> str:
201
182
  if self.req:
@@ -214,7 +195,7 @@ class InstallRequirement:
214
195
  s += f" in {location}"
215
196
  if self.comes_from:
216
197
  if isinstance(self.comes_from, str):
217
- comes_from: Optional[str] = self.comes_from
198
+ comes_from: str | None = self.comes_from
218
199
  else:
219
200
  comes_from = self.comes_from.from_path()
220
201
  if comes_from:
@@ -240,15 +221,13 @@ class InstallRequirement:
240
221
 
241
222
  # Things that are valid for all kinds of requirements?
242
223
  @property
243
- def name(self) -> Optional[str]:
224
+ def name(self) -> str | None:
244
225
  if self.req is None:
245
226
  return None
246
227
  return self.req.name
247
228
 
248
229
  @functools.cached_property
249
230
  def supports_pyproject_editable(self) -> bool:
250
- if not self.use_pep517:
251
- return False
252
231
  assert self.pep517_backend
253
232
  with self.build_env:
254
233
  runner = runner_with_spinner_message(
@@ -277,7 +256,7 @@ class InstallRequirement:
277
256
  specifiers = self.req.specifier
278
257
  return len(specifiers) == 1 and next(iter(specifiers)).operator in {"==", "==="}
279
258
 
280
- def match_markers(self, extras_requested: Optional[Iterable[str]] = None) -> bool:
259
+ def match_markers(self, extras_requested: Iterable[str] | None = None) -> bool:
281
260
  if not extras_requested:
282
261
  # Provide an extra to safely evaluate the markers
283
262
  # without matching any extra
@@ -326,13 +305,13 @@ class InstallRequirement:
326
305
  good_hashes.setdefault(link.hash_name, []).append(link.hash)
327
306
  return Hashes(good_hashes)
328
307
 
329
- def from_path(self) -> Optional[str]:
308
+ def from_path(self) -> str | None:
330
309
  """Format a nice indicator to show where this "comes from" """
331
310
  if self.req is None:
332
311
  return None
333
312
  s = str(self.req)
334
313
  if self.comes_from:
335
- comes_from: Optional[str]
314
+ comes_from: str | None
336
315
  if isinstance(self.comes_from, str):
337
316
  comes_from = self.comes_from
338
317
  else:
@@ -489,13 +468,6 @@ class InstallRequirement:
489
468
 
490
469
  return setup_py
491
470
 
492
- @property
493
- def setup_cfg_path(self) -> str:
494
- assert self.source_dir, f"No source dir for {self}"
495
- setup_cfg = os.path.join(self.unpacked_source_directory, "setup.cfg")
496
-
497
- return setup_cfg
498
-
499
471
  @property
500
472
  def pyproject_toml_path(self) -> str:
501
473
  assert self.source_dir, f"No source dir for {self}"
@@ -505,20 +477,12 @@ class InstallRequirement:
505
477
  """Load the pyproject.toml file.
506
478
 
507
479
  After calling this routine, all of the attributes related to PEP 517
508
- processing for this requirement have been set. In particular, the
509
- use_pep517 attribute can be used to determine whether we should
510
- follow the PEP 517 or legacy (setup.py) code path.
480
+ processing for this requirement have been set.
511
481
  """
512
482
  pyproject_toml_data = load_pyproject_toml(
513
- self.use_pep517, self.pyproject_toml_path, self.setup_py_path, str(self)
483
+ self.pyproject_toml_path, self.setup_py_path, str(self)
514
484
  )
515
-
516
- if pyproject_toml_data is None:
517
- assert not self.config_settings
518
- self.use_pep517 = False
519
- return
520
-
521
- self.use_pep517 = True
485
+ assert pyproject_toml_data
522
486
  requires, backend, check, backend_path = pyproject_toml_data
523
487
  self.requirements_to_check = check
524
488
  self.pyproject_requires = requires
@@ -529,23 +493,15 @@ class InstallRequirement:
529
493
  backend_path=backend_path,
530
494
  )
531
495
 
532
- def isolated_editable_sanity_check(self) -> None:
496
+ def editable_sanity_check(self) -> None:
533
497
  """Check that an editable requirement if valid for use with PEP 517/518.
534
498
 
535
- This verifies that an editable that has a pyproject.toml either supports PEP 660
536
- or as a setup.py or a setup.cfg
499
+ This verifies that an editable has a build backend that supports PEP 660.
537
500
  """
538
- if (
539
- self.editable
540
- and self.use_pep517
541
- and not self.supports_pyproject_editable
542
- and not os.path.isfile(self.setup_py_path)
543
- and not os.path.isfile(self.setup_cfg_path)
544
- ):
501
+ if self.editable and not self.supports_pyproject_editable:
545
502
  raise InstallationError(
546
- f"Project {self} has a 'pyproject.toml' and its build "
547
- f"backend is missing the 'build_editable' hook. Since it does not "
548
- f"have a 'setup.py' nor a 'setup.cfg', "
503
+ f"Project {self} uses a build backend "
504
+ f"that is missing the 'build_editable' hook, so "
549
505
  f"it cannot be installed in editable mode. "
550
506
  f"Consider using a build backend that supports PEP 660."
551
507
  )
@@ -559,30 +515,21 @@ class InstallRequirement:
559
515
  assert self.source_dir, f"No source dir for {self}"
560
516
  details = self.name or f"from {self.link}"
561
517
 
562
- if self.use_pep517:
563
- assert self.pep517_backend is not None
564
- if (
565
- self.editable
566
- and self.permit_editable_wheels
567
- and self.supports_pyproject_editable
568
- ):
569
- self.metadata_directory = generate_editable_metadata(
570
- build_env=self.build_env,
571
- backend=self.pep517_backend,
572
- details=details,
573
- )
574
- else:
575
- self.metadata_directory = generate_metadata(
576
- build_env=self.build_env,
577
- backend=self.pep517_backend,
578
- details=details,
579
- )
518
+ assert self.pep517_backend is not None
519
+ if (
520
+ self.editable
521
+ and self.permit_editable_wheels
522
+ and self.supports_pyproject_editable
523
+ ):
524
+ self.metadata_directory = generate_editable_metadata(
525
+ build_env=self.build_env,
526
+ backend=self.pep517_backend,
527
+ details=details,
528
+ )
580
529
  else:
581
- self.metadata_directory = generate_metadata_legacy(
530
+ self.metadata_directory = generate_metadata(
582
531
  build_env=self.build_env,
583
- setup_py_path=self.setup_py_path,
584
- source_dir=self.unpacked_source_directory,
585
- isolated=self.isolated,
532
+ backend=self.pep517_backend,
586
533
  details=details,
587
534
  )
588
535
 
@@ -601,8 +548,13 @@ class InstallRequirement:
601
548
 
602
549
  return self._metadata
603
550
 
551
+ def set_dist(self, distribution: BaseDistribution) -> None:
552
+ self._distribution = distribution
553
+
604
554
  def get_dist(self) -> BaseDistribution:
605
- if self.metadata_directory:
555
+ if self._distribution is not None:
556
+ return self._distribution
557
+ elif self.metadata_directory:
606
558
  return get_directory_distribution(self.metadata_directory)
607
559
  elif self.local_file_path and self.is_wheel:
608
560
  assert self.req is not None
@@ -699,7 +651,7 @@ class InstallRequirement:
699
651
  # Top-level Actions
700
652
  def uninstall(
701
653
  self, auto_confirm: bool = False, verbose: bool = False
702
- ) -> Optional[UninstallPathSet]:
654
+ ) -> UninstallPathSet | None:
703
655
  """
704
656
  Uninstall the distribution currently satisfying this requirement.
705
657
 
@@ -737,7 +689,7 @@ class InstallRequirement:
737
689
  name = _clean_zip_name(path, rootdir)
738
690
  return self.req.name + "/" + name
739
691
 
740
- def archive(self, build_dir: Optional[str]) -> None:
692
+ def archive(self, build_dir: str | None) -> None:
741
693
  """Saves archive to provided build_dir.
742
694
 
743
695
  Used for saving downloaded VCS requirements as part of `pip download`.
@@ -806,10 +758,9 @@ class InstallRequirement:
806
758
 
807
759
  def install(
808
760
  self,
809
- global_options: Optional[Sequence[str]] = None,
810
- root: Optional[str] = None,
811
- home: Optional[str] = None,
812
- prefix: Optional[str] = None,
761
+ root: str | None = None,
762
+ home: str | None = None,
763
+ prefix: str | None = None,
813
764
  warn_script_location: bool = True,
814
765
  use_user_site: bool = False,
815
766
  pycompile: bool = True,
@@ -824,43 +775,6 @@ class InstallRequirement:
824
775
  prefix=prefix,
825
776
  )
826
777
 
827
- if self.editable and not self.is_wheel:
828
- deprecated(
829
- reason=(
830
- f"Legacy editable install of {self} (setup.py develop) "
831
- "is deprecated."
832
- ),
833
- replacement=(
834
- "to add a pyproject.toml or enable --use-pep517, "
835
- "and use setuptools >= 64. "
836
- "If the resulting installation is not behaving as expected, "
837
- "try using --config-settings editable_mode=compat. "
838
- "Please consult the setuptools documentation for more information"
839
- ),
840
- gone_in="25.3",
841
- issue=11457,
842
- )
843
- if self.config_settings:
844
- logger.warning(
845
- "--config-settings ignored for legacy editable install of %s. "
846
- "Consider upgrading to a version of setuptools "
847
- "that supports PEP 660 (>= 64).",
848
- self,
849
- )
850
- install_editable_legacy(
851
- global_options=global_options if global_options is not None else [],
852
- prefix=prefix,
853
- home=home,
854
- use_user_site=use_user_site,
855
- name=self.req.name,
856
- setup_py_path=self.setup_py_path,
857
- isolated=self.isolated,
858
- build_env=self.build_env,
859
- unpacked_source_directory=self.unpacked_source_directory,
860
- )
861
- self.install_succeeded = True
862
- return
863
-
864
778
  assert self.is_wheel
865
779
  assert self.local_file_path
866
780
 
@@ -905,30 +819,10 @@ def check_invalid_constraint_type(req: InstallRequirement) -> str:
905
819
  return problem
906
820
 
907
821
 
908
- def _has_option(options: Values, reqs: List[InstallRequirement], option: str) -> bool:
822
+ def _has_option(options: Values, reqs: list[InstallRequirement], option: str) -> bool:
909
823
  if getattr(options, option, None):
910
824
  return True
911
825
  for req in reqs:
912
826
  if getattr(req, option, None):
913
827
  return True
914
828
  return False
915
-
916
-
917
- def check_legacy_setup_py_options(
918
- options: Values,
919
- reqs: List[InstallRequirement],
920
- ) -> None:
921
- has_build_options = _has_option(options, reqs, "build_options")
922
- has_global_options = _has_option(options, reqs, "global_options")
923
- if has_build_options or has_global_options:
924
- deprecated(
925
- reason="--build-option and --global-option are deprecated.",
926
- issue=11859,
927
- replacement="to use --config-settings",
928
- gone_in="25.3",
929
- )
930
- logger.warning(
931
- "Implying --no-binary=:all: due to the presence of "
932
- "--build-option / --global-option. "
933
- )
934
- options.format_control.disallow_binaries()
@@ -1,6 +1,5 @@
1
1
  import logging
2
2
  from collections import OrderedDict
3
- from typing import Dict, List
4
3
 
5
4
  from pip._vendor.packaging.utils import canonicalize_name
6
5
 
@@ -13,10 +12,10 @@ class RequirementSet:
13
12
  def __init__(self, check_supported_wheels: bool = True) -> None:
14
13
  """Create a RequirementSet."""
15
14
 
16
- self.requirements: Dict[str, InstallRequirement] = OrderedDict()
15
+ self.requirements: dict[str, InstallRequirement] = OrderedDict()
17
16
  self.check_supported_wheels = check_supported_wheels
18
17
 
19
- self.unnamed_requirements: List[InstallRequirement] = []
18
+ self.unnamed_requirements: list[InstallRequirement] = []
20
19
 
21
20
  def __str__(self) -> str:
22
21
  requirements = sorted(
@@ -65,11 +64,11 @@ class RequirementSet:
65
64
  raise KeyError(f"No project with the name {name!r}")
66
65
 
67
66
  @property
68
- def all_requirements(self) -> List[InstallRequirement]:
67
+ def all_requirements(self) -> list[InstallRequirement]:
69
68
  return self.unnamed_requirements + list(self.requirements.values())
70
69
 
71
70
  @property
72
- def requirements_to_install(self) -> List[InstallRequirement]:
71
+ def requirements_to_install(self) -> list[InstallRequirement]:
73
72
  """Return the list of requirements that need to be installed.
74
73
 
75
74
  TODO remove this property together with the legacy resolver, since the new
@@ -1,9 +1,12 @@
1
+ from __future__ import annotations
2
+
1
3
  import functools
2
4
  import os
3
5
  import sys
4
6
  import sysconfig
7
+ from collections.abc import Generator, Iterable
5
8
  from importlib.util import cache_from_source
6
- from typing import Any, Callable, Dict, Generator, Iterable, List, Optional, Set, Tuple
9
+ from typing import Any, Callable
7
10
 
8
11
  from pip._internal.exceptions import LegacyDistutilsInstall, UninstallMissingRecord
9
12
  from pip._internal.locations import get_bin_prefix, get_bin_user
@@ -42,7 +45,7 @@ def _unique(
42
45
  ) -> Callable[..., Generator[Any, None, None]]:
43
46
  @functools.wraps(fn)
44
47
  def unique(*args: Any, **kw: Any) -> Generator[Any, None, None]:
45
- seen: Set[Any] = set()
48
+ seen: set[Any] = set()
46
49
  for item in fn(*args, **kw):
47
50
  if item not in seen:
48
51
  seen.add(item)
@@ -85,14 +88,14 @@ def uninstallation_paths(dist: BaseDistribution) -> Generator[str, None, None]:
85
88
  yield path
86
89
 
87
90
 
88
- def compact(paths: Iterable[str]) -> Set[str]:
91
+ def compact(paths: Iterable[str]) -> set[str]:
89
92
  """Compact a path set to contain the minimal number of paths
90
93
  necessary to contain all paths in the set. If /a/path/ and
91
94
  /a/path/to/a/file.txt are both in the set, leave only the
92
95
  shorter path."""
93
96
 
94
97
  sep = os.path.sep
95
- short_paths: Set[str] = set()
98
+ short_paths: set[str] = set()
96
99
  for path in sorted(paths, key=len):
97
100
  should_skip = any(
98
101
  path.startswith(shortpath.rstrip("*"))
@@ -104,7 +107,7 @@ def compact(paths: Iterable[str]) -> Set[str]:
104
107
  return short_paths
105
108
 
106
109
 
107
- def compress_for_rename(paths: Iterable[str]) -> Set[str]:
110
+ def compress_for_rename(paths: Iterable[str]) -> set[str]:
108
111
  """Returns a set containing the paths that need to be renamed.
109
112
 
110
113
  This set may include directories when the original sequence of paths
@@ -113,7 +116,7 @@ def compress_for_rename(paths: Iterable[str]) -> Set[str]:
113
116
  case_map = {os.path.normcase(p): p for p in paths}
114
117
  remaining = set(case_map)
115
118
  unchecked = sorted({os.path.split(p)[0] for p in case_map.values()}, key=len)
116
- wildcards: Set[str] = set()
119
+ wildcards: set[str] = set()
117
120
 
118
121
  def norm_join(*a: str) -> str:
119
122
  return os.path.normcase(os.path.join(*a))
@@ -123,8 +126,8 @@ def compress_for_rename(paths: Iterable[str]) -> Set[str]:
123
126
  # This directory has already been handled.
124
127
  continue
125
128
 
126
- all_files: Set[str] = set()
127
- all_subdirs: Set[str] = set()
129
+ all_files: set[str] = set()
130
+ all_subdirs: set[str] = set()
128
131
  for dirname, subdirs, files in os.walk(root):
129
132
  all_subdirs.update(norm_join(root, dirname, d) for d in subdirs)
130
133
  all_files.update(norm_join(root, dirname, f) for f in files)
@@ -138,7 +141,7 @@ def compress_for_rename(paths: Iterable[str]) -> Set[str]:
138
141
  return set(map(case_map.__getitem__, remaining)) | wildcards
139
142
 
140
143
 
141
- def compress_for_output_listing(paths: Iterable[str]) -> Tuple[Set[str], Set[str]]:
144
+ def compress_for_output_listing(paths: Iterable[str]) -> tuple[set[str], set[str]]:
142
145
  """Returns a tuple of 2 sets of which paths to display to user
143
146
 
144
147
  The first set contains paths that would be deleted. Files of a package
@@ -194,10 +197,10 @@ class StashedUninstallPathSet:
194
197
  def __init__(self) -> None:
195
198
  # Mapping from source file root to [Adjacent]TempDirectory
196
199
  # for files under that directory.
197
- self._save_dirs: Dict[str, TempDirectory] = {}
200
+ self._save_dirs: dict[str, TempDirectory] = {}
198
201
  # (old path, new path) tuples for each move that may need
199
202
  # to be undone.
200
- self._moves: List[Tuple[str, str]] = []
203
+ self._moves: list[tuple[str, str]] = []
201
204
 
202
205
  def _get_directory_stash(self, path: str) -> str:
203
206
  """Stashes a directory.
@@ -297,9 +300,9 @@ class UninstallPathSet:
297
300
  requirement."""
298
301
 
299
302
  def __init__(self, dist: BaseDistribution) -> None:
300
- self._paths: Set[str] = set()
301
- self._refuse: Set[str] = set()
302
- self._pth: Dict[str, UninstallPthEntries] = {}
303
+ self._paths: set[str] = set()
304
+ self._refuse: set[str] = set()
305
+ self._pth: dict[str, UninstallPthEntries] = {}
303
306
  self._dist = dist
304
307
  self._moved_paths = StashedUninstallPathSet()
305
308
  # Create local cache of normalize_path results. Creating an UninstallPathSet
@@ -421,7 +424,7 @@ class UninstallPathSet:
421
424
  self._moved_paths.commit()
422
425
 
423
426
  @classmethod
424
- def from_dist(cls, dist: BaseDistribution) -> "UninstallPathSet":
427
+ def from_dist(cls, dist: BaseDistribution) -> UninstallPathSet:
425
428
  dist_location = dist.location
426
429
  info_location = dist.info_location
427
430
  if dist_location is None:
@@ -581,8 +584,8 @@ class UninstallPathSet:
581
584
  class UninstallPthEntries:
582
585
  def __init__(self, pth_file: str) -> None:
583
586
  self.file = pth_file
584
- self.entries: Set[str] = set()
585
- self._saved_lines: Optional[List[bytes]] = None
587
+ self.entries: set[str] = set()
588
+ self._saved_lines: list[bytes] | None = None
586
589
 
587
590
  def add(self, entry: str) -> None:
588
591
  entry = os.path.normcase(entry)
@@ -1,4 +1,4 @@
1
- from typing import Callable, List, Optional
1
+ from typing import Callable, Optional
2
2
 
3
3
  from pip._internal.req.req_install import InstallRequirement
4
4
  from pip._internal.req.req_set import RequirementSet
@@ -10,11 +10,11 @@ InstallRequirementProvider = Callable[
10
10
 
11
11
  class BaseResolver:
12
12
  def resolve(
13
- self, root_reqs: List[InstallRequirement], check_supported_wheels: bool
13
+ self, root_reqs: list[InstallRequirement], check_supported_wheels: bool
14
14
  ) -> RequirementSet:
15
15
  raise NotImplementedError()
16
16
 
17
17
  def get_installation_order(
18
18
  self, req_set: RequirementSet
19
- ) -> List[InstallRequirement]:
19
+ ) -> list[InstallRequirement]:
20
20
  raise NotImplementedError()