pip 25.2__py3-none-any.whl → 26.0__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 (167) hide show
  1. pip/__init__.py +1 -1
  2. pip/_internal/__init__.py +0 -0
  3. pip/_internal/build_env.py +265 -8
  4. pip/_internal/cache.py +1 -1
  5. pip/_internal/cli/base_command.py +11 -0
  6. pip/_internal/cli/cmdoptions.py +200 -71
  7. pip/_internal/cli/index_command.py +20 -0
  8. pip/_internal/cli/main.py +11 -6
  9. pip/_internal/cli/main_parser.py +3 -1
  10. pip/_internal/cli/parser.py +96 -36
  11. pip/_internal/cli/progress_bars.py +4 -2
  12. pip/_internal/cli/req_command.py +126 -30
  13. pip/_internal/commands/cache.py +24 -0
  14. pip/_internal/commands/completion.py +2 -1
  15. pip/_internal/commands/download.py +12 -11
  16. pip/_internal/commands/index.py +13 -6
  17. pip/_internal/commands/install.py +55 -43
  18. pip/_internal/commands/list.py +14 -16
  19. pip/_internal/commands/lock.py +19 -14
  20. pip/_internal/commands/wheel.py +13 -23
  21. pip/_internal/configuration.py +1 -2
  22. pip/_internal/distributions/sdist.py +13 -14
  23. pip/_internal/exceptions.py +96 -6
  24. pip/_internal/index/collector.py +2 -3
  25. pip/_internal/index/package_finder.py +87 -21
  26. pip/_internal/locations/__init__.py +1 -2
  27. pip/_internal/locations/_sysconfig.py +4 -1
  28. pip/_internal/metadata/__init__.py +7 -2
  29. pip/_internal/metadata/importlib/_dists.py +8 -2
  30. pip/_internal/models/link.py +18 -14
  31. pip/_internal/models/release_control.py +92 -0
  32. pip/_internal/models/selection_prefs.py +6 -3
  33. pip/_internal/models/wheel.py +5 -66
  34. pip/_internal/network/auth.py +6 -2
  35. pip/_internal/network/cache.py +6 -11
  36. pip/_internal/network/download.py +4 -5
  37. pip/_internal/network/lazy_wheel.py +5 -3
  38. pip/_internal/network/session.py +14 -10
  39. pip/_internal/operations/build/wheel.py +4 -4
  40. pip/_internal/operations/build/wheel_editable.py +4 -4
  41. pip/_internal/operations/install/wheel.py +1 -2
  42. pip/_internal/operations/prepare.py +9 -4
  43. pip/_internal/pyproject.py +2 -61
  44. pip/_internal/req/__init__.py +1 -3
  45. pip/_internal/req/constructors.py +45 -39
  46. pip/_internal/req/pep723.py +41 -0
  47. pip/_internal/req/req_file.py +10 -2
  48. pip/_internal/req/req_install.py +32 -141
  49. pip/_internal/resolution/resolvelib/candidates.py +20 -11
  50. pip/_internal/resolution/resolvelib/factory.py +43 -1
  51. pip/_internal/resolution/resolvelib/provider.py +9 -0
  52. pip/_internal/resolution/resolvelib/reporter.py +21 -8
  53. pip/_internal/resolution/resolvelib/requirements.py +7 -3
  54. pip/_internal/resolution/resolvelib/resolver.py +2 -6
  55. pip/_internal/self_outdated_check.py +17 -16
  56. pip/_internal/utils/datetime.py +18 -0
  57. pip/_internal/utils/filesystem.py +52 -1
  58. pip/_internal/utils/logging.py +34 -2
  59. pip/_internal/utils/misc.py +18 -12
  60. pip/_internal/utils/pylock.py +116 -0
  61. pip/_internal/utils/unpacking.py +26 -1
  62. pip/_internal/vcs/versioncontrol.py +3 -1
  63. pip/_internal/wheel_builder.py +23 -96
  64. pip/_vendor/README.rst +180 -0
  65. pip/_vendor/cachecontrol/LICENSE.txt +13 -0
  66. pip/_vendor/cachecontrol/__init__.py +6 -3
  67. pip/_vendor/cachecontrol/adapter.py +0 -1
  68. pip/_vendor/cachecontrol/controller.py +1 -1
  69. pip/_vendor/cachecontrol/filewrapper.py +3 -1
  70. pip/_vendor/certifi/LICENSE +20 -0
  71. pip/_vendor/certifi/__init__.py +1 -1
  72. pip/_vendor/certifi/cacert.pem +62 -372
  73. pip/_vendor/dependency_groups/LICENSE.txt +9 -0
  74. pip/_vendor/distlib/LICENSE.txt +284 -0
  75. pip/_vendor/distro/LICENSE +202 -0
  76. pip/_vendor/idna/LICENSE.md +31 -0
  77. pip/_vendor/idna/codec.py +1 -1
  78. pip/_vendor/idna/core.py +1 -1
  79. pip/_vendor/idna/idnadata.py +72 -6
  80. pip/_vendor/idna/package_data.py +1 -1
  81. pip/_vendor/idna/uts46data.py +891 -731
  82. pip/_vendor/msgpack/COPYING +14 -0
  83. pip/_vendor/msgpack/__init__.py +2 -2
  84. pip/_vendor/packaging/LICENSE +3 -0
  85. pip/_vendor/packaging/LICENSE.APACHE +177 -0
  86. pip/_vendor/packaging/LICENSE.BSD +23 -0
  87. pip/_vendor/packaging/__init__.py +1 -1
  88. pip/_vendor/packaging/_elffile.py +0 -1
  89. pip/_vendor/packaging/_manylinux.py +36 -36
  90. pip/_vendor/packaging/_musllinux.py +1 -1
  91. pip/_vendor/packaging/_parser.py +22 -10
  92. pip/_vendor/packaging/_structures.py +8 -0
  93. pip/_vendor/packaging/_tokenizer.py +23 -25
  94. pip/_vendor/packaging/licenses/__init__.py +13 -11
  95. pip/_vendor/packaging/licenses/_spdx.py +41 -1
  96. pip/_vendor/packaging/markers.py +64 -38
  97. pip/_vendor/packaging/metadata.py +143 -27
  98. pip/_vendor/packaging/pylock.py +635 -0
  99. pip/_vendor/packaging/requirements.py +5 -10
  100. pip/_vendor/packaging/specifiers.py +219 -170
  101. pip/_vendor/packaging/tags.py +15 -20
  102. pip/_vendor/packaging/utils.py +19 -24
  103. pip/_vendor/packaging/version.py +315 -105
  104. pip/_vendor/pkg_resources/LICENSE +17 -0
  105. pip/_vendor/platformdirs/LICENSE +21 -0
  106. pip/_vendor/platformdirs/api.py +1 -1
  107. pip/_vendor/platformdirs/macos.py +10 -8
  108. pip/_vendor/platformdirs/version.py +16 -3
  109. pip/_vendor/platformdirs/windows.py +7 -1
  110. pip/_vendor/pygments/LICENSE +25 -0
  111. pip/_vendor/pyproject_hooks/LICENSE +21 -0
  112. pip/_vendor/requests/LICENSE +175 -0
  113. pip/_vendor/requests/__version__.py +2 -2
  114. pip/_vendor/requests/adapters.py +17 -40
  115. pip/_vendor/requests/sessions.py +1 -1
  116. pip/_vendor/resolvelib/LICENSE +13 -0
  117. pip/_vendor/resolvelib/__init__.py +1 -1
  118. pip/_vendor/resolvelib/resolvers/abstract.py +3 -3
  119. pip/_vendor/resolvelib/resolvers/resolution.py +5 -0
  120. pip/_vendor/rich/LICENSE +19 -0
  121. pip/_vendor/rich/style.py +7 -11
  122. pip/_vendor/tomli/LICENSE +21 -0
  123. pip/_vendor/tomli/__init__.py +1 -1
  124. pip/_vendor/tomli/_parser.py +28 -21
  125. pip/_vendor/tomli/_re.py +8 -5
  126. pip/_vendor/tomli_w/LICENSE +21 -0
  127. pip/_vendor/truststore/LICENSE +21 -0
  128. pip/_vendor/truststore/__init__.py +1 -1
  129. pip/_vendor/truststore/_api.py +14 -6
  130. pip/_vendor/truststore/_openssl.py +3 -1
  131. pip/_vendor/urllib3/LICENSE.txt +21 -0
  132. pip/_vendor/vendor.txt +11 -11
  133. {pip-25.2.dist-info → pip-26.0.dist-info}/METADATA +10 -11
  134. {pip-25.2.dist-info → pip-26.0.dist-info}/RECORD +158 -139
  135. {pip-25.2.dist-info → pip-26.0.dist-info}/WHEEL +1 -2
  136. pip-26.0.dist-info/entry_points.txt +4 -0
  137. {pip-25.2.dist-info → pip-26.0.dist-info}/licenses/AUTHORS.txt +27 -0
  138. {pip-25.2.dist-info → pip-26.0.dist-info}/licenses/src/pip/_vendor/idna/LICENSE.md +1 -1
  139. pip/_internal/models/pylock.py +0 -188
  140. pip/_internal/operations/build/metadata_legacy.py +0 -73
  141. pip/_internal/operations/build/wheel_legacy.py +0 -119
  142. pip/_internal/operations/install/editable_legacy.py +0 -48
  143. pip/_internal/utils/setuptools_build.py +0 -149
  144. pip-25.2.dist-info/entry_points.txt +0 -3
  145. pip-25.2.dist-info/licenses/src/pip/_vendor/tomli/LICENSE-HEADER +0 -3
  146. pip-25.2.dist-info/top_level.txt +0 -1
  147. {pip-25.2.dist-info → pip-26.0.dist-info}/licenses/LICENSE.txt +0 -0
  148. {pip-25.2.dist-info → pip-26.0.dist-info}/licenses/src/pip/_vendor/cachecontrol/LICENSE.txt +0 -0
  149. {pip-25.2.dist-info → pip-26.0.dist-info}/licenses/src/pip/_vendor/certifi/LICENSE +0 -0
  150. {pip-25.2.dist-info → pip-26.0.dist-info}/licenses/src/pip/_vendor/dependency_groups/LICENSE.txt +0 -0
  151. {pip-25.2.dist-info → pip-26.0.dist-info}/licenses/src/pip/_vendor/distlib/LICENSE.txt +0 -0
  152. {pip-25.2.dist-info → pip-26.0.dist-info}/licenses/src/pip/_vendor/distro/LICENSE +0 -0
  153. {pip-25.2.dist-info → pip-26.0.dist-info}/licenses/src/pip/_vendor/msgpack/COPYING +0 -0
  154. {pip-25.2.dist-info → pip-26.0.dist-info}/licenses/src/pip/_vendor/packaging/LICENSE +0 -0
  155. {pip-25.2.dist-info → pip-26.0.dist-info}/licenses/src/pip/_vendor/packaging/LICENSE.APACHE +0 -0
  156. {pip-25.2.dist-info → pip-26.0.dist-info}/licenses/src/pip/_vendor/packaging/LICENSE.BSD +0 -0
  157. {pip-25.2.dist-info → pip-26.0.dist-info}/licenses/src/pip/_vendor/pkg_resources/LICENSE +0 -0
  158. {pip-25.2.dist-info → pip-26.0.dist-info}/licenses/src/pip/_vendor/platformdirs/LICENSE +0 -0
  159. {pip-25.2.dist-info → pip-26.0.dist-info}/licenses/src/pip/_vendor/pygments/LICENSE +0 -0
  160. {pip-25.2.dist-info → pip-26.0.dist-info}/licenses/src/pip/_vendor/pyproject_hooks/LICENSE +0 -0
  161. {pip-25.2.dist-info → pip-26.0.dist-info}/licenses/src/pip/_vendor/requests/LICENSE +0 -0
  162. {pip-25.2.dist-info → pip-26.0.dist-info}/licenses/src/pip/_vendor/resolvelib/LICENSE +0 -0
  163. {pip-25.2.dist-info → pip-26.0.dist-info}/licenses/src/pip/_vendor/rich/LICENSE +0 -0
  164. {pip-25.2.dist-info → pip-26.0.dist-info}/licenses/src/pip/_vendor/tomli/LICENSE +0 -0
  165. {pip-25.2.dist-info → pip-26.0.dist-info}/licenses/src/pip/_vendor/tomli_w/LICENSE +0 -0
  166. {pip-25.2.dist-info → pip-26.0.dist-info}/licenses/src/pip/_vendor/truststore/LICENSE +0 -0
  167. {pip-25.2.dist-info → pip-26.0.dist-info}/licenses/src/pip/_vendor/urllib3/LICENSE.txt +0 -0
@@ -1,6 +1,5 @@
1
1
  from __future__ import annotations
2
2
 
3
- import importlib.util
4
3
  import os
5
4
  from collections import namedtuple
6
5
  from typing import Any
@@ -30,13 +29,11 @@ BuildSystemDetails = namedtuple(
30
29
 
31
30
 
32
31
  def load_pyproject_toml(
33
- use_pep517: bool | None, pyproject_toml: str, setup_py: str, req_name: str
34
- ) -> BuildSystemDetails | None:
32
+ pyproject_toml: str, setup_py: str, req_name: str
33
+ ) -> BuildSystemDetails:
35
34
  """Load the pyproject.toml file.
36
35
 
37
36
  Parameters:
38
- use_pep517 - Has the user requested PEP 517 processing? None
39
- means the user hasn't explicitly specified.
40
37
  pyproject_toml - Location of the project's pyproject.toml file
41
38
  setup_py - Location of the project's setup.py file
42
39
  req_name - The name of the requirement we're processing (for
@@ -69,57 +66,7 @@ def load_pyproject_toml(
69
66
  else:
70
67
  build_system = None
71
68
 
72
- # The following cases must use PEP 517
73
- # We check for use_pep517 being non-None and falsy because that means
74
- # the user explicitly requested --no-use-pep517. The value 0 as
75
- # opposed to False can occur when the value is provided via an
76
- # environment variable or config file option (due to the quirk of
77
- # strtobool() returning an integer in pip's configuration code).
78
- if has_pyproject and not has_setup:
79
- if use_pep517 is not None and not use_pep517:
80
- raise InstallationError(
81
- "Disabling PEP 517 processing is invalid: "
82
- "project does not have a setup.py"
83
- )
84
- use_pep517 = True
85
- elif build_system and "build-backend" in build_system:
86
- if use_pep517 is not None and not use_pep517:
87
- raise InstallationError(
88
- "Disabling PEP 517 processing is invalid: "
89
- "project specifies a build backend of {} "
90
- "in pyproject.toml".format(build_system["build-backend"])
91
- )
92
- use_pep517 = True
93
-
94
- # If we haven't worked out whether to use PEP 517 yet,
95
- # and the user hasn't explicitly stated a preference,
96
- # we do so if the project has a pyproject.toml file
97
- # or if we cannot import setuptools or wheels.
98
-
99
- # We fallback to PEP 517 when without setuptools or without the wheel package,
100
- # so setuptools can be installed as a default build backend.
101
- # For more info see:
102
- # https://discuss.python.org/t/pip-without-setuptools-could-the-experience-be-improved/11810/9
103
- # https://github.com/pypa/pip/issues/8559
104
- elif use_pep517 is None:
105
- use_pep517 = (
106
- has_pyproject
107
- or not importlib.util.find_spec("setuptools")
108
- or not importlib.util.find_spec("wheel")
109
- )
110
-
111
- # At this point, we know whether we're going to use PEP 517.
112
- assert use_pep517 is not None
113
-
114
- # If we're using the legacy code path, there is nothing further
115
- # for us to do here.
116
- if not use_pep517:
117
- return None
118
-
119
69
  if build_system is None:
120
- # Either the user has a pyproject.toml with no build-system
121
- # section, or the user has no pyproject.toml, but has opted in
122
- # explicitly via --use-pep517.
123
70
  # In the absence of any explicit backend specification, we
124
71
  # assume the setuptools backend that most closely emulates the
125
72
  # traditional direct setup.py execution, and require wheel and
@@ -130,12 +77,6 @@ def load_pyproject_toml(
130
77
  "build-backend": "setuptools.build_meta:__legacy__",
131
78
  }
132
79
 
133
- # If we're using PEP 517, we have build system information (either
134
- # from pyproject.toml, or defaulted by the code above).
135
- # Note that at this point, we do not know if the user has actually
136
- # specified a backend, though.
137
- assert build_system is not None
138
-
139
80
  # Ensure that the build-system section in pyproject.toml conforms
140
81
  # to PEP 518.
141
82
 
@@ -2,7 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  import collections
4
4
  import logging
5
- from collections.abc import Generator, Sequence
5
+ from collections.abc import Generator
6
6
  from dataclasses import dataclass
7
7
 
8
8
  from pip._internal.cli.progress_bars import BarType, get_install_progress_renderer
@@ -37,7 +37,6 @@ def _validate_requirements(
37
37
 
38
38
  def install_given_reqs(
39
39
  requirements: list[InstallRequirement],
40
- global_options: Sequence[str],
41
40
  root: str | None,
42
41
  home: str | None,
43
42
  prefix: str | None,
@@ -83,7 +82,6 @@ def install_given_reqs(
83
82
 
84
83
  try:
85
84
  requirement.install(
86
- global_options,
87
85
  root=root,
88
86
  home=home,
89
87
  prefix=prefix,
@@ -47,7 +47,7 @@ def _strip_extras(path: str) -> tuple[str, str | None]:
47
47
  m = re.match(r"^(.+)(\[[^\]]+\])$", path)
48
48
  extras = None
49
49
  if m:
50
- path_no_extras = m.group(1)
50
+ path_no_extras = m.group(1).rstrip()
51
51
  extras = m.group(2)
52
52
  else:
53
53
  path_no_extras = path
@@ -86,17 +86,25 @@ def _set_requirement_extras(req: Requirement, new_extras: set[str]) -> Requireme
86
86
  return get_requirement(f"{pre}{extras}{post}")
87
87
 
88
88
 
89
- def parse_editable(editable_req: str) -> tuple[str | None, str, set[str]]:
90
- """Parses an editable requirement into:
91
- - a requirement name
92
- - an URL
93
- - extras
94
- - editable options
95
- Accepted requirements:
96
- svn+http://blahblah@rev#egg=Foobar[baz]&subdirectory=version_subdir
97
- .[some_extra]
98
- """
89
+ def _parse_direct_url_editable(editable_req: str) -> tuple[str | None, str, set[str]]:
90
+ try:
91
+ req = Requirement(editable_req)
92
+ except InvalidRequirement:
93
+ pass
94
+ else:
95
+ if req.url:
96
+ # Join the marker back into the name part. This will be parsed out
97
+ # later into a Requirement again.
98
+ if req.marker:
99
+ name = f"{req.name} ; {req.marker}"
100
+ else:
101
+ name = req.name
102
+ return (name, req.url, req.extras)
99
103
 
104
+ raise ValueError
105
+
106
+
107
+ def _parse_pip_syntax_editable(editable_req: str) -> tuple[str | None, str, set[str]]:
100
108
  url = editable_req
101
109
 
102
110
  # If a file path is specified with extras, strip off the extras.
@@ -122,9 +130,27 @@ def parse_editable(editable_req: str) -> tuple[str | None, str, set[str]]:
122
130
  url = f"{version_control}+{url}"
123
131
  break
124
132
 
133
+ return Link(url).egg_fragment, url, set()
134
+
135
+
136
+ def parse_editable(editable_req: str) -> tuple[str | None, str, set[str]]:
137
+ """Parses an editable requirement into:
138
+ - a requirement name with environment markers
139
+ - an URL
140
+ - extras
141
+ Accepted requirements:
142
+ - svn+http://blahblah@rev#egg=Foobar[baz]&subdirectory=version_subdir
143
+ - local_path[some_extra]
144
+ - Foobar[extra] @ svn+http://blahblah@rev#subdirectory=subdir ; markers
145
+ """
146
+ try:
147
+ package_name, url, extras = _parse_direct_url_editable(editable_req)
148
+ except ValueError:
149
+ package_name, url, extras = _parse_pip_syntax_editable(editable_req)
150
+
125
151
  link = Link(url)
126
152
 
127
- if not link.is_vcs:
153
+ if not link.is_vcs and not link.url.startswith("file:"):
128
154
  backends = ", ".join(vcs.all_schemes)
129
155
  raise InstallationError(
130
156
  f"{editable_req} is not a valid editable requirement. "
@@ -132,13 +158,13 @@ def parse_editable(editable_req: str) -> tuple[str | None, str, set[str]]:
132
158
  f"(beginning with {backends})."
133
159
  )
134
160
 
135
- package_name = link.egg_fragment
136
- if not package_name:
161
+ # The project name can be inferred from local file URIs easily.
162
+ if not package_name and not link.url.startswith("file:"):
137
163
  raise InstallationError(
138
164
  f"Could not detect requirement name for '{editable_req}', "
139
- "please specify one with #egg=your_package_name"
165
+ "please specify one with your_package_name @ URL"
140
166
  )
141
- return package_name, url, set()
167
+ return package_name, url, extras
142
168
 
143
169
 
144
170
  def check_first_requirement_in_file(filename: str) -> None:
@@ -225,17 +251,17 @@ def install_req_from_editable(
225
251
  editable_req: str,
226
252
  comes_from: InstallRequirement | str | None = None,
227
253
  *,
228
- use_pep517: bool | None = None,
229
254
  isolated: bool = False,
230
- global_options: list[str] | None = None,
231
255
  hash_options: dict[str, list[str]] | None = None,
232
256
  constraint: bool = False,
233
257
  user_supplied: bool = False,
234
258
  permit_editable_wheels: bool = False,
235
259
  config_settings: dict[str, str | list[str]] | None = None,
236
260
  ) -> InstallRequirement:
237
- parts = parse_req_from_editable(editable_req)
261
+ if constraint:
262
+ raise InstallationError("Editable requirements are not allowed as constraints")
238
263
 
264
+ parts = parse_req_from_editable(editable_req)
239
265
  return InstallRequirement(
240
266
  parts.requirement,
241
267
  comes_from=comes_from,
@@ -244,9 +270,7 @@ def install_req_from_editable(
244
270
  permit_editable_wheels=permit_editable_wheels,
245
271
  link=parts.link,
246
272
  constraint=constraint,
247
- use_pep517=use_pep517,
248
273
  isolated=isolated,
249
- global_options=global_options,
250
274
  hash_options=hash_options,
251
275
  config_settings=config_settings,
252
276
  extras=parts.extras,
@@ -389,9 +413,7 @@ def install_req_from_line(
389
413
  name: str,
390
414
  comes_from: str | InstallRequirement | None = None,
391
415
  *,
392
- use_pep517: bool | None = None,
393
416
  isolated: bool = False,
394
- global_options: list[str] | None = None,
395
417
  hash_options: dict[str, list[str]] | None = None,
396
418
  constraint: bool = False,
397
419
  line_source: str | None = None,
@@ -411,9 +433,7 @@ def install_req_from_line(
411
433
  comes_from,
412
434
  link=parts.link,
413
435
  markers=parts.markers,
414
- use_pep517=use_pep517,
415
436
  isolated=isolated,
416
- global_options=global_options,
417
437
  hash_options=hash_options,
418
438
  config_settings=config_settings,
419
439
  constraint=constraint,
@@ -426,7 +446,6 @@ def install_req_from_req_string(
426
446
  req_string: str,
427
447
  comes_from: InstallRequirement | None = None,
428
448
  isolated: bool = False,
429
- use_pep517: bool | None = None,
430
449
  user_supplied: bool = False,
431
450
  ) -> InstallRequirement:
432
451
  try:
@@ -455,7 +474,6 @@ def install_req_from_req_string(
455
474
  req,
456
475
  comes_from,
457
476
  isolated=isolated,
458
- use_pep517=use_pep517,
459
477
  user_supplied=user_supplied,
460
478
  )
461
479
 
@@ -463,7 +481,6 @@ def install_req_from_req_string(
463
481
  def install_req_from_parsed_requirement(
464
482
  parsed_req: ParsedRequirement,
465
483
  isolated: bool = False,
466
- use_pep517: bool | None = None,
467
484
  user_supplied: bool = False,
468
485
  config_settings: dict[str, str | list[str]] | None = None,
469
486
  ) -> InstallRequirement:
@@ -471,7 +488,6 @@ def install_req_from_parsed_requirement(
471
488
  req = install_req_from_editable(
472
489
  parsed_req.requirement,
473
490
  comes_from=parsed_req.comes_from,
474
- use_pep517=use_pep517,
475
491
  constraint=parsed_req.constraint,
476
492
  isolated=isolated,
477
493
  user_supplied=user_supplied,
@@ -482,13 +498,7 @@ def install_req_from_parsed_requirement(
482
498
  req = install_req_from_line(
483
499
  parsed_req.requirement,
484
500
  comes_from=parsed_req.comes_from,
485
- use_pep517=use_pep517,
486
501
  isolated=isolated,
487
- global_options=(
488
- parsed_req.options.get("global_options", [])
489
- if parsed_req.options
490
- else []
491
- ),
492
502
  hash_options=(
493
503
  parsed_req.options.get("hashes", {}) if parsed_req.options else {}
494
504
  ),
@@ -509,9 +519,7 @@ def install_req_from_link_and_ireq(
509
519
  editable=ireq.editable,
510
520
  link=link,
511
521
  markers=ireq.markers,
512
- use_pep517=ireq.use_pep517,
513
522
  isolated=ireq.isolated,
514
- global_options=ireq.global_options,
515
523
  hash_options=ireq.hash_options,
516
524
  config_settings=ireq.config_settings,
517
525
  user_supplied=ireq.user_supplied,
@@ -532,9 +540,7 @@ def install_req_drop_extras(ireq: InstallRequirement) -> InstallRequirement:
532
540
  editable=ireq.editable,
533
541
  link=ireq.link,
534
542
  markers=ireq.markers,
535
- use_pep517=ireq.use_pep517,
536
543
  isolated=ireq.isolated,
537
- global_options=ireq.global_options,
538
544
  hash_options=ireq.hash_options,
539
545
  constraint=ireq.constraint,
540
546
  extras=[],
@@ -0,0 +1,41 @@
1
+ import re
2
+ from typing import Any
3
+
4
+ from pip._internal.utils.compat import tomllib
5
+
6
+ REGEX = r"(?m)^# /// (?P<type>[a-zA-Z0-9-]+)$\s(?P<content>(^#(| .*)$\s)+)^# ///$"
7
+
8
+
9
+ class PEP723Exception(ValueError):
10
+ """Raised to indicate a problem when parsing PEP 723 metadata from a script"""
11
+
12
+ def __init__(self, msg: str) -> None:
13
+ self.msg = msg
14
+
15
+
16
+ def pep723_metadata(scriptfile: str) -> dict[str, Any]:
17
+ with open(scriptfile) as f:
18
+ script = f.read()
19
+
20
+ name = "script"
21
+ matches = list(
22
+ filter(lambda m: m.group("type") == name, re.finditer(REGEX, script))
23
+ )
24
+
25
+ if len(matches) > 1:
26
+ raise PEP723Exception(f"Multiple {name!r} blocks found in {scriptfile!r}")
27
+ elif len(matches) == 1:
28
+ content = "".join(
29
+ line[2:] if line.startswith("# ") else line[1:]
30
+ for line in matches[0].group("content").splitlines(keepends=True)
31
+ )
32
+ try:
33
+ metadata = tomllib.loads(content)
34
+ except Exception as exc:
35
+ raise PEP723Exception(f"Failed to parse TOML in {scriptfile!r}") from exc
36
+ else:
37
+ raise PEP723Exception(
38
+ f"File does not contain {name!r} metadata: {scriptfile!r}"
39
+ )
40
+
41
+ return metadata
@@ -25,6 +25,7 @@ from typing import (
25
25
 
26
26
  from pip._internal.cli import cmdoptions
27
27
  from pip._internal.exceptions import InstallationError, RequirementsFileParseError
28
+ from pip._internal.models.release_control import ReleaseControl
28
29
  from pip._internal.models.search_scope import SearchScope
29
30
 
30
31
  if TYPE_CHECKING:
@@ -59,13 +60,14 @@ SUPPORTED_OPTIONS: list[Callable[..., optparse.Option]] = [
59
60
  cmdoptions.prefer_binary,
60
61
  cmdoptions.require_hashes,
61
62
  cmdoptions.pre,
63
+ cmdoptions.all_releases,
64
+ cmdoptions.only_final,
62
65
  cmdoptions.trusted_host,
63
66
  cmdoptions.use_new_feature,
64
67
  ]
65
68
 
66
69
  # options to be passed to requirements
67
70
  SUPPORTED_OPTIONS_REQ: list[Callable[..., optparse.Option]] = [
68
- cmdoptions.global_options,
69
71
  cmdoptions.hash,
70
72
  cmdoptions.config_settings,
71
73
  ]
@@ -274,8 +276,14 @@ def handle_option_line(
274
276
  )
275
277
  finder.search_scope = search_scope
276
278
 
279
+ # Transform --pre into --all-releases :all:
277
280
  if opts.pre:
278
- finder.set_allow_all_prereleases()
281
+ if not opts.release_control:
282
+ opts.release_control = ReleaseControl()
283
+ opts.release_control.all_releases.add(":all:")
284
+
285
+ if opts.release_control:
286
+ finder.set_release_control(opts.release_control)
279
287
 
280
288
  if opts.prefer_binary:
281
289
  finder.set_prefer_binary()
@@ -7,7 +7,7 @@ import shutil
7
7
  import sys
8
8
  import uuid
9
9
  import zipfile
10
- from collections.abc import Collection, Iterable, Sequence
10
+ from collections.abc import Collection, Iterable
11
11
  from optparse import Values
12
12
  from pathlib import Path
13
13
  from typing import Any
@@ -34,12 +34,6 @@ from pip._internal.models.direct_url import DirectUrl
34
34
  from pip._internal.models.link import Link
35
35
  from pip._internal.operations.build.metadata import generate_metadata
36
36
  from pip._internal.operations.build.metadata_editable import generate_editable_metadata
37
- from pip._internal.operations.build.metadata_legacy import (
38
- generate_metadata as generate_metadata_legacy,
39
- )
40
- from pip._internal.operations.install.editable_legacy import (
41
- install_editable as install_editable_legacy,
42
- )
43
37
  from pip._internal.operations.install.wheel import install_wheel
44
38
  from pip._internal.pyproject import load_pyproject_toml, make_pyproject_path
45
39
  from pip._internal.req.req_uninstall import UninstallPathSet
@@ -79,10 +73,8 @@ class InstallRequirement:
79
73
  editable: bool = False,
80
74
  link: Link | None = None,
81
75
  markers: Marker | None = None,
82
- use_pep517: bool | None = None,
83
76
  isolated: bool = False,
84
77
  *,
85
- global_options: list[str] | None = None,
86
78
  hash_options: dict[str, list[str]] | None = None,
87
79
  config_settings: dict[str, str | list[str]] | None = None,
88
80
  constraint: bool = False,
@@ -149,7 +141,6 @@ class InstallRequirement:
149
141
  # Set to True after successful installation
150
142
  self.install_succeeded: bool | None = None
151
143
  # Supplied options
152
- self.global_options = global_options if global_options else []
153
144
  self.hash_options = hash_options if hash_options else {}
154
145
  self.config_settings = config_settings
155
146
  # Set to True after successful preparation of this requirement
@@ -168,6 +159,10 @@ class InstallRequirement:
168
159
  # details).
169
160
  self.metadata_directory: str | None = None
170
161
 
162
+ # The cached metadata distribution that this requirement represents.
163
+ # See get_dist / set_dist.
164
+ self._distribution: BaseDistribution | None = None
165
+
171
166
  # The static build requirements (from pyproject.toml)
172
167
  self.pyproject_requires: list[str] | None = None
173
168
 
@@ -177,23 +172,6 @@ class InstallRequirement:
177
172
  # The PEP 517 backend we should use to build the project
178
173
  self.pep517_backend: BuildBackendHookCaller | None = None
179
174
 
180
- # Are we using PEP 517 for this requirement?
181
- # After pyproject.toml has been loaded, the only valid values are True
182
- # and False. Before loading, None is valid (meaning "use the default").
183
- # Setting an explicit value before loading pyproject.toml is supported,
184
- # but after loading this flag should be treated as read only.
185
- self.use_pep517 = use_pep517
186
-
187
- # If config settings are provided, enforce PEP 517.
188
- if self.config_settings:
189
- if self.use_pep517 is False:
190
- logger.warning(
191
- "--no-use-pep517 ignored for %s "
192
- "because --config-settings are specified.",
193
- self,
194
- )
195
- self.use_pep517 = True
196
-
197
175
  # This requirement needs more preparation before it can be built
198
176
  self.needs_more_preparation = False
199
177
 
@@ -250,8 +228,6 @@ class InstallRequirement:
250
228
 
251
229
  @functools.cached_property
252
230
  def supports_pyproject_editable(self) -> bool:
253
- if not self.use_pep517:
254
- return False
255
231
  assert self.pep517_backend
256
232
  with self.build_env:
257
233
  runner = runner_with_spinner_message(
@@ -492,13 +468,6 @@ class InstallRequirement:
492
468
 
493
469
  return setup_py
494
470
 
495
- @property
496
- def setup_cfg_path(self) -> str:
497
- assert self.source_dir, f"No source dir for {self}"
498
- setup_cfg = os.path.join(self.unpacked_source_directory, "setup.cfg")
499
-
500
- return setup_cfg
501
-
502
471
  @property
503
472
  def pyproject_toml_path(self) -> str:
504
473
  assert self.source_dir, f"No source dir for {self}"
@@ -508,20 +477,12 @@ class InstallRequirement:
508
477
  """Load the pyproject.toml file.
509
478
 
510
479
  After calling this routine, all of the attributes related to PEP 517
511
- processing for this requirement have been set. In particular, the
512
- use_pep517 attribute can be used to determine whether we should
513
- follow the PEP 517 or legacy (setup.py) code path.
480
+ processing for this requirement have been set.
514
481
  """
515
482
  pyproject_toml_data = load_pyproject_toml(
516
- self.use_pep517, self.pyproject_toml_path, self.setup_py_path, str(self)
483
+ self.pyproject_toml_path, self.setup_py_path, str(self)
517
484
  )
518
-
519
- if pyproject_toml_data is None:
520
- assert not self.config_settings
521
- self.use_pep517 = False
522
- return
523
-
524
- self.use_pep517 = True
485
+ assert pyproject_toml_data
525
486
  requires, backend, check, backend_path = pyproject_toml_data
526
487
  self.requirements_to_check = check
527
488
  self.pyproject_requires = requires
@@ -532,23 +493,15 @@ class InstallRequirement:
532
493
  backend_path=backend_path,
533
494
  )
534
495
 
535
- def isolated_editable_sanity_check(self) -> None:
496
+ def editable_sanity_check(self) -> None:
536
497
  """Check that an editable requirement if valid for use with PEP 517/518.
537
498
 
538
- This verifies that an editable that has a pyproject.toml either supports PEP 660
539
- or as a setup.py or a setup.cfg
499
+ This verifies that an editable has a build backend that supports PEP 660.
540
500
  """
541
- if (
542
- self.editable
543
- and self.use_pep517
544
- and not self.supports_pyproject_editable
545
- and not os.path.isfile(self.setup_py_path)
546
- and not os.path.isfile(self.setup_cfg_path)
547
- ):
501
+ if self.editable and not self.supports_pyproject_editable:
548
502
  raise InstallationError(
549
- f"Project {self} has a 'pyproject.toml' and its build "
550
- f"backend is missing the 'build_editable' hook. Since it does not "
551
- 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 "
552
505
  f"it cannot be installed in editable mode. "
553
506
  f"Consider using a build backend that supports PEP 660."
554
507
  )
@@ -562,30 +515,21 @@ class InstallRequirement:
562
515
  assert self.source_dir, f"No source dir for {self}"
563
516
  details = self.name or f"from {self.link}"
564
517
 
565
- if self.use_pep517:
566
- assert self.pep517_backend is not None
567
- if (
568
- self.editable
569
- and self.permit_editable_wheels
570
- and self.supports_pyproject_editable
571
- ):
572
- self.metadata_directory = generate_editable_metadata(
573
- build_env=self.build_env,
574
- backend=self.pep517_backend,
575
- details=details,
576
- )
577
- else:
578
- self.metadata_directory = generate_metadata(
579
- build_env=self.build_env,
580
- backend=self.pep517_backend,
581
- details=details,
582
- )
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
+ )
583
529
  else:
584
- self.metadata_directory = generate_metadata_legacy(
530
+ self.metadata_directory = generate_metadata(
585
531
  build_env=self.build_env,
586
- setup_py_path=self.setup_py_path,
587
- source_dir=self.unpacked_source_directory,
588
- isolated=self.isolated,
532
+ backend=self.pep517_backend,
589
533
  details=details,
590
534
  )
591
535
 
@@ -604,8 +548,13 @@ class InstallRequirement:
604
548
 
605
549
  return self._metadata
606
550
 
551
+ def set_dist(self, distribution: BaseDistribution) -> None:
552
+ self._distribution = distribution
553
+
607
554
  def get_dist(self) -> BaseDistribution:
608
- if self.metadata_directory:
555
+ if self._distribution is not None:
556
+ return self._distribution
557
+ elif self.metadata_directory:
609
558
  return get_directory_distribution(self.metadata_directory)
610
559
  elif self.local_file_path and self.is_wheel:
611
560
  assert self.req is not None
@@ -809,7 +758,6 @@ class InstallRequirement:
809
758
 
810
759
  def install(
811
760
  self,
812
- global_options: Sequence[str] | None = None,
813
761
  root: str | None = None,
814
762
  home: str | None = None,
815
763
  prefix: str | None = None,
@@ -827,43 +775,6 @@ class InstallRequirement:
827
775
  prefix=prefix,
828
776
  )
829
777
 
830
- if self.editable and not self.is_wheel:
831
- deprecated(
832
- reason=(
833
- f"Legacy editable install of {self} (setup.py develop) "
834
- "is deprecated."
835
- ),
836
- replacement=(
837
- "to add a pyproject.toml or enable --use-pep517, "
838
- "and use setuptools >= 64. "
839
- "If the resulting installation is not behaving as expected, "
840
- "try using --config-settings editable_mode=compat. "
841
- "Please consult the setuptools documentation for more information"
842
- ),
843
- gone_in="25.3",
844
- issue=11457,
845
- )
846
- if self.config_settings:
847
- logger.warning(
848
- "--config-settings ignored for legacy editable install of %s. "
849
- "Consider upgrading to a version of setuptools "
850
- "that supports PEP 660 (>= 64).",
851
- self,
852
- )
853
- install_editable_legacy(
854
- global_options=global_options if global_options is not None else [],
855
- prefix=prefix,
856
- home=home,
857
- use_user_site=use_user_site,
858
- name=self.req.name,
859
- setup_py_path=self.setup_py_path,
860
- isolated=self.isolated,
861
- build_env=self.build_env,
862
- unpacked_source_directory=self.unpacked_source_directory,
863
- )
864
- self.install_succeeded = True
865
- return
866
-
867
778
  assert self.is_wheel
868
779
  assert self.local_file_path
869
780
 
@@ -915,23 +826,3 @@ def _has_option(options: Values, reqs: list[InstallRequirement], option: str) ->
915
826
  if getattr(req, option, None):
916
827
  return True
917
828
  return False
918
-
919
-
920
- def check_legacy_setup_py_options(
921
- options: Values,
922
- reqs: list[InstallRequirement],
923
- ) -> None:
924
- has_build_options = _has_option(options, reqs, "build_options")
925
- has_global_options = _has_option(options, reqs, "global_options")
926
- if has_build_options or has_global_options:
927
- deprecated(
928
- reason="--build-option and --global-option are deprecated.",
929
- issue=11859,
930
- replacement="to use --config-settings",
931
- gone_in="25.3",
932
- )
933
- logger.warning(
934
- "Implying --no-binary=:all: due to the presence of "
935
- "--build-option / --global-option. "
936
- )
937
- options.format_control.disallow_binaries()