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
pip/__init__.py CHANGED
@@ -1,9 +1,9 @@
1
- from typing import List, Optional
1
+ from __future__ import annotations
2
2
 
3
- __version__ = "25.1.1"
3
+ __version__ = "25.3"
4
4
 
5
5
 
6
- def main(args: Optional[List[str]] = None) -> int:
6
+ def main(args: list[str] | None = None) -> int:
7
7
  """This is an internal API only meant for use by pip's own console scripts.
8
8
 
9
9
  For additional details, see https://github.com/pypa/pip/issues/7498.
pip/_internal/__init__.py CHANGED
@@ -1,4 +1,4 @@
1
- from typing import List, Optional
1
+ from __future__ import annotations
2
2
 
3
3
  from pip._internal.utils import _log
4
4
 
@@ -7,7 +7,7 @@ from pip._internal.utils import _log
7
7
  _log.init_logging()
8
8
 
9
9
 
10
- def main(args: Optional[List[str]] = None) -> int:
10
+ def main(args: list[str] | None = None) -> int:
11
11
  """This is preserved for old console scripts that may still be referencing
12
12
  it.
13
13
 
@@ -1,5 +1,7 @@
1
1
  """Build Environment used for isolation during sdist building"""
2
2
 
3
+ from __future__ import annotations
4
+
3
5
  import logging
4
6
  import os
5
7
  import pathlib
@@ -7,8 +9,9 @@ import site
7
9
  import sys
8
10
  import textwrap
9
11
  from collections import OrderedDict
12
+ from collections.abc import Iterable
10
13
  from types import TracebackType
11
- from typing import TYPE_CHECKING, Iterable, List, Optional, Set, Tuple, Type, Union
14
+ from typing import TYPE_CHECKING, Protocol, TypedDict
12
15
 
13
16
  from pip._vendor.packaging.version import Version
14
17
 
@@ -16,6 +19,7 @@ from pip import __file__ as pip_location
16
19
  from pip._internal.cli.spinners import open_spinner
17
20
  from pip._internal.locations import get_platlib, get_purelib, get_scheme
18
21
  from pip._internal.metadata import get_default_environment, get_environment
22
+ from pip._internal.utils.deprecation import deprecated
19
23
  from pip._internal.utils.logging import VERBOSE
20
24
  from pip._internal.utils.packaging import get_requirement
21
25
  from pip._internal.utils.subprocess import call_subprocess
@@ -23,11 +27,16 @@ from pip._internal.utils.temp_dir import TempDirectory, tempdir_kinds
23
27
 
24
28
  if TYPE_CHECKING:
25
29
  from pip._internal.index.package_finder import PackageFinder
30
+ from pip._internal.req.req_install import InstallRequirement
31
+
32
+ class ExtraEnviron(TypedDict, total=False):
33
+ extra_environ: dict[str, str]
34
+
26
35
 
27
36
  logger = logging.getLogger(__name__)
28
37
 
29
38
 
30
- def _dedup(a: str, b: str) -> Union[Tuple[str], Tuple[str, str]]:
39
+ def _dedup(a: str, b: str) -> tuple[str] | tuple[str, str]:
31
40
  return (a, b) if a != b else (a,)
32
41
 
33
42
 
@@ -56,7 +65,7 @@ def get_runnable_pip() -> str:
56
65
  return os.fsdecode(source / "__pip-runner__.py")
57
66
 
58
67
 
59
- def _get_system_sitepackages() -> Set[str]:
68
+ def _get_system_sitepackages() -> set[str]:
60
69
  """Get system site packages
61
70
 
62
71
  Usually from site.getsitepackages,
@@ -76,10 +85,171 @@ def _get_system_sitepackages() -> Set[str]:
76
85
  return {os.path.normcase(path) for path in system_sites}
77
86
 
78
87
 
88
+ class BuildEnvironmentInstaller(Protocol):
89
+ """
90
+ Interface for installing build dependencies into an isolated build
91
+ environment.
92
+ """
93
+
94
+ def install(
95
+ self,
96
+ requirements: Iterable[str],
97
+ prefix: _Prefix,
98
+ *,
99
+ kind: str,
100
+ for_req: InstallRequirement | None,
101
+ ) -> None: ...
102
+
103
+
104
+ class SubprocessBuildEnvironmentInstaller:
105
+ """
106
+ Install build dependencies by calling pip in a subprocess.
107
+ """
108
+
109
+ def __init__(
110
+ self,
111
+ finder: PackageFinder,
112
+ build_constraints: list[str] | None = None,
113
+ build_constraint_feature_enabled: bool = False,
114
+ ) -> None:
115
+ self.finder = finder
116
+ self._build_constraints = build_constraints or []
117
+ self._build_constraint_feature_enabled = build_constraint_feature_enabled
118
+
119
+ def _deprecation_constraint_check(self) -> None:
120
+ """
121
+ Check for deprecation warning: PIP_CONSTRAINT affecting build environments.
122
+
123
+ This warns when build-constraint feature is NOT enabled and PIP_CONSTRAINT
124
+ is not empty.
125
+ """
126
+ if self._build_constraint_feature_enabled or self._build_constraints:
127
+ return
128
+
129
+ pip_constraint = os.environ.get("PIP_CONSTRAINT")
130
+ if not pip_constraint or not pip_constraint.strip():
131
+ return
132
+
133
+ deprecated(
134
+ reason=(
135
+ "Setting PIP_CONSTRAINT will not affect "
136
+ "build constraints in the future,"
137
+ ),
138
+ replacement=(
139
+ "to specify build constraints using --build-constraint or "
140
+ "PIP_BUILD_CONSTRAINT. To disable this warning without "
141
+ "any build constraints set --use-feature=build-constraint or "
142
+ 'PIP_USE_FEATURE="build-constraint"'
143
+ ),
144
+ gone_in="26.2",
145
+ issue=None,
146
+ )
147
+
148
+ def install(
149
+ self,
150
+ requirements: Iterable[str],
151
+ prefix: _Prefix,
152
+ *,
153
+ kind: str,
154
+ for_req: InstallRequirement | None,
155
+ ) -> None:
156
+ self._deprecation_constraint_check()
157
+
158
+ finder = self.finder
159
+ args: list[str] = [
160
+ sys.executable,
161
+ get_runnable_pip(),
162
+ "install",
163
+ "--ignore-installed",
164
+ "--no-user",
165
+ "--prefix",
166
+ prefix.path,
167
+ "--no-warn-script-location",
168
+ "--disable-pip-version-check",
169
+ # As the build environment is ephemeral, it's wasteful to
170
+ # pre-compile everything, especially as not every Python
171
+ # module will be used/compiled in most cases.
172
+ "--no-compile",
173
+ # The prefix specified two lines above, thus
174
+ # target from config file or env var should be ignored
175
+ "--target",
176
+ "",
177
+ ]
178
+ if logger.getEffectiveLevel() <= logging.DEBUG:
179
+ args.append("-vv")
180
+ elif logger.getEffectiveLevel() <= VERBOSE:
181
+ args.append("-v")
182
+ for format_control in ("no_binary", "only_binary"):
183
+ formats = getattr(finder.format_control, format_control)
184
+ args.extend(
185
+ (
186
+ "--" + format_control.replace("_", "-"),
187
+ ",".join(sorted(formats or {":none:"})),
188
+ )
189
+ )
190
+
191
+ index_urls = finder.index_urls
192
+ if index_urls:
193
+ args.extend(["-i", index_urls[0]])
194
+ for extra_index in index_urls[1:]:
195
+ args.extend(["--extra-index-url", extra_index])
196
+ else:
197
+ args.append("--no-index")
198
+ for link in finder.find_links:
199
+ args.extend(["--find-links", link])
200
+
201
+ if finder.proxy:
202
+ args.extend(["--proxy", finder.proxy])
203
+ for host in finder.trusted_hosts:
204
+ args.extend(["--trusted-host", host])
205
+ if finder.custom_cert:
206
+ args.extend(["--cert", finder.custom_cert])
207
+ if finder.client_cert:
208
+ args.extend(["--client-cert", finder.client_cert])
209
+ if finder.allow_all_prereleases:
210
+ args.append("--pre")
211
+ if finder.prefer_binary:
212
+ args.append("--prefer-binary")
213
+
214
+ # Handle build constraints
215
+ if self._build_constraint_feature_enabled:
216
+ args.extend(["--use-feature", "build-constraint"])
217
+
218
+ if self._build_constraints:
219
+ # Build constraints must be passed as both constraints
220
+ # and build constraints, so that nested builds receive
221
+ # build constraints
222
+ for constraint_file in self._build_constraints:
223
+ args.extend(["--constraint", constraint_file])
224
+ args.extend(["--build-constraint", constraint_file])
225
+
226
+ extra_environ: ExtraEnviron = {}
227
+ if self._build_constraint_feature_enabled and not self._build_constraints:
228
+ # If there are no build constraints but the build constraints
229
+ # feature is enabled then we must ignore regular constraints
230
+ # in the isolated build environment
231
+ extra_environ = {"extra_environ": {"_PIP_IN_BUILD_IGNORE_CONSTRAINTS": "1"}}
232
+
233
+ args.append("--")
234
+ args.extend(requirements)
235
+
236
+ identify_requirement = (
237
+ f" for {for_req.name}" if for_req and for_req.name else ""
238
+ )
239
+ with open_spinner(f"Installing {kind}") as spinner:
240
+ call_subprocess(
241
+ args,
242
+ command_desc=f"installing {kind}{identify_requirement}",
243
+ spinner=spinner,
244
+ **extra_environ,
245
+ )
246
+
247
+
79
248
  class BuildEnvironment:
80
249
  """Creates and manages an isolated environment to install build deps"""
81
250
 
82
- def __init__(self) -> None:
251
+ def __init__(self, installer: BuildEnvironmentInstaller) -> None:
252
+ self.installer = installer
83
253
  temp_dir = TempDirectory(kind=tempdir_kinds.BUILD_ENV, globally_managed=True)
84
254
 
85
255
  self._prefixes = OrderedDict(
@@ -87,8 +257,8 @@ class BuildEnvironment:
87
257
  for name in ("normal", "overlay")
88
258
  )
89
259
 
90
- self._bin_dirs: List[str] = []
91
- self._lib_dirs: List[str] = []
260
+ self._bin_dirs: list[str] = []
261
+ self._lib_dirs: list[str] = []
92
262
  for prefix in reversed(list(self._prefixes.values())):
93
263
  self._bin_dirs.append(prefix.bin_dir)
94
264
  self._lib_dirs.extend(prefix.lib_dirs)
@@ -156,9 +326,9 @@ class BuildEnvironment:
156
326
 
157
327
  def __exit__(
158
328
  self,
159
- exc_type: Optional[Type[BaseException]],
160
- exc_val: Optional[BaseException],
161
- exc_tb: Optional[TracebackType],
329
+ exc_type: type[BaseException] | None,
330
+ exc_val: BaseException | None,
331
+ exc_tb: TracebackType | None,
162
332
  ) -> None:
163
333
  for varname, old_value in self._save_env.items():
164
334
  if old_value is None:
@@ -168,7 +338,7 @@ class BuildEnvironment:
168
338
 
169
339
  def check_requirements(
170
340
  self, reqs: Iterable[str]
171
- ) -> Tuple[Set[Tuple[str, str]], Set[str]]:
341
+ ) -> tuple[set[tuple[str, str]], set[str]]:
172
342
  """Return 2 sets:
173
343
  - conflicting requirements: set of (installed, wanted) reqs tuples
174
344
  - missing requirements: set of reqs
@@ -202,96 +372,18 @@ class BuildEnvironment:
202
372
 
203
373
  def install_requirements(
204
374
  self,
205
- finder: "PackageFinder",
206
375
  requirements: Iterable[str],
207
376
  prefix_as_string: str,
208
377
  *,
209
378
  kind: str,
379
+ for_req: InstallRequirement | None = None,
210
380
  ) -> None:
211
381
  prefix = self._prefixes[prefix_as_string]
212
382
  assert not prefix.setup
213
383
  prefix.setup = True
214
384
  if not requirements:
215
385
  return
216
- self._install_requirements(
217
- get_runnable_pip(),
218
- finder,
219
- requirements,
220
- prefix,
221
- kind=kind,
222
- )
223
-
224
- @staticmethod
225
- def _install_requirements(
226
- pip_runnable: str,
227
- finder: "PackageFinder",
228
- requirements: Iterable[str],
229
- prefix: _Prefix,
230
- *,
231
- kind: str,
232
- ) -> None:
233
- args: List[str] = [
234
- sys.executable,
235
- pip_runnable,
236
- "install",
237
- "--ignore-installed",
238
- "--no-user",
239
- "--prefix",
240
- prefix.path,
241
- "--no-warn-script-location",
242
- "--disable-pip-version-check",
243
- # As the build environment is ephemeral, it's wasteful to
244
- # pre-compile everything, especially as not every Python
245
- # module will be used/compiled in most cases.
246
- "--no-compile",
247
- # The prefix specified two lines above, thus
248
- # target from config file or env var should be ignored
249
- "--target",
250
- "",
251
- ]
252
- if logger.getEffectiveLevel() <= logging.DEBUG:
253
- args.append("-vv")
254
- elif logger.getEffectiveLevel() <= VERBOSE:
255
- args.append("-v")
256
- for format_control in ("no_binary", "only_binary"):
257
- formats = getattr(finder.format_control, format_control)
258
- args.extend(
259
- (
260
- "--" + format_control.replace("_", "-"),
261
- ",".join(sorted(formats or {":none:"})),
262
- )
263
- )
264
-
265
- index_urls = finder.index_urls
266
- if index_urls:
267
- args.extend(["-i", index_urls[0]])
268
- for extra_index in index_urls[1:]:
269
- args.extend(["--extra-index-url", extra_index])
270
- else:
271
- args.append("--no-index")
272
- for link in finder.find_links:
273
- args.extend(["--find-links", link])
274
-
275
- if finder.proxy:
276
- args.extend(["--proxy", finder.proxy])
277
- for host in finder.trusted_hosts:
278
- args.extend(["--trusted-host", host])
279
- if finder.custom_cert:
280
- args.extend(["--cert", finder.custom_cert])
281
- if finder.client_cert:
282
- args.extend(["--client-cert", finder.client_cert])
283
- if finder.allow_all_prereleases:
284
- args.append("--pre")
285
- if finder.prefer_binary:
286
- args.append("--prefer-binary")
287
- args.append("--")
288
- args.extend(requirements)
289
- with open_spinner(f"Installing {kind}") as spinner:
290
- call_subprocess(
291
- args,
292
- command_desc=f"pip subprocess to install {kind}",
293
- spinner=spinner,
294
- )
386
+ self.installer.install(requirements, prefix, kind=kind, for_req=for_req)
295
387
 
296
388
 
297
389
  class NoOpBuildEnvironment(BuildEnvironment):
@@ -305,9 +397,9 @@ class NoOpBuildEnvironment(BuildEnvironment):
305
397
 
306
398
  def __exit__(
307
399
  self,
308
- exc_type: Optional[Type[BaseException]],
309
- exc_val: Optional[BaseException],
310
- exc_tb: Optional[TracebackType],
400
+ exc_type: type[BaseException] | None,
401
+ exc_val: BaseException | None,
402
+ exc_tb: TracebackType | None,
311
403
  ) -> None:
312
404
  pass
313
405
 
@@ -316,10 +408,10 @@ class NoOpBuildEnvironment(BuildEnvironment):
316
408
 
317
409
  def install_requirements(
318
410
  self,
319
- finder: "PackageFinder",
320
411
  requirements: Iterable[str],
321
412
  prefix_as_string: str,
322
413
  *,
323
414
  kind: str,
415
+ for_req: InstallRequirement | None = None,
324
416
  ) -> None:
325
417
  raise NotImplementedError()
pip/_internal/cache.py CHANGED
@@ -1,11 +1,13 @@
1
1
  """Cache Management"""
2
2
 
3
+ from __future__ import annotations
4
+
3
5
  import hashlib
4
6
  import json
5
7
  import logging
6
8
  import os
7
9
  from pathlib import Path
8
- from typing import Any, Dict, List, Optional
10
+ from typing import Any
9
11
 
10
12
  from pip._vendor.packaging.tags import Tag, interpreter_name, interpreter_version
11
13
  from pip._vendor.packaging.utils import canonicalize_name
@@ -22,7 +24,7 @@ logger = logging.getLogger(__name__)
22
24
  ORIGIN_JSON_NAME = "origin.json"
23
25
 
24
26
 
25
- def _hash_dict(d: Dict[str, str]) -> str:
27
+ def _hash_dict(d: dict[str, str]) -> str:
26
28
  """Return a stable sha224 of a dictionary."""
27
29
  s = json.dumps(d, sort_keys=True, separators=(",", ":"), ensure_ascii=True)
28
30
  return hashlib.sha224(s.encode("ascii")).hexdigest()
@@ -39,7 +41,7 @@ class Cache:
39
41
  assert not cache_dir or os.path.isabs(cache_dir)
40
42
  self.cache_dir = cache_dir or None
41
43
 
42
- def _get_cache_path_parts(self, link: Link) -> List[str]:
44
+ def _get_cache_path_parts(self, link: Link) -> list[str]:
43
45
  """Get parts of part that must be os.path.joined with cache_dir"""
44
46
 
45
47
  # We want to generate an url to use as our cache key, we don't want to
@@ -72,7 +74,7 @@ class Cache:
72
74
 
73
75
  return parts
74
76
 
75
- def _get_candidates(self, link: Link, canonical_package_name: str) -> List[Any]:
77
+ def _get_candidates(self, link: Link, canonical_package_name: str) -> list[Any]:
76
78
  can_not_cache = not self.cache_dir or not canonical_package_name or not link
77
79
  if can_not_cache:
78
80
  return []
@@ -89,8 +91,8 @@ class Cache:
89
91
  def get(
90
92
  self,
91
93
  link: Link,
92
- package_name: Optional[str],
93
- supported_tags: List[Tag],
94
+ package_name: str | None,
95
+ supported_tags: list[Tag],
94
96
  ) -> Link:
95
97
  """Returns a link to a cached item if it exists, otherwise returns the
96
98
  passed link.
@@ -127,8 +129,8 @@ class SimpleWheelCache(Cache):
127
129
  def get(
128
130
  self,
129
131
  link: Link,
130
- package_name: Optional[str],
131
- supported_tags: List[Tag],
132
+ package_name: str | None,
133
+ supported_tags: list[Tag],
132
134
  ) -> Link:
133
135
  candidates = []
134
136
 
@@ -141,7 +143,7 @@ class SimpleWheelCache(Cache):
141
143
  wheel = Wheel(wheel_name)
142
144
  except InvalidWheelFilename:
143
145
  continue
144
- if canonicalize_name(wheel.name) != canonical_package_name:
146
+ if wheel.name != canonical_package_name:
145
147
  logger.debug(
146
148
  "Ignoring cached wheel %s for %s as it "
147
149
  "does not match the expected distribution name %s.",
@@ -188,7 +190,7 @@ class CacheEntry:
188
190
  ):
189
191
  self.link = link
190
192
  self.persistent = persistent
191
- self.origin: Optional[DirectUrl] = None
193
+ self.origin: DirectUrl | None = None
192
194
  origin_direct_url_path = Path(self.link.file_path).parent / ORIGIN_JSON_NAME
193
195
  if origin_direct_url_path.exists():
194
196
  try:
@@ -225,8 +227,8 @@ class WheelCache(Cache):
225
227
  def get(
226
228
  self,
227
229
  link: Link,
228
- package_name: Optional[str],
229
- supported_tags: List[Tag],
230
+ package_name: str | None,
231
+ supported_tags: list[Tag],
230
232
  ) -> Link:
231
233
  cache_entry = self.get_cache_entry(link, package_name, supported_tags)
232
234
  if cache_entry is None:
@@ -236,9 +238,9 @@ class WheelCache(Cache):
236
238
  def get_cache_entry(
237
239
  self,
238
240
  link: Link,
239
- package_name: Optional[str],
240
- supported_tags: List[Tag],
241
- ) -> Optional[CacheEntry]:
241
+ package_name: str | None,
242
+ supported_tags: list[Tag],
243
+ ) -> CacheEntry | None:
242
244
  """Returns a CacheEntry with a link to a cached item if it exists or
243
245
  None. The cache entry indicates if the item was found in the persistent
244
246
  or ephemeral cache.
@@ -1,10 +1,13 @@
1
1
  """Logic that powers autocompletion installed by ``pip completion``."""
2
2
 
3
+ from __future__ import annotations
4
+
3
5
  import optparse
4
6
  import os
5
7
  import sys
8
+ from collections.abc import Iterable
6
9
  from itertools import chain
7
- from typing import Any, Iterable, List, Optional
10
+ from typing import Any
8
11
 
9
12
  from pip._internal.cli.main_parser import create_main_parser
10
13
  from pip._internal.commands import commands_dict, create_command
@@ -32,7 +35,7 @@ def autocomplete() -> None:
32
35
  options = []
33
36
 
34
37
  # subcommand
35
- subcommand_name: Optional[str] = None
38
+ subcommand_name: str | None = None
36
39
  for word in cwords:
37
40
  if word in subcommands:
38
41
  subcommand_name = word
@@ -100,6 +103,12 @@ def autocomplete() -> None:
100
103
  if option[1] and option[0][:2] == "--":
101
104
  opt_label += "="
102
105
  print(opt_label)
106
+
107
+ # Complete sub-commands (unless one is already given).
108
+ if not any(name in cwords for name in subcommand.handler_map()):
109
+ for handler_name in subcommand.handler_map():
110
+ if handler_name.startswith(current):
111
+ print(handler_name)
103
112
  else:
104
113
  # show main parser options only when necessary
105
114
 
@@ -121,8 +130,8 @@ def autocomplete() -> None:
121
130
 
122
131
 
123
132
  def get_path_completion_type(
124
- cwords: List[str], cword: int, opts: Iterable[Any]
125
- ) -> Optional[str]:
133
+ cwords: list[str], cword: int, opts: Iterable[Any]
134
+ ) -> str | None:
126
135
  """Get the type of path completion (``file``, ``dir``, ``path`` or None)
127
136
 
128
137
  :param cwords: same as the environmental variable ``COMP_WORDS``
@@ -1,5 +1,7 @@
1
1
  """Base Command class, and related routines"""
2
2
 
3
+ from __future__ import annotations
4
+
3
5
  import logging
4
6
  import logging.config
5
7
  import optparse
@@ -7,7 +9,7 @@ import os
7
9
  import sys
8
10
  import traceback
9
11
  from optparse import Values
10
- from typing import List, Optional, Tuple
12
+ from typing import Callable
11
13
 
12
14
  from pip._vendor.rich import reconfigure
13
15
  from pip._vendor.rich import traceback as rich_traceback
@@ -60,7 +62,7 @@ class Command(CommandContextMixIn):
60
62
  isolated=isolated,
61
63
  )
62
64
 
63
- self.tempdir_registry: Optional[TempDirRegistry] = None
65
+ self.tempdir_registry: TempDirRegistry | None = None
64
66
 
65
67
  # Commands should add options to this option group
66
68
  optgroup_name = f"{self.name.capitalize()} Options"
@@ -87,10 +89,10 @@ class Command(CommandContextMixIn):
87
89
  # are present.
88
90
  assert not hasattr(options, "no_index")
89
91
 
90
- def run(self, options: Values, args: List[str]) -> int:
92
+ def run(self, options: Values, args: list[str]) -> int:
91
93
  raise NotImplementedError
92
94
 
93
- def _run_wrapper(self, level_number: int, options: Values, args: List[str]) -> int:
95
+ def _run_wrapper(self, level_number: int, options: Values, args: list[str]) -> int:
94
96
  def _inner_run() -> int:
95
97
  try:
96
98
  return self.run(options, args)
@@ -147,18 +149,18 @@ class Command(CommandContextMixIn):
147
149
 
148
150
  return UNKNOWN_ERROR
149
151
 
150
- def parse_args(self, args: List[str]) -> Tuple[Values, List[str]]:
152
+ def parse_args(self, args: list[str]) -> tuple[Values, list[str]]:
151
153
  # factored out for testability
152
154
  return self.parser.parse_args(args)
153
155
 
154
- def main(self, args: List[str]) -> int:
156
+ def main(self, args: list[str]) -> int:
155
157
  try:
156
158
  with self.main_context():
157
159
  return self._main(args)
158
160
  finally:
159
161
  logging.shutdown()
160
162
 
161
- def _main(self, args: List[str]) -> int:
163
+ def _main(self, args: list[str]) -> int:
162
164
  # We must initialize this before the tempdir manager, otherwise the
163
165
  # configuration would not be accessible by the time we clean up the
164
166
  # tempdir manager.
@@ -174,6 +176,9 @@ class Command(CommandContextMixIn):
174
176
  if options.debug_mode:
175
177
  self.verbosity = 2
176
178
 
179
+ if hasattr(options, "progress_bar") and options.progress_bar == "auto":
180
+ options.progress_bar = "on" if self.verbosity >= 0 else "off"
181
+
177
182
  reconfigure(no_color=options.no_color)
178
183
  level_number = setup_logging(
179
184
  verbosity=self.verbosity,
@@ -231,3 +236,9 @@ class Command(CommandContextMixIn):
231
236
  options.cache_dir = None
232
237
 
233
238
  return self._run_wrapper(level_number, options, args)
239
+
240
+ def handler_map(self) -> dict[str, Callable[[Values, list[str]], None]]:
241
+ """
242
+ map of names to handler actions for commands with sub-actions
243
+ """
244
+ return {}