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
@@ -83,7 +83,7 @@ def is_within_directory(directory: str, target: str) -> bool:
83
83
  abs_directory = os.path.abspath(directory)
84
84
  abs_target = os.path.abspath(target)
85
85
 
86
- prefix = os.path.commonprefix([abs_directory, abs_target])
86
+ prefix = os.path.commonpath([abs_directory, abs_target])
87
87
  return prefix == abs_directory
88
88
 
89
89
 
@@ -248,6 +248,20 @@ def untar_file(filename: str, location: str) -> None:
248
248
  tar.close()
249
249
 
250
250
 
251
+ def is_symlink_target_in_tar(tar: tarfile.TarFile, tarinfo: tarfile.TarInfo) -> bool:
252
+ """Check if the file pointed to by the symbolic link is in the tar archive"""
253
+ linkname = os.path.join(os.path.dirname(tarinfo.name), tarinfo.linkname)
254
+
255
+ linkname = os.path.normpath(linkname)
256
+ linkname = linkname.replace("\\", "/")
257
+
258
+ try:
259
+ tar.getmember(linkname)
260
+ return True
261
+ except KeyError:
262
+ return False
263
+
264
+
251
265
  def _untar_without_filter(
252
266
  filename: str,
253
267
  location: str,
@@ -255,6 +269,9 @@ def _untar_without_filter(
255
269
  leading: bool,
256
270
  ) -> None:
257
271
  """Fallback for Python without tarfile.data_filter"""
272
+ # NOTE: This function can be removed once pip requires CPython ≥ 3.12.​
273
+ # PEP 706 added tarfile.data_filter, made tarfile extraction operations more secure.
274
+ # This feature is fully supported from CPython 3.12 onward.
258
275
  for member in tar.getmembers():
259
276
  fn = member.name
260
277
  if leading:
@@ -269,6 +286,14 @@ def _untar_without_filter(
269
286
  if member.isdir():
270
287
  ensure_dir(path)
271
288
  elif member.issym():
289
+ if not is_symlink_target_in_tar(tar, member):
290
+ message = (
291
+ "The tar file ({}) has a file ({}) trying to install "
292
+ "outside target directory ({})"
293
+ )
294
+ raise InstallationError(
295
+ message.format(filename, member.name, member.linkname)
296
+ )
272
297
  try:
273
298
  tar._extract_member(member, path)
274
299
  except Exception as exc:
@@ -62,8 +62,9 @@ def make_vcs_requirement_url(
62
62
  repo_url: the remote VCS url, with any needed VCS prefix (e.g. "git+").
63
63
  project_name: the (unescaped) project name.
64
64
  """
65
+ quoted_rev = urllib.parse.quote(rev, "/")
65
66
  egg_project_name = project_name.replace("-", "_")
66
- req = f"{repo_url}@{rev}#egg={egg_project_name}"
67
+ req = f"{repo_url}@{quoted_rev}#egg={egg_project_name}"
67
68
  if subdir:
68
69
  req += f"&subdirectory={subdir}"
69
70
 
@@ -397,6 +398,7 @@ class VersionControl:
397
398
  "which is not supported. Include a revision after @ "
398
399
  "or remove @ from the URL."
399
400
  )
401
+ rev = urllib.parse.unquote(rev)
400
402
  url = urllib.parse.urlunsplit((scheme, netloc, path, query, ""))
401
403
  return url, rev, user_pass
402
404
 
@@ -5,8 +5,8 @@ from __future__ import annotations
5
5
  import logging
6
6
  import os.path
7
7
  import re
8
- import shutil
9
8
  from collections.abc import Iterable
9
+ from tempfile import TemporaryDirectory
10
10
 
11
11
  from pip._vendor.packaging.utils import canonicalize_name, canonicalize_version
12
12
  from pip._vendor.packaging.version import InvalidVersion, Version
@@ -18,13 +18,9 @@ from pip._internal.models.link import Link
18
18
  from pip._internal.models.wheel import Wheel
19
19
  from pip._internal.operations.build.wheel import build_wheel_pep517
20
20
  from pip._internal.operations.build.wheel_editable import build_wheel_editable
21
- from pip._internal.operations.build.wheel_legacy import build_wheel_legacy
22
21
  from pip._internal.req.req_install import InstallRequirement
23
22
  from pip._internal.utils.logging import indent_log
24
23
  from pip._internal.utils.misc import ensure_dir, hash_file
25
- from pip._internal.utils.setuptools_build import make_setuptools_clean_args
26
- from pip._internal.utils.subprocess import call_subprocess
27
- from pip._internal.utils.temp_dir import TempDirectory
28
24
  from pip._internal.utils.urls import path_to_url
29
25
  from pip._internal.vcs import vcs
30
26
 
@@ -43,37 +39,12 @@ def _contains_egg_info(s: str) -> bool:
43
39
  return bool(_egg_info_re.search(s))
44
40
 
45
41
 
46
- def _should_build(
47
- req: InstallRequirement,
48
- ) -> bool:
49
- """Return whether an InstallRequirement should be built into a wheel."""
50
- assert not req.constraint
51
-
52
- if req.is_wheel:
53
- return False
54
-
55
- assert req.source_dir
56
-
57
- if req.editable:
58
- # we only build PEP 660 editable requirements
59
- return req.supports_pyproject_editable
60
-
61
- return True
62
-
63
-
64
- def should_build_for_install_command(
65
- req: InstallRequirement,
66
- ) -> bool:
67
- return _should_build(req)
68
-
69
-
70
42
  def _should_cache(
71
43
  req: InstallRequirement,
72
44
  ) -> bool | None:
73
45
  """
74
46
  Return whether a built InstallRequirement can be stored in the persistent
75
- wheel cache, assuming the wheel cache is available, and _should_build()
76
- has determined a wheel needs to be built.
47
+ wheel cache, assuming the wheel cache is available.
77
48
  """
78
49
  if req.editable or not req.source_dir:
79
50
  # never cache editable requirements
@@ -118,7 +89,7 @@ def _get_cache_dir(
118
89
  def _verify_one(req: InstallRequirement, wheel_path: str) -> None:
119
90
  canonical_name = canonicalize_name(req.name or "")
120
91
  w = Wheel(os.path.basename(wheel_path))
121
- if canonicalize_name(w.name) != canonical_name:
92
+ if w.name != canonical_name:
122
93
  raise InvalidWheelFilename(
123
94
  f"Wheel has unexpected file name: expected {canonical_name!r}, "
124
95
  f"got {w.name!r}",
@@ -148,8 +119,6 @@ def _build_one(
148
119
  req: InstallRequirement,
149
120
  output_dir: str,
150
121
  verify: bool,
151
- build_options: list[str],
152
- global_options: list[str],
153
122
  editable: bool,
154
123
  ) -> str | None:
155
124
  """Build one wheel.
@@ -170,9 +139,7 @@ def _build_one(
170
139
 
171
140
  # Install build deps into temporary directory (PEP 518)
172
141
  with req.build_env:
173
- wheel_path = _build_one_inside_env(
174
- req, output_dir, build_options, global_options, editable
175
- )
142
+ wheel_path = _build_one_inside_env(req, output_dir, editable)
176
143
  if wheel_path and verify:
177
144
  try:
178
145
  _verify_one(req, wheel_path)
@@ -185,45 +152,25 @@ def _build_one(
185
152
  def _build_one_inside_env(
186
153
  req: InstallRequirement,
187
154
  output_dir: str,
188
- build_options: list[str],
189
- global_options: list[str],
190
155
  editable: bool,
191
156
  ) -> str | None:
192
- with TempDirectory(kind="wheel") as temp_dir:
157
+ with TemporaryDirectory(dir=output_dir) as wheel_directory:
193
158
  assert req.name
194
- if req.use_pep517:
195
- assert req.metadata_directory
196
- assert req.pep517_backend
197
- if global_options:
198
- logger.warning(
199
- "Ignoring --global-option when building %s using PEP 517", req.name
200
- )
201
- if build_options:
202
- logger.warning(
203
- "Ignoring --build-option when building %s using PEP 517", req.name
204
- )
205
- if editable:
206
- wheel_path = build_wheel_editable(
207
- name=req.name,
208
- backend=req.pep517_backend,
209
- metadata_directory=req.metadata_directory,
210
- tempd=temp_dir.path,
211
- )
212
- else:
213
- wheel_path = build_wheel_pep517(
214
- name=req.name,
215
- backend=req.pep517_backend,
216
- metadata_directory=req.metadata_directory,
217
- tempd=temp_dir.path,
218
- )
159
+ assert req.metadata_directory
160
+ assert req.pep517_backend
161
+ if editable:
162
+ wheel_path = build_wheel_editable(
163
+ name=req.name,
164
+ backend=req.pep517_backend,
165
+ metadata_directory=req.metadata_directory,
166
+ wheel_directory=wheel_directory,
167
+ )
219
168
  else:
220
- wheel_path = build_wheel_legacy(
169
+ wheel_path = build_wheel_pep517(
221
170
  name=req.name,
222
- setup_py_path=req.setup_py_path,
223
- source_dir=req.unpacked_source_directory,
224
- global_options=global_options,
225
- build_options=build_options,
226
- tempd=temp_dir.path,
171
+ backend=req.pep517_backend,
172
+ metadata_directory=req.metadata_directory,
173
+ wheel_directory=wheel_directory,
227
174
  )
228
175
 
229
176
  if wheel_path is not None:
@@ -231,7 +178,11 @@ def _build_one_inside_env(
231
178
  dest_path = os.path.join(output_dir, wheel_name)
232
179
  try:
233
180
  wheel_hash, length = hash_file(wheel_path)
234
- shutil.move(wheel_path, dest_path)
181
+ # We can do a replace here because wheel_path is guaranteed to
182
+ # be in the same filesystem as output_dir. This will perform an
183
+ # atomic rename, which is necessary to avoid concurrency issues
184
+ # when populating the cache.
185
+ os.replace(wheel_path, dest_path)
235
186
  logger.info(
236
187
  "Created wheel for %s: filename=%s size=%d sha256=%s",
237
188
  req.name,
@@ -247,35 +198,13 @@ def _build_one_inside_env(
247
198
  req.name,
248
199
  e,
249
200
  )
250
- # Ignore return, we can't do anything else useful.
251
- if not req.use_pep517:
252
- _clean_one_legacy(req, global_options)
253
201
  return None
254
202
 
255
203
 
256
- def _clean_one_legacy(req: InstallRequirement, global_options: list[str]) -> bool:
257
- clean_args = make_setuptools_clean_args(
258
- req.setup_py_path,
259
- global_options=global_options,
260
- )
261
-
262
- logger.info("Running setup.py clean for %s", req.name)
263
- try:
264
- call_subprocess(
265
- clean_args, command_desc="python setup.py clean", cwd=req.source_dir
266
- )
267
- return True
268
- except Exception:
269
- logger.error("Failed cleaning build dir for %s", req.name)
270
- return False
271
-
272
-
273
204
  def build(
274
205
  requirements: Iterable[InstallRequirement],
275
206
  wheel_cache: WheelCache,
276
207
  verify: bool,
277
- build_options: list[str],
278
- global_options: list[str],
279
208
  ) -> BuildResult:
280
209
  """Build wheels.
281
210
 
@@ -300,8 +229,6 @@ def build(
300
229
  req,
301
230
  cache_dir,
302
231
  verify,
303
- build_options,
304
- global_options,
305
232
  req.editable and req.permit_editable_wheels,
306
233
  )
307
234
  if wheel_file:
pip/_vendor/README.rst ADDED
@@ -0,0 +1,180 @@
1
+ ================
2
+ Vendoring Policy
3
+ ================
4
+
5
+ * Vendored libraries **MUST** not be modified except as required to
6
+ successfully vendor them.
7
+ * Vendored libraries **MUST** be released copies of libraries available on
8
+ PyPI.
9
+ * Vendored libraries **MUST** be available under a license that allows
10
+ them to be integrated into ``pip``, which is released under the MIT license.
11
+ * Vendored libraries **MUST** be accompanied with LICENSE files.
12
+ * The versions of libraries vendored in pip **MUST** be reflected in
13
+ ``pip/_vendor/vendor.txt``.
14
+ * Vendored libraries **MUST** function without any build steps such as ``2to3``
15
+ or compilation of C code, practically this limits to single source 2.x/3.x and
16
+ pure Python.
17
+ * Any modifications made to libraries **MUST** be noted in
18
+ ``pip/_vendor/README.rst`` and their corresponding patches **MUST** be
19
+ included ``tools/vendoring/patches``.
20
+ * Vendored libraries should have corresponding ``vendored()`` entries in
21
+ ``pip/_vendor/__init__.py``.
22
+
23
+ Rationale
24
+ =========
25
+
26
+ Historically pip has not had any dependencies except for ``setuptools`` itself,
27
+ choosing instead to implement any functionality it needed to prevent needing
28
+ a dependency. However, starting with pip 1.5, we began to replace code that was
29
+ implemented inside of pip with reusable libraries from PyPI. This brought the
30
+ typical benefits of reusing libraries instead of reinventing the wheel like
31
+ higher quality and more battle tested code, centralization of bug fixes
32
+ (particularly security sensitive ones), and better/more features for less work.
33
+
34
+ However, there are several issues with having dependencies in the traditional
35
+ way (via ``install_requires``) for pip. These issues are:
36
+
37
+ **Fragility**
38
+ When pip depends on another library to function then if for whatever reason
39
+ that library either isn't installed or an incompatible version is installed
40
+ then pip ceases to function. This is of course true for all Python
41
+ applications, however for every application *except* for pip the way you fix
42
+ it is by re-running pip. Obviously, when pip can't run, you can't use pip to
43
+ fix pip, so you're left having to manually resolve dependencies and
44
+ installing them by hand.
45
+
46
+ **Making other libraries uninstallable**
47
+ One of pip's current dependencies is the ``requests`` library, for which pip
48
+ requires a fairly recent version to run. If pip depended on ``requests`` in
49
+ the traditional manner, then we'd either have to maintain compatibility with
50
+ every ``requests`` version that has ever existed (and ever will), OR allow
51
+ pip to render certain versions of ``requests`` uninstallable. (The second
52
+ issue, although technically true for any Python application, is magnified by
53
+ pip's ubiquity; pip is installed by default in Python, in ``pyvenv``, and in
54
+ ``virtualenv``.)
55
+
56
+ **Security**
57
+ This might seem puzzling at first glance, since vendoring has a tendency to
58
+ complicate updating dependencies for security updates, and that holds true
59
+ for pip. However, given the *other* reasons for avoiding dependencies, the
60
+ alternative is for pip to reinvent the wheel itself. This is what pip did
61
+ historically. It forced pip to re-implement its own HTTPS verification
62
+ routines as a workaround for the Python standard library's lack of SSL
63
+ validation, which resulted in similar bugs in the validation routine in
64
+ ``requests`` and ``urllib3``, except that they had to be discovered and
65
+ fixed independently. Even though we're vendoring, reusing libraries keeps
66
+ pip more secure by relying on the great work of our dependencies, *and*
67
+ allowing for faster, easier security fixes by simply pulling in newer
68
+ versions of dependencies.
69
+
70
+ **Bootstrapping**
71
+ Currently most popular methods of installing pip rely on pip's
72
+ self-contained nature to install pip itself. These tools work by bundling a
73
+ copy of pip, adding it to ``sys.path``, and then executing that copy of pip.
74
+ This is done instead of implementing a "mini installer" (to reduce
75
+ duplication); pip already knows how to install a Python package, and is far
76
+ more battle-tested than any "mini installer" could ever possibly be.
77
+
78
+ Many downstream redistributors have policies against this kind of bundling, and
79
+ instead opt to patch the software they distribute to debundle it and make it
80
+ rely on the global versions of the software that they already have packaged
81
+ (which may have its own patches applied to it). We (the pip team) would prefer
82
+ it if pip was *not* debundled in this manner due to the above reasons and
83
+ instead we would prefer it if pip would be left intact as it is now.
84
+
85
+ In the longer term, if someone has a *portable* solution to the above problems,
86
+ other than the bundling method we currently use, that doesn't add additional
87
+ problems that are unreasonable then we would be happy to consider, and possibly
88
+ switch to said method. This solution must function correctly across all of the
89
+ situation that we expect pip to be used and not mandate some external mechanism
90
+ such as OS packages.
91
+
92
+
93
+ Modifications
94
+ =============
95
+
96
+ * ``setuptools`` is completely stripped to only keep ``pkg_resources``.
97
+ * ``pkg_resources`` has been modified to import its dependencies from
98
+ ``pip._vendor``, and to use the vendored copy of ``platformdirs``
99
+ rather than ``appdirs``.
100
+ * ``packaging`` has been modified to import its dependencies from
101
+ ``pip._vendor``.
102
+ * ``CacheControl`` has been modified to import its dependencies from
103
+ ``pip._vendor``.
104
+ * ``requests`` has been modified to import its other dependencies from
105
+ ``pip._vendor`` and to *not* load ``simplejson`` (all platforms) and
106
+ ``pyopenssl`` (Windows).
107
+ * ``platformdirs`` has been modified to import its submodules from ``pip._vendor.platformdirs``.
108
+
109
+ Automatic Vendoring
110
+ ===================
111
+
112
+ Vendoring is automated via the `vendoring <https://pypi.org/project/vendoring/>`_ tool from the content of
113
+ ``pip/_vendor/vendor.txt`` and the different patches in
114
+ ``tools/vendoring/patches``.
115
+ Launch it via ``vendoring sync . -v`` (requires ``vendoring>=0.2.2``).
116
+ Tool configuration is done via ``pyproject.toml``.
117
+
118
+ To update the vendored library versions, we have a session defined in ``nox``.
119
+ The command to upgrade everything is::
120
+
121
+ nox -s vendoring -- --upgrade-all --skip urllib3 --skip setuptools
122
+
123
+ At the time of writing (April 2025) we do not upgrade ``urllib3`` because the
124
+ next version is a major upgrade and will be handled as an independent PR. We also
125
+ do not upgrade ``setuptools``, because we only rely on ``pkg_resources``, and
126
+ tracking every ``setuptools`` change is unnecessary for our needs.
127
+
128
+
129
+ Managing Local Patches
130
+ ======================
131
+
132
+ The ``vendoring`` tool automatically applies our local patches, but updating,
133
+ the patches sometimes no longer apply cleanly. In that case, the update will
134
+ fail. To resolve this, take the following steps:
135
+
136
+ 1. Revert any incomplete changes in the revendoring branch, to ensure you have
137
+ a clean starting point.
138
+ 2. Run the revendoring of the library with a problem again: ``nox -s vendoring
139
+ -- --upgrade <library_name>``.
140
+ 3. This will fail again, but you will have the original source in your working
141
+ directory. Review the existing patch against the source, and modify the patch
142
+ to reflect the new version of the source. If you ``git add`` the changes the
143
+ vendoring made, you can modify the source to reflect the patch file and then
144
+ generate a new patch with ``git diff``.
145
+ 4. Now, revert everything *except* the patch file changes. Leave the modified
146
+ patch file unstaged but saved in the working tree.
147
+ 5. Re-run the vendoring. This time, it should pick up the changed patch file
148
+ and apply it cleanly. The patch file changes will be committed along with the
149
+ revendoring, so the new commit should be ready to test and publish as a PR.
150
+
151
+
152
+ Debundling
153
+ ==========
154
+
155
+ As mentioned in the rationale, we, the pip team, would prefer it if pip was not
156
+ debundled (other than optionally ``pip/_vendor/requests/cacert.pem``) and that
157
+ pip was left intact. However, if you insist on doing so, we have a
158
+ semi-supported method (that we don't test in our CI) and requires a bit of
159
+ extra work on your end in order to solve the problems described above.
160
+
161
+ 1. Delete everything in ``pip/_vendor/`` **except** for
162
+ ``pip/_vendor/__init__.py`` and ``pip/_vendor/vendor.txt``.
163
+ 2. Generate wheels for each of pip's dependencies (and any of their
164
+ dependencies) using your patched copies of these libraries. These must be
165
+ placed somewhere on the filesystem that pip can access (``pip/_vendor`` is
166
+ the default assumption).
167
+ 3. Modify ``pip/_vendor/__init__.py`` so that the ``DEBUNDLED`` variable is
168
+ ``True``.
169
+ 4. Upon installation, the ``INSTALLER`` file in pip's own ``dist-info``
170
+ directory should be set to something other than ``pip``, so that pip
171
+ can detect that it wasn't installed using itself.
172
+ 5. *(optional)* If you've placed the wheels in a location other than
173
+ ``pip/_vendor/``, then modify ``pip/_vendor/__init__.py`` so that the
174
+ ``WHEEL_DIR`` variable points to the location you've placed them.
175
+ 6. *(optional)* Update the ``pip_self_version_check`` logic to use the
176
+ appropriate logic for determining the latest available version of pip and
177
+ prompt the user with the correct upgrade message.
178
+
179
+ Note that partial debundling is **NOT** supported. You need to prepare wheels
180
+ for all dependencies for successful debundling.
@@ -0,0 +1,13 @@
1
+ Copyright 2012-2021 Eric Larson
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
@@ -7,14 +7,17 @@
7
7
  Make it easy to import from cachecontrol without long namespaces.
8
8
  """
9
9
 
10
- __author__ = "Eric Larson"
11
- __email__ = "eric@ionrock.org"
12
- __version__ = "0.14.3"
10
+ import importlib.metadata
13
11
 
14
12
  from pip._vendor.cachecontrol.adapter import CacheControlAdapter
15
13
  from pip._vendor.cachecontrol.controller import CacheController
16
14
  from pip._vendor.cachecontrol.wrapper import CacheControl
17
15
 
16
+ __author__ = "Eric Larson"
17
+ __email__ = "eric@ionrock.org"
18
+ # pip patch: this won't work when vendored, so just patch it out as it's unused
19
+ # __version__ = importlib.metadata.version("cachecontrol")
20
+
18
21
  __all__ = [
19
22
  "__author__",
20
23
  "__email__",
@@ -4,7 +4,6 @@
4
4
  from __future__ import annotations
5
5
 
6
6
  import functools
7
- import types
8
7
  import weakref
9
8
  import zlib
10
9
  from typing import TYPE_CHECKING, Any, Collection, Mapping
@@ -490,7 +490,7 @@ class CacheController:
490
490
  #
491
491
  # The server isn't supposed to send headers that would make
492
492
  # the cached body invalid. But... just in case, we'll be sure
493
- # to strip out ones we know that might be problmatic due to
493
+ # to strip out ones we know that might be problematic due to
494
494
  # typical assumptions.
495
495
  excluded_headers = ["content-length"]
496
496
 
@@ -8,6 +8,7 @@ from tempfile import NamedTemporaryFile
8
8
  from typing import TYPE_CHECKING, Any, Callable
9
9
 
10
10
  if TYPE_CHECKING:
11
+ from collections.abc import Buffer
11
12
  from http.client import HTTPResponse
12
13
 
13
14
 
@@ -31,7 +32,7 @@ class CallbackFileWrapper:
31
32
  """
32
33
 
33
34
  def __init__(
34
- self, fp: HTTPResponse, callback: Callable[[bytes], None] | None
35
+ self, fp: HTTPResponse, callback: Callable[[Buffer], None] | None
35
36
  ) -> None:
36
37
  self.__buf = NamedTemporaryFile("rb+", delete=True)
37
38
  self.__fp = fp
@@ -68,6 +69,7 @@ class CallbackFileWrapper:
68
69
  return False
69
70
 
70
71
  def _close(self) -> None:
72
+ result: Buffer
71
73
  if self.__callback:
72
74
  if self.__buf.tell() == 0:
73
75
  # Empty file:
@@ -0,0 +1,20 @@
1
+ This package contains a modified version of ca-bundle.crt:
2
+
3
+ ca-bundle.crt -- Bundle of CA Root Certificates
4
+
5
+ This is a bundle of X.509 certificates of public Certificate Authorities
6
+ (CA). These were automatically extracted from Mozilla's root certificates
7
+ file (certdata.txt). This file can be found in the mozilla source tree:
8
+ https://hg.mozilla.org/mozilla-central/file/tip/security/nss/lib/ckfw/builtins/certdata.txt
9
+ It contains the certificates in PEM format and therefore
10
+ can be directly used with curl / libcurl / php_curl, or with
11
+ an Apache+mod_ssl webserver for SSL client authentication.
12
+ Just configure this file as the SSLCACertificateFile.#
13
+
14
+ ***** BEGIN LICENSE BLOCK *****
15
+ This Source Code Form is subject to the terms of the Mozilla Public License,
16
+ v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain
17
+ one at http://mozilla.org/MPL/2.0/.
18
+
19
+ ***** END LICENSE BLOCK *****
20
+ @(#) $RCSfile: certdata.txt,v $ $Revision: 1.80 $ $Date: 2011/11/03 15:11:58 $
@@ -1,4 +1,4 @@
1
1
  from .core import contents, where
2
2
 
3
3
  __all__ = ["contents", "where"]
4
- __version__ = "2025.07.14"
4
+ __version__ = "2026.01.04"