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,14 @@
1
+ from __future__ import annotations
2
+
1
3
  import json
2
4
  import logging
5
+ from collections.abc import Generator, Sequence
3
6
  from email.parser import Parser
4
7
  from optparse import Values
5
- from typing import TYPE_CHECKING, Generator, List, Optional, Sequence, Tuple, cast
8
+ from typing import TYPE_CHECKING, cast
6
9
 
7
10
  from pip._vendor.packaging.utils import canonicalize_name
8
- from pip._vendor.packaging.version import Version
11
+ from pip._vendor.packaging.version import InvalidVersion, Version
9
12
 
10
13
  from pip._internal.cli import cmdoptions
11
14
  from pip._internal.cli.index_command import IndexGroupCommand
@@ -140,8 +143,8 @@ class ListCommand(IndexGroupCommand):
140
143
  super().handle_pip_version_check(options)
141
144
 
142
145
  def _build_package_finder(
143
- self, options: Values, session: "PipSession"
144
- ) -> "PackageFinder":
146
+ self, options: Values, session: PipSession
147
+ ) -> PackageFinder:
145
148
  """
146
149
  Create a package finder appropriate to this list command.
147
150
  """
@@ -162,7 +165,7 @@ class ListCommand(IndexGroupCommand):
162
165
  selection_prefs=selection_prefs,
163
166
  )
164
167
 
165
- def run(self, options: Values, args: List[str]) -> int:
168
+ def run(self, options: Values, args: list[str]) -> int:
166
169
  if options.outdated and options.uptodate:
167
170
  raise CommandError("Options --outdated and --uptodate cannot be combined.")
168
171
 
@@ -204,8 +207,8 @@ class ListCommand(IndexGroupCommand):
204
207
  return SUCCESS
205
208
 
206
209
  def get_outdated(
207
- self, packages: "_ProcessedDists", options: Values
208
- ) -> "_ProcessedDists":
210
+ self, packages: _ProcessedDists, options: Values
211
+ ) -> _ProcessedDists:
209
212
  return [
210
213
  dist
211
214
  for dist in self.iter_packages_latest_infos(packages, options)
@@ -213,8 +216,8 @@ class ListCommand(IndexGroupCommand):
213
216
  ]
214
217
 
215
218
  def get_uptodate(
216
- self, packages: "_ProcessedDists", options: Values
217
- ) -> "_ProcessedDists":
219
+ self, packages: _ProcessedDists, options: Values
220
+ ) -> _ProcessedDists:
218
221
  return [
219
222
  dist
220
223
  for dist in self.iter_packages_latest_infos(packages, options)
@@ -222,8 +225,8 @@ class ListCommand(IndexGroupCommand):
222
225
  ]
223
226
 
224
227
  def get_not_required(
225
- self, packages: "_ProcessedDists", options: Values
226
- ) -> "_ProcessedDists":
228
+ self, packages: _ProcessedDists, options: Values
229
+ ) -> _ProcessedDists:
227
230
  dep_keys = {
228
231
  canonicalize_name(dep.name)
229
232
  for dist in packages
@@ -236,14 +239,14 @@ class ListCommand(IndexGroupCommand):
236
239
  return list({pkg for pkg in packages if pkg.canonical_name not in dep_keys})
237
240
 
238
241
  def iter_packages_latest_infos(
239
- self, packages: "_ProcessedDists", options: Values
240
- ) -> Generator["_DistWithLatestInfo", None, None]:
242
+ self, packages: _ProcessedDists, options: Values
243
+ ) -> Generator[_DistWithLatestInfo, None, None]:
241
244
  with self._build_session(options) as session:
242
245
  finder = self._build_package_finder(options, session)
243
246
 
244
247
  def latest_info(
245
- dist: "_DistWithLatestInfo",
246
- ) -> Optional["_DistWithLatestInfo"]:
248
+ dist: _DistWithLatestInfo,
249
+ ) -> _DistWithLatestInfo | None:
247
250
  all_candidates = finder.find_all_candidates(dist.canonical_name)
248
251
  if not options.pre:
249
252
  # Remove prereleases
@@ -274,7 +277,7 @@ class ListCommand(IndexGroupCommand):
274
277
  yield dist
275
278
 
276
279
  def output_package_listing(
277
- self, packages: "_ProcessedDists", options: Values
280
+ self, packages: _ProcessedDists, options: Values
278
281
  ) -> None:
279
282
  packages = sorted(
280
283
  packages,
@@ -285,17 +288,19 @@ class ListCommand(IndexGroupCommand):
285
288
  self.output_package_listing_columns(data, header)
286
289
  elif options.list_format == "freeze":
287
290
  for dist in packages:
291
+ try:
292
+ req_string = f"{dist.raw_name}=={dist.version}"
293
+ except InvalidVersion:
294
+ req_string = f"{dist.raw_name}==={dist.raw_version}"
288
295
  if options.verbose >= 1:
289
- write_output(
290
- "%s==%s (%s)", dist.raw_name, dist.version, dist.location
291
- )
296
+ write_output("%s (%s)", req_string, dist.location)
292
297
  else:
293
- write_output("%s==%s", dist.raw_name, dist.version)
298
+ write_output(req_string)
294
299
  elif options.list_format == "json":
295
300
  write_output(format_for_json(packages, options))
296
301
 
297
302
  def output_package_listing_columns(
298
- self, data: List[List[str]], header: List[str]
303
+ self, data: list[list[str]], header: list[str]
299
304
  ) -> None:
300
305
  # insert the header first: we need to know the size of column names
301
306
  if len(data) > 0:
@@ -312,8 +317,8 @@ class ListCommand(IndexGroupCommand):
312
317
 
313
318
 
314
319
  def format_for_columns(
315
- pkgs: "_ProcessedDists", options: Values
316
- ) -> Tuple[List[List[str]], List[str]]:
320
+ pkgs: _ProcessedDists, options: Values
321
+ ) -> tuple[list[list[str]], list[str]]:
317
322
  """
318
323
  Convert the package data into something usable
319
324
  by output_package_listing_columns.
@@ -324,7 +329,7 @@ def format_for_columns(
324
329
  if running_outdated:
325
330
  header.extend(["Latest", "Type"])
326
331
 
327
- def wheel_build_tag(dist: BaseDistribution) -> Optional[str]:
332
+ def wheel_build_tag(dist: BaseDistribution) -> str | None:
328
333
  try:
329
334
  wheel_file = dist.read_text("WHEEL")
330
335
  except FileNotFoundError:
@@ -371,12 +376,16 @@ def format_for_columns(
371
376
  return data, header
372
377
 
373
378
 
374
- def format_for_json(packages: "_ProcessedDists", options: Values) -> str:
379
+ def format_for_json(packages: _ProcessedDists, options: Values) -> str:
375
380
  data = []
376
381
  for dist in packages:
382
+ try:
383
+ version = str(dist.version)
384
+ except InvalidVersion:
385
+ version = dist.raw_version
377
386
  info = {
378
387
  "name": dist.raw_name,
379
- "version": str(dist.version),
388
+ "version": version,
380
389
  }
381
390
  if options.verbose >= 1:
382
391
  info["location"] = dist.location or ""
@@ -1,7 +1,6 @@
1
1
  import sys
2
2
  from optparse import Values
3
3
  from pathlib import Path
4
- from typing import List
5
4
 
6
5
  from pip._internal.cache import WheelCache
7
6
  from pip._internal.cli import cmdoptions
@@ -12,9 +11,6 @@ from pip._internal.cli.req_command import (
12
11
  from pip._internal.cli.status_codes import SUCCESS
13
12
  from pip._internal.models.pylock import Pylock, is_valid_pylock_file_name
14
13
  from pip._internal.operations.build.build_tracker import get_build_tracker
15
- from pip._internal.req.req_install import (
16
- check_legacy_setup_py_options,
17
- )
18
14
  from pip._internal.utils.logging import getLogger
19
15
  from pip._internal.utils.misc import (
20
16
  get_pip_version,
@@ -60,6 +56,7 @@ class LockCommand(RequirementCommand):
60
56
  )
61
57
  self.cmd_opts.add_option(cmdoptions.requirements())
62
58
  self.cmd_opts.add_option(cmdoptions.constraints())
59
+ self.cmd_opts.add_option(cmdoptions.build_constraints())
63
60
  self.cmd_opts.add_option(cmdoptions.no_deps())
64
61
  self.cmd_opts.add_option(cmdoptions.pre())
65
62
 
@@ -70,7 +67,6 @@ class LockCommand(RequirementCommand):
70
67
  self.cmd_opts.add_option(cmdoptions.ignore_requires_python())
71
68
  self.cmd_opts.add_option(cmdoptions.no_build_isolation())
72
69
  self.cmd_opts.add_option(cmdoptions.use_pep517())
73
- self.cmd_opts.add_option(cmdoptions.no_use_pep517())
74
70
  self.cmd_opts.add_option(cmdoptions.check_build_deps())
75
71
 
76
72
  self.cmd_opts.add_option(cmdoptions.config_settings())
@@ -90,7 +86,7 @@ class LockCommand(RequirementCommand):
90
86
  self.parser.insert_option_group(0, self.cmd_opts)
91
87
 
92
88
  @with_cleanup
93
- def run(self, options: Values, args: List[str]) -> int:
89
+ def run(self, options: Values, args: list[str]) -> int:
94
90
  logger.verbose("Using %s", get_pip_version())
95
91
 
96
92
  logger.warning(
@@ -99,6 +95,8 @@ class LockCommand(RequirementCommand):
99
95
  "without prior warning."
100
96
  )
101
97
 
98
+ cmdoptions.check_build_constraints(options)
99
+
102
100
  session = self.get_default_session(options)
103
101
 
104
102
  finder = self._build_package_finder(
@@ -115,7 +113,6 @@ class LockCommand(RequirementCommand):
115
113
  )
116
114
 
117
115
  reqs = self.get_requirements(args, options, finder, session)
118
- check_legacy_setup_py_options(options, reqs)
119
116
 
120
117
  wheel_cache = WheelCache(options.cache_dir)
121
118
 
@@ -143,7 +140,6 @@ class LockCommand(RequirementCommand):
143
140
  ignore_installed=True,
144
141
  ignore_requires_python=options.ignore_requires_python,
145
142
  upgrade_strategy="to-satisfy-only",
146
- use_pep517=options.use_pep517,
147
143
  )
148
144
 
149
145
  self.trace_basic_info(finder)
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  import logging
2
4
  import shutil
3
5
  import sys
@@ -5,7 +7,7 @@ import textwrap
5
7
  import xmlrpc.client
6
8
  from collections import OrderedDict
7
9
  from optparse import Values
8
- from typing import Dict, List, Optional, TypedDict
10
+ from typing import TypedDict
9
11
 
10
12
  from pip._vendor.packaging.version import parse as parse_version
11
13
 
@@ -24,7 +26,7 @@ from pip._internal.utils.misc import write_output
24
26
  class TransformedHit(TypedDict):
25
27
  name: str
26
28
  summary: str
27
- versions: List[str]
29
+ versions: list[str]
28
30
 
29
31
 
30
32
  logger = logging.getLogger(__name__)
@@ -49,7 +51,7 @@ class SearchCommand(Command, SessionCommandMixin):
49
51
 
50
52
  self.parser.insert_option_group(0, self.cmd_opts)
51
53
 
52
- def run(self, options: Values, args: List[str]) -> int:
54
+ def run(self, options: Values, args: list[str]) -> int:
53
55
  if not args:
54
56
  raise CommandError("Missing required argument (search query).")
55
57
  query = args
@@ -65,7 +67,7 @@ class SearchCommand(Command, SessionCommandMixin):
65
67
  return SUCCESS
66
68
  return NO_MATCHES_FOUND
67
69
 
68
- def search(self, query: List[str], options: Values) -> List[Dict[str, str]]:
70
+ def search(self, query: list[str], options: Values) -> list[dict[str, str]]:
69
71
  index_url = options.index
70
72
 
71
73
  session = self.get_default_session(options)
@@ -83,13 +85,13 @@ class SearchCommand(Command, SessionCommandMixin):
83
85
  return hits
84
86
 
85
87
 
86
- def transform_hits(hits: List[Dict[str, str]]) -> List["TransformedHit"]:
88
+ def transform_hits(hits: list[dict[str, str]]) -> list[TransformedHit]:
87
89
  """
88
90
  The list from pypi is really a list of versions. We want a list of
89
91
  packages with the list of versions stored inline. This converts the
90
92
  list from pypi into one we can use.
91
93
  """
92
- packages: Dict[str, TransformedHit] = OrderedDict()
94
+ packages: dict[str, TransformedHit] = OrderedDict()
93
95
  for hit in hits:
94
96
  name = hit["name"]
95
97
  summary = hit["summary"]
@@ -111,7 +113,7 @@ def transform_hits(hits: List[Dict[str, str]]) -> List["TransformedHit"]:
111
113
  return list(packages.values())
112
114
 
113
115
 
114
- def print_dist_installation_info(latest: str, dist: Optional[BaseDistribution]) -> None:
116
+ def print_dist_installation_info(latest: str, dist: BaseDistribution | None) -> None:
115
117
  if dist is not None:
116
118
  with indent_log():
117
119
  if dist.version == latest:
@@ -128,15 +130,15 @@ def print_dist_installation_info(latest: str, dist: Optional[BaseDistribution])
128
130
  write_output("LATEST: %s", latest)
129
131
 
130
132
 
131
- def get_installed_distribution(name: str) -> Optional[BaseDistribution]:
133
+ def get_installed_distribution(name: str) -> BaseDistribution | None:
132
134
  env = get_default_environment()
133
135
  return env.get_distribution(name)
134
136
 
135
137
 
136
138
  def print_results(
137
- hits: List["TransformedHit"],
138
- name_column_width: Optional[int] = None,
139
- terminal_width: Optional[int] = None,
139
+ hits: list[TransformedHit],
140
+ name_column_width: int | None = None,
141
+ terminal_width: int | None = None,
140
142
  ) -> None:
141
143
  if not hits:
142
144
  return
@@ -172,5 +174,5 @@ def print_results(
172
174
  pass
173
175
 
174
176
 
175
- def highest_version(versions: List[str]) -> str:
177
+ def highest_version(versions: list[str]) -> str:
176
178
  return max(versions, key=parse_version)
@@ -1,7 +1,10 @@
1
+ from __future__ import annotations
2
+
1
3
  import logging
2
4
  import string
5
+ from collections.abc import Generator, Iterable, Iterator
3
6
  from optparse import Values
4
- from typing import Generator, Iterable, Iterator, List, NamedTuple, Optional
7
+ from typing import NamedTuple
5
8
 
6
9
  from pip._vendor.packaging.requirements import InvalidRequirement
7
10
  from pip._vendor.packaging.utils import canonicalize_name
@@ -44,7 +47,7 @@ class ShowCommand(Command):
44
47
 
45
48
  self.parser.insert_option_group(0, self.cmd_opts)
46
49
 
47
- def run(self, options: Values, args: List[str]) -> int:
50
+ def run(self, options: Values, args: list[str]) -> int:
48
51
  if not args:
49
52
  logger.warning("ERROR: Please provide a package name or names.")
50
53
  return ERROR
@@ -62,24 +65,24 @@ class _PackageInfo(NamedTuple):
62
65
  name: str
63
66
  version: str
64
67
  location: str
65
- editable_project_location: Optional[str]
66
- requires: List[str]
67
- required_by: List[str]
68
+ editable_project_location: str | None
69
+ requires: list[str]
70
+ required_by: list[str]
68
71
  installer: str
69
72
  metadata_version: str
70
- classifiers: List[str]
73
+ classifiers: list[str]
71
74
  summary: str
72
75
  homepage: str
73
- project_urls: List[str]
76
+ project_urls: list[str]
74
77
  author: str
75
78
  author_email: str
76
79
  license: str
77
80
  license_expression: str
78
- entry_points: List[str]
79
- files: Optional[List[str]]
81
+ entry_points: list[str]
82
+ files: list[str] | None
80
83
 
81
84
 
82
- def search_packages_info(query: List[str]) -> Generator[_PackageInfo, None, None]:
85
+ def search_packages_info(query: list[str]) -> Generator[_PackageInfo, None, None]:
83
86
  """
84
87
  Gather details from installed distributions. Print distribution name,
85
88
  version, location, and installed files. Installed files requires a
@@ -132,7 +135,7 @@ def search_packages_info(query: List[str]) -> Generator[_PackageInfo, None, None
132
135
 
133
136
  files_iter = dist.iter_declared_entries()
134
137
  if files_iter is None:
135
- files: Optional[List[str]] = None
138
+ files: list[str] | None = None
136
139
  else:
137
140
  files = sorted(files_iter)
138
141
 
@@ -1,6 +1,5 @@
1
1
  import logging
2
2
  from optparse import Values
3
- from typing import List
4
3
 
5
4
  from pip._vendor.packaging.utils import canonicalize_name
6
5
 
@@ -62,7 +61,7 @@ class UninstallCommand(Command, SessionCommandMixin):
62
61
  self.cmd_opts.add_option(cmdoptions.override_externally_managed())
63
62
  self.parser.insert_option_group(0, self.cmd_opts)
64
63
 
65
- def run(self, options: Values, args: List[str]) -> int:
64
+ def run(self, options: Values, args: list[str]) -> int:
66
65
  session = self.get_default_session(options)
67
66
 
68
67
  reqs_to_uninstall = {}
@@ -2,7 +2,6 @@ import logging
2
2
  import os
3
3
  import shutil
4
4
  from optparse import Values
5
- from typing import List
6
5
 
7
6
  from pip._internal.cache import WheelCache
8
7
  from pip._internal.cli import cmdoptions
@@ -12,7 +11,6 @@ from pip._internal.exceptions import CommandError
12
11
  from pip._internal.operations.build.build_tracker import get_build_tracker
13
12
  from pip._internal.req.req_install import (
14
13
  InstallRequirement,
15
- check_legacy_setup_py_options,
16
14
  )
17
15
  from pip._internal.utils.misc import ensure_dir, normalize_path
18
16
  from pip._internal.utils.temp_dir import TempDirectory
@@ -58,9 +56,9 @@ class WheelCommand(RequirementCommand):
58
56
  self.cmd_opts.add_option(cmdoptions.prefer_binary())
59
57
  self.cmd_opts.add_option(cmdoptions.no_build_isolation())
60
58
  self.cmd_opts.add_option(cmdoptions.use_pep517())
61
- self.cmd_opts.add_option(cmdoptions.no_use_pep517())
62
59
  self.cmd_opts.add_option(cmdoptions.check_build_deps())
63
60
  self.cmd_opts.add_option(cmdoptions.constraints())
61
+ self.cmd_opts.add_option(cmdoptions.build_constraints())
64
62
  self.cmd_opts.add_option(cmdoptions.editable())
65
63
  self.cmd_opts.add_option(cmdoptions.requirements())
66
64
  self.cmd_opts.add_option(cmdoptions.src())
@@ -77,8 +75,6 @@ class WheelCommand(RequirementCommand):
77
75
  )
78
76
 
79
77
  self.cmd_opts.add_option(cmdoptions.config_settings())
80
- self.cmd_opts.add_option(cmdoptions.build_options())
81
- self.cmd_opts.add_option(cmdoptions.global_options())
82
78
 
83
79
  self.cmd_opts.add_option(
84
80
  "--pre",
@@ -101,7 +97,9 @@ class WheelCommand(RequirementCommand):
101
97
  self.parser.insert_option_group(0, self.cmd_opts)
102
98
 
103
99
  @with_cleanup
104
- def run(self, options: Values, args: List[str]) -> int:
100
+ def run(self, options: Values, args: list[str]) -> int:
101
+ cmdoptions.check_build_constraints(options)
102
+
105
103
  session = self.get_default_session(options)
106
104
 
107
105
  finder = self._build_package_finder(options, session)
@@ -118,7 +116,6 @@ class WheelCommand(RequirementCommand):
118
116
  )
119
117
 
120
118
  reqs = self.get_requirements(args, options, finder, session)
121
- check_legacy_setup_py_options(options, reqs)
122
119
 
123
120
  wheel_cache = WheelCache(options.cache_dir)
124
121
 
@@ -139,29 +136,26 @@ class WheelCommand(RequirementCommand):
139
136
  options=options,
140
137
  wheel_cache=wheel_cache,
141
138
  ignore_requires_python=options.ignore_requires_python,
142
- use_pep517=options.use_pep517,
143
139
  )
144
140
 
145
141
  self.trace_basic_info(finder)
146
142
 
147
143
  requirement_set = resolver.resolve(reqs, check_supported_wheels=True)
148
144
 
149
- reqs_to_build: List[InstallRequirement] = []
145
+ preparer.prepare_linked_requirements_more(requirement_set.requirements.values())
146
+
147
+ reqs_to_build: list[InstallRequirement] = []
150
148
  for req in requirement_set.requirements.values():
151
149
  if req.is_wheel:
152
150
  preparer.save_linked_requirement(req)
153
151
  else:
154
152
  reqs_to_build.append(req)
155
153
 
156
- preparer.prepare_linked_requirements_more(requirement_set.requirements.values())
157
-
158
154
  # build wheels
159
155
  build_successes, build_failures = build(
160
156
  reqs_to_build,
161
157
  wheel_cache=wheel_cache,
162
158
  verify=(not options.no_verify),
163
- build_options=options.build_options or [],
164
- global_options=options.global_options or [],
165
159
  )
166
160
  for req in build_successes:
167
161
  assert req.link and req.link.is_wheel
@@ -11,11 +11,14 @@ Some terminology:
11
11
  A single word describing where the configuration key-value pair came from
12
12
  """
13
13
 
14
+ from __future__ import annotations
15
+
14
16
  import configparser
15
17
  import locale
16
18
  import os
17
19
  import sys
18
- from typing import Any, Dict, Iterable, List, NewType, Optional, Tuple
20
+ from collections.abc import Iterable
21
+ from typing import Any, NewType
19
22
 
20
23
  from pip._internal.exceptions import (
21
24
  ConfigurationError,
@@ -50,12 +53,11 @@ logger = getLogger(__name__)
50
53
  def _normalize_name(name: str) -> str:
51
54
  """Make a name consistent regardless of source (environment or file)"""
52
55
  name = name.lower().replace("_", "-")
53
- if name.startswith("--"):
54
- name = name[2:] # only prefer long opts
56
+ name = name.removeprefix("--") # only prefer long opts
55
57
  return name
56
58
 
57
59
 
58
- def _disassemble_key(name: str) -> List[str]:
60
+ def _disassemble_key(name: str) -> list[str]:
59
61
  if "." not in name:
60
62
  error_message = (
61
63
  "Key does not contain dot separated section and key. "
@@ -65,7 +67,7 @@ def _disassemble_key(name: str) -> List[str]:
65
67
  return name.split(".", 1)
66
68
 
67
69
 
68
- def get_configuration_files() -> Dict[Kind, List[str]]:
70
+ def get_configuration_files() -> dict[Kind, list[str]]:
69
71
  global_config_files = [
70
72
  os.path.join(path, CONFIG_BASENAME) for path in appdirs.site_config_dirs("pip")
71
73
  ]
@@ -98,7 +100,7 @@ class Configuration:
98
100
  and the data stored is also nice.
99
101
  """
100
102
 
101
- def __init__(self, isolated: bool, load_only: Optional[Kind] = None) -> None:
103
+ def __init__(self, isolated: bool, load_only: Kind | None = None) -> None:
102
104
  super().__init__()
103
105
 
104
106
  if load_only is not None and load_only not in VALID_LOAD_ONLY:
@@ -111,13 +113,13 @@ class Configuration:
111
113
  self.load_only = load_only
112
114
 
113
115
  # Because we keep track of where we got the data from
114
- self._parsers: Dict[Kind, List[Tuple[str, RawConfigParser]]] = {
116
+ self._parsers: dict[Kind, list[tuple[str, RawConfigParser]]] = {
115
117
  variant: [] for variant in OVERRIDE_ORDER
116
118
  }
117
- self._config: Dict[Kind, Dict[str, Any]] = {
119
+ self._config: dict[Kind, dict[str, dict[str, Any]]] = {
118
120
  variant: {} for variant in OVERRIDE_ORDER
119
121
  }
120
- self._modified_parsers: List[Tuple[str, RawConfigParser]] = []
122
+ self._modified_parsers: list[tuple[str, RawConfigParser]] = []
121
123
 
122
124
  def load(self) -> None:
123
125
  """Loads configuration from configuration files and environment"""
@@ -125,7 +127,7 @@ class Configuration:
125
127
  if not self.isolated:
126
128
  self._load_environment_vars()
127
129
 
128
- def get_file_to_edit(self) -> Optional[str]:
130
+ def get_file_to_edit(self) -> str | None:
129
131
  """Returns the file with highest priority in configuration"""
130
132
  assert self.load_only is not None, "Need to be specified a file to be editing"
131
133
 
@@ -134,7 +136,7 @@ class Configuration:
134
136
  except IndexError:
135
137
  return None
136
138
 
137
- def items(self) -> Iterable[Tuple[str, Any]]:
139
+ def items(self) -> Iterable[tuple[str, Any]]:
138
140
  """Returns key-value pairs like dict.items() representing the loaded
139
141
  configuration
140
142
  """
@@ -145,7 +147,10 @@ class Configuration:
145
147
  orig_key = key
146
148
  key = _normalize_name(key)
147
149
  try:
148
- return self._dictionary[key]
150
+ clean_config: dict[str, Any] = {}
151
+ for file_values in self._dictionary.values():
152
+ clean_config.update(file_values)
153
+ return clean_config[key]
149
154
  except KeyError:
150
155
  # disassembling triggers a more useful error message than simply
151
156
  # "No such key" in the case that the key isn't in the form command.option
@@ -168,7 +173,8 @@ class Configuration:
168
173
  parser.add_section(section)
169
174
  parser.set(section, name, value)
170
175
 
171
- self._config[self.load_only][key] = value
176
+ self._config[self.load_only].setdefault(fname, {})
177
+ self._config[self.load_only][fname][key] = value
172
178
  self._mark_as_modified(fname, parser)
173
179
 
174
180
  def unset_value(self, key: str) -> None:
@@ -178,11 +184,14 @@ class Configuration:
178
184
  self._ensure_have_load_only()
179
185
 
180
186
  assert self.load_only
181
- if key not in self._config[self.load_only]:
182
- raise ConfigurationError(f"No such key - {orig_key}")
183
-
184
187
  fname, parser = self._get_parser_to_modify()
185
188
 
189
+ if (
190
+ key not in self._config[self.load_only][fname]
191
+ and key not in self._config[self.load_only]
192
+ ):
193
+ raise ConfigurationError(f"No such key - {orig_key}")
194
+
186
195
  if parser is not None:
187
196
  section, name = _disassemble_key(key)
188
197
  if not (
@@ -197,8 +206,10 @@ class Configuration:
197
206
  if not parser.items(section):
198
207
  parser.remove_section(section)
199
208
  self._mark_as_modified(fname, parser)
200
-
201
- del self._config[self.load_only][key]
209
+ try:
210
+ del self._config[self.load_only][fname][key]
211
+ except KeyError:
212
+ del self._config[self.load_only][key]
202
213
 
203
214
  def save(self) -> None:
204
215
  """Save the current in-memory state."""
@@ -230,7 +241,7 @@ class Configuration:
230
241
  logger.debug("Will be working with %s variant only", self.load_only)
231
242
 
232
243
  @property
233
- def _dictionary(self) -> Dict[str, Any]:
244
+ def _dictionary(self) -> dict[str, dict[str, Any]]:
234
245
  """A dictionary representing the loaded configuration."""
235
246
  # NOTE: Dictionaries are not populated if not loaded. So, conditionals
236
247
  # are not needed here.
@@ -270,7 +281,8 @@ class Configuration:
270
281
 
271
282
  for section in parser.sections():
272
283
  items = parser.items(section)
273
- self._config[variant].update(self._normalized_keys(section, items))
284
+ self._config[variant].setdefault(fname, {})
285
+ self._config[variant][fname].update(self._normalized_keys(section, items))
274
286
 
275
287
  return parser
276
288
 
@@ -297,13 +309,14 @@ class Configuration:
297
309
 
298
310
  def _load_environment_vars(self) -> None:
299
311
  """Loads configuration from environment variables"""
300
- self._config[kinds.ENV_VAR].update(
312
+ self._config[kinds.ENV_VAR].setdefault(":env:", {})
313
+ self._config[kinds.ENV_VAR][":env:"].update(
301
314
  self._normalized_keys(":env:", self.get_environ_vars())
302
315
  )
303
316
 
304
317
  def _normalized_keys(
305
- self, section: str, items: Iterable[Tuple[str, Any]]
306
- ) -> Dict[str, Any]:
318
+ self, section: str, items: Iterable[tuple[str, Any]]
319
+ ) -> dict[str, Any]:
307
320
  """Normalizes items to construct a dictionary with normalized keys.
308
321
 
309
322
  This routine is where the names become keys and are made the same
@@ -315,7 +328,7 @@ class Configuration:
315
328
  normalized[key] = val
316
329
  return normalized
317
330
 
318
- def get_environ_vars(self) -> Iterable[Tuple[str, str]]:
331
+ def get_environ_vars(self) -> Iterable[tuple[str, str]]:
319
332
  """Returns a generator with all environmental vars with prefix PIP_"""
320
333
  for key, val in os.environ.items():
321
334
  if key.startswith("PIP_"):
@@ -324,7 +337,7 @@ class Configuration:
324
337
  yield name, val
325
338
 
326
339
  # XXX: This is patched in the tests.
327
- def iter_config_files(self) -> Iterable[Tuple[Kind, List[str]]]:
340
+ def iter_config_files(self) -> Iterable[tuple[Kind, list[str]]]:
328
341
  """Yields variant and configuration files associated with it.
329
342
 
330
343
  This should be treated like items of a dictionary. The order
@@ -356,11 +369,11 @@ class Configuration:
356
369
  else:
357
370
  yield kinds.ENV, []
358
371
 
359
- def get_values_in_config(self, variant: Kind) -> Dict[str, Any]:
372
+ def get_values_in_config(self, variant: Kind) -> dict[str, Any]:
360
373
  """Get values present in a config file"""
361
374
  return self._config[variant]
362
375
 
363
- def _get_parser_to_modify(self) -> Tuple[str, RawConfigParser]:
376
+ def _get_parser_to_modify(self) -> tuple[str, RawConfigParser]:
364
377
  # Determine which parser to modify
365
378
  assert self.load_only
366
379
  parsers = self._parsers[self.load_only]