pip 25.1__py3-none-any.whl → 25.2__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.
- pip/__init__.py +3 -3
- pip/_internal/__init__.py +2 -2
- pip/_internal/build_env.py +118 -94
- pip/_internal/cache.py +16 -14
- pip/_internal/cli/autocompletion.py +13 -4
- pip/_internal/cli/base_command.py +18 -7
- pip/_internal/cli/cmdoptions.py +14 -9
- pip/_internal/cli/command_context.py +4 -3
- pip/_internal/cli/index_command.py +11 -9
- pip/_internal/cli/main.py +3 -2
- pip/_internal/cli/main_parser.py +4 -3
- pip/_internal/cli/parser.py +26 -22
- pip/_internal/cli/progress_bars.py +19 -12
- pip/_internal/cli/req_command.py +16 -12
- pip/_internal/cli/spinners.py +81 -5
- pip/_internal/commands/__init__.py +5 -3
- pip/_internal/commands/cache.py +18 -15
- pip/_internal/commands/check.py +1 -2
- pip/_internal/commands/completion.py +1 -2
- pip/_internal/commands/configuration.py +26 -18
- pip/_internal/commands/debug.py +8 -6
- pip/_internal/commands/download.py +2 -3
- pip/_internal/commands/freeze.py +2 -3
- pip/_internal/commands/hash.py +1 -2
- pip/_internal/commands/help.py +1 -2
- pip/_internal/commands/index.py +15 -9
- pip/_internal/commands/inspect.py +4 -4
- pip/_internal/commands/install.py +45 -40
- pip/_internal/commands/list.py +35 -26
- pip/_internal/commands/lock.py +1 -2
- pip/_internal/commands/search.py +14 -12
- pip/_internal/commands/show.py +14 -11
- pip/_internal/commands/uninstall.py +1 -2
- pip/_internal/commands/wheel.py +2 -3
- pip/_internal/configuration.py +39 -25
- pip/_internal/distributions/base.py +6 -4
- pip/_internal/distributions/installed.py +8 -4
- pip/_internal/distributions/sdist.py +20 -13
- pip/_internal/distributions/wheel.py +6 -4
- pip/_internal/exceptions.py +58 -39
- pip/_internal/index/collector.py +24 -29
- pip/_internal/index/package_finder.py +70 -61
- pip/_internal/index/sources.py +17 -14
- pip/_internal/locations/__init__.py +18 -16
- pip/_internal/locations/_distutils.py +12 -11
- pip/_internal/locations/_sysconfig.py +5 -4
- pip/_internal/locations/base.py +4 -3
- pip/_internal/main.py +2 -2
- pip/_internal/metadata/__init__.py +8 -6
- pip/_internal/metadata/_json.py +5 -4
- pip/_internal/metadata/base.py +22 -27
- pip/_internal/metadata/importlib/_compat.py +6 -4
- pip/_internal/metadata/importlib/_dists.py +12 -17
- pip/_internal/metadata/importlib/_envs.py +9 -6
- pip/_internal/metadata/pkg_resources.py +11 -14
- pip/_internal/models/direct_url.py +24 -21
- pip/_internal/models/format_control.py +5 -5
- pip/_internal/models/installation_report.py +4 -3
- pip/_internal/models/link.py +39 -34
- pip/_internal/models/pylock.py +27 -22
- pip/_internal/models/search_scope.py +6 -7
- pip/_internal/models/selection_prefs.py +3 -3
- pip/_internal/models/target_python.py +10 -9
- pip/_internal/models/wheel.py +7 -5
- pip/_internal/network/auth.py +20 -22
- pip/_internal/network/cache.py +22 -6
- pip/_internal/network/download.py +169 -141
- pip/_internal/network/lazy_wheel.py +10 -7
- pip/_internal/network/session.py +32 -27
- pip/_internal/network/utils.py +2 -2
- pip/_internal/network/xmlrpc.py +2 -2
- pip/_internal/operations/build/build_tracker.py +10 -8
- pip/_internal/operations/build/wheel.py +3 -2
- pip/_internal/operations/build/wheel_editable.py +3 -2
- pip/_internal/operations/build/wheel_legacy.py +9 -8
- pip/_internal/operations/check.py +21 -26
- pip/_internal/operations/freeze.py +12 -9
- pip/_internal/operations/install/editable_legacy.py +5 -3
- pip/_internal/operations/install/wheel.py +53 -44
- pip/_internal/operations/prepare.py +35 -30
- pip/_internal/pyproject.py +7 -10
- pip/_internal/req/__init__.py +12 -10
- pip/_internal/req/constructors.py +33 -31
- pip/_internal/req/req_dependency_group.py +9 -8
- pip/_internal/req/req_file.py +32 -35
- pip/_internal/req/req_install.py +37 -34
- pip/_internal/req/req_set.py +4 -5
- pip/_internal/req/req_uninstall.py +20 -17
- pip/_internal/resolution/base.py +3 -3
- pip/_internal/resolution/legacy/resolver.py +21 -20
- pip/_internal/resolution/resolvelib/base.py +16 -13
- pip/_internal/resolution/resolvelib/candidates.py +29 -26
- pip/_internal/resolution/resolvelib/factory.py +41 -50
- pip/_internal/resolution/resolvelib/found_candidates.py +11 -9
- pip/_internal/resolution/resolvelib/provider.py +15 -20
- pip/_internal/resolution/resolvelib/reporter.py +5 -3
- pip/_internal/resolution/resolvelib/requirements.py +8 -6
- pip/_internal/resolution/resolvelib/resolver.py +39 -23
- pip/_internal/self_outdated_check.py +8 -6
- pip/_internal/utils/appdirs.py +1 -2
- pip/_internal/utils/compat.py +7 -1
- pip/_internal/utils/compatibility_tags.py +17 -16
- pip/_internal/utils/deprecation.py +11 -9
- pip/_internal/utils/direct_url_helpers.py +2 -2
- pip/_internal/utils/egg_link.py +6 -5
- pip/_internal/utils/entrypoints.py +3 -2
- pip/_internal/utils/filesystem.py +8 -5
- pip/_internal/utils/filetypes.py +4 -6
- pip/_internal/utils/glibc.py +6 -5
- pip/_internal/utils/hashes.py +9 -6
- pip/_internal/utils/logging.py +8 -5
- pip/_internal/utils/misc.py +54 -44
- pip/_internal/utils/packaging.py +3 -2
- pip/_internal/utils/retry.py +7 -4
- pip/_internal/utils/setuptools_build.py +12 -10
- pip/_internal/utils/subprocess.py +20 -17
- pip/_internal/utils/temp_dir.py +10 -12
- pip/_internal/utils/unpacking.py +6 -4
- pip/_internal/utils/urls.py +1 -1
- pip/_internal/utils/virtualenv.py +3 -2
- pip/_internal/utils/wheel.py +3 -4
- pip/_internal/vcs/bazaar.py +26 -8
- pip/_internal/vcs/git.py +59 -24
- pip/_internal/vcs/mercurial.py +34 -11
- pip/_internal/vcs/subversion.py +27 -16
- pip/_internal/vcs/versioncontrol.py +56 -51
- pip/_internal/wheel_builder.py +14 -12
- pip/_vendor/cachecontrol/__init__.py +1 -1
- pip/_vendor/certifi/__init__.py +1 -1
- pip/_vendor/certifi/cacert.pem +102 -221
- pip/_vendor/certifi/core.py +1 -32
- pip/_vendor/dependency_groups/_implementation.py +7 -11
- pip/_vendor/distlib/__init__.py +2 -2
- pip/_vendor/distlib/scripts.py +1 -1
- pip/_vendor/msgpack/__init__.py +2 -2
- pip/_vendor/pkg_resources/__init__.py +1 -1
- pip/_vendor/platformdirs/version.py +2 -2
- pip/_vendor/pygments/__init__.py +1 -1
- pip/_vendor/requests/__version__.py +2 -2
- pip/_vendor/requests/compat.py +12 -0
- pip/_vendor/requests/models.py +3 -1
- pip/_vendor/requests/utils.py +6 -16
- pip/_vendor/resolvelib/__init__.py +3 -3
- pip/_vendor/resolvelib/reporters.py +1 -1
- pip/_vendor/resolvelib/resolvers/__init__.py +4 -4
- pip/_vendor/resolvelib/resolvers/resolution.py +91 -10
- pip/_vendor/rich/__main__.py +12 -40
- pip/_vendor/rich/_inspect.py +1 -1
- pip/_vendor/rich/_ratio.py +1 -7
- pip/_vendor/rich/align.py +1 -7
- pip/_vendor/rich/box.py +1 -7
- pip/_vendor/rich/console.py +25 -20
- pip/_vendor/rich/control.py +1 -7
- pip/_vendor/rich/diagnose.py +1 -0
- pip/_vendor/rich/emoji.py +1 -6
- pip/_vendor/rich/live.py +32 -7
- pip/_vendor/rich/live_render.py +1 -7
- pip/_vendor/rich/logging.py +1 -1
- pip/_vendor/rich/panel.py +3 -4
- pip/_vendor/rich/progress.py +15 -15
- pip/_vendor/rich/spinner.py +7 -13
- pip/_vendor/rich/syntax.py +24 -5
- pip/_vendor/rich/traceback.py +32 -17
- pip/_vendor/truststore/_api.py +1 -1
- pip/_vendor/vendor.txt +10 -11
- {pip-25.1.dist-info → pip-25.2.dist-info}/METADATA +26 -4
- {pip-25.1.dist-info → pip-25.2.dist-info}/RECORD +194 -181
- {pip-25.1.dist-info → pip-25.2.dist-info}/WHEEL +1 -1
- {pip-25.1.dist-info → pip-25.2.dist-info}/licenses/AUTHORS.txt +12 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/cachecontrol/LICENSE.txt +13 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/certifi/LICENSE +20 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/dependency_groups/LICENSE.txt +9 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/distlib/LICENSE.txt +284 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/distro/LICENSE +202 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/idna/LICENSE.md +31 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/msgpack/COPYING +14 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/packaging/LICENSE +3 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/packaging/LICENSE.APACHE +177 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/packaging/LICENSE.BSD +23 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/pkg_resources/LICENSE +17 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/platformdirs/LICENSE +21 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/pygments/LICENSE +25 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/pyproject_hooks/LICENSE +21 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/requests/LICENSE +175 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/resolvelib/LICENSE +13 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/rich/LICENSE +19 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/tomli/LICENSE +21 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/tomli/LICENSE-HEADER +3 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/tomli_w/LICENSE +21 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/truststore/LICENSE +21 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/urllib3/LICENSE.txt +21 -0
- pip/_vendor/distlib/database.py +0 -1329
- pip/_vendor/distlib/index.py +0 -508
- pip/_vendor/distlib/locators.py +0 -1295
- pip/_vendor/distlib/manifest.py +0 -384
- pip/_vendor/distlib/markers.py +0 -162
- pip/_vendor/distlib/metadata.py +0 -1031
- pip/_vendor/distlib/version.py +0 -750
- pip/_vendor/distlib/wheel.py +0 -1100
- pip/_vendor/typing_extensions.py +0 -4584
- {pip-25.1.dist-info → pip-25.2.dist-info}/entry_points.txt +0 -0
- {pip-25.1.dist-info → pip-25.2.dist-info}/licenses/LICENSE.txt +0 -0
- {pip-25.1.dist-info → pip-25.2.dist-info}/top_level.txt +0 -0
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
"""Support for installing and building the "wheel" binary package format."""
|
|
2
2
|
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
3
5
|
import collections
|
|
4
6
|
import compileall
|
|
5
7
|
import contextlib
|
|
@@ -10,27 +12,19 @@ import os.path
|
|
|
10
12
|
import re
|
|
11
13
|
import shutil
|
|
12
14
|
import sys
|
|
15
|
+
import textwrap
|
|
13
16
|
import warnings
|
|
14
17
|
from base64 import urlsafe_b64encode
|
|
18
|
+
from collections.abc import Generator, Iterable, Iterator, Sequence
|
|
15
19
|
from email.message import Message
|
|
16
|
-
from io import StringIO
|
|
17
20
|
from itertools import chain, filterfalse, starmap
|
|
18
21
|
from typing import (
|
|
19
22
|
IO,
|
|
20
23
|
Any,
|
|
21
24
|
BinaryIO,
|
|
22
25
|
Callable,
|
|
23
|
-
Dict,
|
|
24
|
-
Generator,
|
|
25
|
-
Iterable,
|
|
26
|
-
Iterator,
|
|
27
|
-
List,
|
|
28
26
|
NewType,
|
|
29
|
-
Optional,
|
|
30
27
|
Protocol,
|
|
31
|
-
Sequence,
|
|
32
|
-
Set,
|
|
33
|
-
Tuple,
|
|
34
28
|
Union,
|
|
35
29
|
cast,
|
|
36
30
|
)
|
|
@@ -50,7 +44,7 @@ from pip._internal.metadata import (
|
|
|
50
44
|
from pip._internal.models.direct_url import DIRECT_URL_METADATA_NAME, DirectUrl
|
|
51
45
|
from pip._internal.models.scheme import SCHEME_KEYS, Scheme
|
|
52
46
|
from pip._internal.utils.filesystem import adjacent_tmp_file, replace
|
|
53
|
-
from pip._internal.utils.misc import ensure_dir, hash_file, partition
|
|
47
|
+
from pip._internal.utils.misc import StreamWrapper, ensure_dir, hash_file, partition
|
|
54
48
|
from pip._internal.utils.unpacking import (
|
|
55
49
|
current_umask,
|
|
56
50
|
is_within_directory,
|
|
@@ -61,7 +55,7 @@ from pip._internal.utils.wheel import parse_wheel
|
|
|
61
55
|
|
|
62
56
|
|
|
63
57
|
class File(Protocol):
|
|
64
|
-
src_record_path:
|
|
58
|
+
src_record_path: RecordPath
|
|
65
59
|
dest_path: str
|
|
66
60
|
changed: bool
|
|
67
61
|
|
|
@@ -72,17 +66,17 @@ class File(Protocol):
|
|
|
72
66
|
logger = logging.getLogger(__name__)
|
|
73
67
|
|
|
74
68
|
RecordPath = NewType("RecordPath", str)
|
|
75
|
-
InstalledCSVRow =
|
|
69
|
+
InstalledCSVRow = tuple[RecordPath, str, Union[int, str]]
|
|
76
70
|
|
|
77
71
|
|
|
78
|
-
def rehash(path: str, blocksize: int = 1 << 20) ->
|
|
72
|
+
def rehash(path: str, blocksize: int = 1 << 20) -> tuple[str, str]:
|
|
79
73
|
"""Return (encoded_digest, length) for path using hashlib.sha256()"""
|
|
80
74
|
h, length = hash_file(path, blocksize)
|
|
81
75
|
digest = "sha256=" + urlsafe_b64encode(h.digest()).decode("latin1").rstrip("=")
|
|
82
76
|
return (digest, str(length))
|
|
83
77
|
|
|
84
78
|
|
|
85
|
-
def csv_io_kwargs(mode: str) ->
|
|
79
|
+
def csv_io_kwargs(mode: str) -> dict[str, Any]:
|
|
86
80
|
"""Return keyword arguments to properly open a CSV file
|
|
87
81
|
in the given mode.
|
|
88
82
|
"""
|
|
@@ -113,7 +107,7 @@ def wheel_root_is_purelib(metadata: Message) -> bool:
|
|
|
113
107
|
return metadata.get("Root-Is-Purelib", "").lower() == "true"
|
|
114
108
|
|
|
115
109
|
|
|
116
|
-
def get_entrypoints(dist: BaseDistribution) ->
|
|
110
|
+
def get_entrypoints(dist: BaseDistribution) -> tuple[dict[str, str], dict[str, str]]:
|
|
117
111
|
console_scripts = {}
|
|
118
112
|
gui_scripts = {}
|
|
119
113
|
for entry_point in dist.iter_entry_points():
|
|
@@ -124,7 +118,7 @@ def get_entrypoints(dist: BaseDistribution) -> Tuple[Dict[str, str], Dict[str, s
|
|
|
124
118
|
return console_scripts, gui_scripts
|
|
125
119
|
|
|
126
120
|
|
|
127
|
-
def message_about_scripts_not_on_PATH(scripts: Sequence[str]) ->
|
|
121
|
+
def message_about_scripts_not_on_PATH(scripts: Sequence[str]) -> str | None:
|
|
128
122
|
"""Determine if any scripts are not on PATH and format a warning.
|
|
129
123
|
Returns a warning message if one or more scripts are not on PATH,
|
|
130
124
|
otherwise None.
|
|
@@ -133,7 +127,7 @@ def message_about_scripts_not_on_PATH(scripts: Sequence[str]) -> Optional[str]:
|
|
|
133
127
|
return None
|
|
134
128
|
|
|
135
129
|
# Group scripts by the path they were installed in
|
|
136
|
-
grouped_by_dir:
|
|
130
|
+
grouped_by_dir: dict[str, set[str]] = collections.defaultdict(set)
|
|
137
131
|
for destfile in scripts:
|
|
138
132
|
parent_dir = os.path.dirname(destfile)
|
|
139
133
|
script_name = os.path.basename(destfile)
|
|
@@ -149,7 +143,7 @@ def message_about_scripts_not_on_PATH(scripts: Sequence[str]) -> Optional[str]:
|
|
|
149
143
|
not_warn_dirs.append(
|
|
150
144
|
os.path.normcase(os.path.normpath(os.path.dirname(sys.executable)))
|
|
151
145
|
)
|
|
152
|
-
warn_for:
|
|
146
|
+
warn_for: dict[str, set[str]] = {
|
|
153
147
|
parent_dir: scripts
|
|
154
148
|
for parent_dir, scripts in grouped_by_dir.items()
|
|
155
149
|
if os.path.normcase(os.path.normpath(parent_dir)) not in not_warn_dirs
|
|
@@ -160,7 +154,7 @@ def message_about_scripts_not_on_PATH(scripts: Sequence[str]) -> Optional[str]:
|
|
|
160
154
|
# Format a message
|
|
161
155
|
msg_lines = []
|
|
162
156
|
for parent_dir, dir_scripts in warn_for.items():
|
|
163
|
-
sorted_scripts:
|
|
157
|
+
sorted_scripts: list[str] = sorted(dir_scripts)
|
|
164
158
|
if len(sorted_scripts) == 1:
|
|
165
159
|
start_text = f"script {sorted_scripts[0]} is"
|
|
166
160
|
else:
|
|
@@ -198,7 +192,7 @@ def message_about_scripts_not_on_PATH(scripts: Sequence[str]) -> Optional[str]:
|
|
|
198
192
|
|
|
199
193
|
def _normalized_outrows(
|
|
200
194
|
outrows: Iterable[InstalledCSVRow],
|
|
201
|
-
) ->
|
|
195
|
+
) -> list[tuple[str, str, str]]:
|
|
202
196
|
"""Normalize the given rows of a RECORD file.
|
|
203
197
|
|
|
204
198
|
Items in each row are converted into str. Rows are then sorted to make
|
|
@@ -237,17 +231,17 @@ def _fs_to_record_path(path: str, lib_dir: str) -> RecordPath:
|
|
|
237
231
|
|
|
238
232
|
|
|
239
233
|
def get_csv_rows_for_installed(
|
|
240
|
-
old_csv_rows:
|
|
241
|
-
installed:
|
|
242
|
-
changed:
|
|
243
|
-
generated:
|
|
234
|
+
old_csv_rows: list[list[str]],
|
|
235
|
+
installed: dict[RecordPath, RecordPath],
|
|
236
|
+
changed: set[RecordPath],
|
|
237
|
+
generated: list[str],
|
|
244
238
|
lib_dir: str,
|
|
245
|
-
) ->
|
|
239
|
+
) -> list[InstalledCSVRow]:
|
|
246
240
|
"""
|
|
247
241
|
:param installed: A map from archive RECORD path to installation RECORD
|
|
248
242
|
path.
|
|
249
243
|
"""
|
|
250
|
-
installed_rows:
|
|
244
|
+
installed_rows: list[InstalledCSVRow] = []
|
|
251
245
|
for row in old_csv_rows:
|
|
252
246
|
if len(row) > 3:
|
|
253
247
|
logger.warning("RECORD line has more than three elements: %s", row)
|
|
@@ -268,7 +262,7 @@ def get_csv_rows_for_installed(
|
|
|
268
262
|
]
|
|
269
263
|
|
|
270
264
|
|
|
271
|
-
def get_console_script_specs(console:
|
|
265
|
+
def get_console_script_specs(console: dict[str, str]) -> list[str]:
|
|
272
266
|
"""
|
|
273
267
|
Given the mapping from entrypoint name to callable, return the relevant
|
|
274
268
|
console script specs.
|
|
@@ -382,7 +376,7 @@ class ZipBackedFile:
|
|
|
382
376
|
|
|
383
377
|
|
|
384
378
|
class ScriptFile:
|
|
385
|
-
def __init__(self, file:
|
|
379
|
+
def __init__(self, file: File) -> None:
|
|
386
380
|
self._file = file
|
|
387
381
|
self.src_record_path = self._file.src_record_path
|
|
388
382
|
self.dest_path = self._file.dest_path
|
|
@@ -397,7 +391,7 @@ class MissingCallableSuffix(InstallationError):
|
|
|
397
391
|
def __init__(self, entry_point: str) -> None:
|
|
398
392
|
super().__init__(
|
|
399
393
|
f"Invalid script entry point: {entry_point} - A callable "
|
|
400
|
-
"suffix is required.
|
|
394
|
+
"suffix is required. See https://packaging.python.org/"
|
|
401
395
|
"specifications/entry-points/#use-for-scripts for more "
|
|
402
396
|
"information."
|
|
403
397
|
)
|
|
@@ -410,9 +404,22 @@ def _raise_for_invalid_entrypoint(specification: str) -> None:
|
|
|
410
404
|
|
|
411
405
|
|
|
412
406
|
class PipScriptMaker(ScriptMaker):
|
|
407
|
+
# Override distlib's default script template with one that
|
|
408
|
+
# doesn't import `re` module, allowing scripts to load faster.
|
|
409
|
+
script_template = textwrap.dedent(
|
|
410
|
+
"""\
|
|
411
|
+
import sys
|
|
412
|
+
from %(module)s import %(import_name)s
|
|
413
|
+
if __name__ == '__main__':
|
|
414
|
+
if sys.argv[0].endswith('.exe'):
|
|
415
|
+
sys.argv[0] = sys.argv[0][:-4]
|
|
416
|
+
sys.exit(%(func)s())
|
|
417
|
+
"""
|
|
418
|
+
)
|
|
419
|
+
|
|
413
420
|
def make(
|
|
414
|
-
self, specification: str, options:
|
|
415
|
-
) ->
|
|
421
|
+
self, specification: str, options: dict[str, Any] | None = None
|
|
422
|
+
) -> list[str]:
|
|
416
423
|
_raise_for_invalid_entrypoint(specification)
|
|
417
424
|
return super().make(specification, options)
|
|
418
425
|
|
|
@@ -424,7 +431,7 @@ def _install_wheel( # noqa: C901, PLR0915 function is too long
|
|
|
424
431
|
scheme: Scheme,
|
|
425
432
|
pycompile: bool = True,
|
|
426
433
|
warn_script_location: bool = True,
|
|
427
|
-
direct_url:
|
|
434
|
+
direct_url: DirectUrl | None = None,
|
|
428
435
|
requested: bool = False,
|
|
429
436
|
) -> None:
|
|
430
437
|
"""Install a wheel.
|
|
@@ -453,9 +460,9 @@ def _install_wheel( # noqa: C901, PLR0915 function is too long
|
|
|
453
460
|
# installed = files copied from the wheel to the destination
|
|
454
461
|
# changed = files changed while installing (scripts #! line typically)
|
|
455
462
|
# generated = files newly generated during the install (script wrappers)
|
|
456
|
-
installed:
|
|
457
|
-
changed:
|
|
458
|
-
generated:
|
|
463
|
+
installed: dict[RecordPath, RecordPath] = {}
|
|
464
|
+
changed: set[RecordPath] = set()
|
|
465
|
+
generated: list[str] = []
|
|
459
466
|
|
|
460
467
|
def record_installed(
|
|
461
468
|
srcfile: RecordPath, destfile: str, modified: bool = False
|
|
@@ -481,8 +488,8 @@ def _install_wheel( # noqa: C901, PLR0915 function is too long
|
|
|
481
488
|
|
|
482
489
|
def root_scheme_file_maker(
|
|
483
490
|
zip_file: ZipFile, dest: str
|
|
484
|
-
) -> Callable[[RecordPath],
|
|
485
|
-
def make_root_scheme_file(record_path: RecordPath) ->
|
|
491
|
+
) -> Callable[[RecordPath], File]:
|
|
492
|
+
def make_root_scheme_file(record_path: RecordPath) -> File:
|
|
486
493
|
normed_path = os.path.normpath(record_path)
|
|
487
494
|
dest_path = os.path.join(dest, normed_path)
|
|
488
495
|
assert_no_path_traversal(dest, dest_path)
|
|
@@ -492,10 +499,10 @@ def _install_wheel( # noqa: C901, PLR0915 function is too long
|
|
|
492
499
|
|
|
493
500
|
def data_scheme_file_maker(
|
|
494
501
|
zip_file: ZipFile, scheme: Scheme
|
|
495
|
-
) -> Callable[[RecordPath],
|
|
502
|
+
) -> Callable[[RecordPath], File]:
|
|
496
503
|
scheme_paths = {key: getattr(scheme, key) for key in SCHEME_KEYS}
|
|
497
504
|
|
|
498
|
-
def make_data_scheme_file(record_path: RecordPath) ->
|
|
505
|
+
def make_data_scheme_file(record_path: RecordPath) -> File:
|
|
499
506
|
normed_path = os.path.normpath(record_path)
|
|
500
507
|
try:
|
|
501
508
|
_, scheme_key, dest_subpath = normed_path.split(os.path.sep, 2)
|
|
@@ -527,7 +534,7 @@ def _install_wheel( # noqa: C901, PLR0915 function is too long
|
|
|
527
534
|
def is_data_scheme_path(path: RecordPath) -> bool:
|
|
528
535
|
return path.split("/", 1)[0].endswith(".data")
|
|
529
536
|
|
|
530
|
-
paths = cast(
|
|
537
|
+
paths = cast(list[RecordPath], wheel_zip.namelist())
|
|
531
538
|
file_paths = filterfalse(is_dir_path, paths)
|
|
532
539
|
root_scheme_paths, data_scheme_paths = partition(is_data_scheme_path, file_paths)
|
|
533
540
|
|
|
@@ -553,7 +560,7 @@ def _install_wheel( # noqa: C901, PLR0915 function is too long
|
|
|
553
560
|
)
|
|
554
561
|
console, gui = get_entrypoints(distribution)
|
|
555
562
|
|
|
556
|
-
def is_entrypoint_wrapper(file:
|
|
563
|
+
def is_entrypoint_wrapper(file: File) -> bool:
|
|
557
564
|
# EP, EP.exe and EP-script.py are scripts generated for
|
|
558
565
|
# entry point EP by setuptools
|
|
559
566
|
path = file.dest_path
|
|
@@ -607,7 +614,9 @@ def _install_wheel( # noqa: C901, PLR0915 function is too long
|
|
|
607
614
|
|
|
608
615
|
# Compile all of the pyc files for the installed files
|
|
609
616
|
if pycompile:
|
|
610
|
-
with contextlib.redirect_stdout(
|
|
617
|
+
with contextlib.redirect_stdout(
|
|
618
|
+
StreamWrapper.from_stream(sys.stdout)
|
|
619
|
+
) as stdout:
|
|
611
620
|
with warnings.catch_warnings():
|
|
612
621
|
warnings.filterwarnings("ignore")
|
|
613
622
|
for path in pyc_source_file_paths():
|
|
@@ -720,7 +729,7 @@ def install_wheel(
|
|
|
720
729
|
req_description: str,
|
|
721
730
|
pycompile: bool = True,
|
|
722
731
|
warn_script_location: bool = True,
|
|
723
|
-
direct_url:
|
|
732
|
+
direct_url: DirectUrl | None = None,
|
|
724
733
|
requested: bool = False,
|
|
725
734
|
) -> None:
|
|
726
735
|
with ZipFile(wheel_path, allowZip64=True) as z:
|
|
@@ -2,16 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
# The following comment should be removed at some point in the future.
|
|
4
4
|
# mypy: strict-optional=False
|
|
5
|
+
from __future__ import annotations
|
|
5
6
|
|
|
6
7
|
import mimetypes
|
|
7
8
|
import os
|
|
8
9
|
import shutil
|
|
10
|
+
from collections.abc import Iterable
|
|
9
11
|
from dataclasses import dataclass
|
|
10
12
|
from pathlib import Path
|
|
11
|
-
from typing import
|
|
13
|
+
from typing import TYPE_CHECKING
|
|
12
14
|
|
|
13
15
|
from pip._vendor.packaging.utils import canonicalize_name
|
|
14
16
|
|
|
17
|
+
from pip._internal.build_env import BuildEnvironmentInstaller
|
|
15
18
|
from pip._internal.distributions import make_distribution_for_install_requirement
|
|
16
19
|
from pip._internal.distributions.installed import InstalledDistribution
|
|
17
20
|
from pip._internal.exceptions import (
|
|
@@ -28,7 +31,7 @@ from pip._internal.metadata import BaseDistribution, get_metadata_distribution
|
|
|
28
31
|
from pip._internal.models.direct_url import ArchiveInfo
|
|
29
32
|
from pip._internal.models.link import Link
|
|
30
33
|
from pip._internal.models.wheel import Wheel
|
|
31
|
-
from pip._internal.network.download import
|
|
34
|
+
from pip._internal.network.download import Downloader
|
|
32
35
|
from pip._internal.network.lazy_wheel import (
|
|
33
36
|
HTTPRangeRequestUnsupported,
|
|
34
37
|
dist_from_wheel_url,
|
|
@@ -53,13 +56,16 @@ from pip._internal.utils.temp_dir import TempDirectory
|
|
|
53
56
|
from pip._internal.utils.unpacking import unpack_file
|
|
54
57
|
from pip._internal.vcs import vcs
|
|
55
58
|
|
|
59
|
+
if TYPE_CHECKING:
|
|
60
|
+
from pip._internal.cli.progress_bars import BarType
|
|
61
|
+
|
|
56
62
|
logger = getLogger(__name__)
|
|
57
63
|
|
|
58
64
|
|
|
59
65
|
def _get_prepared_distribution(
|
|
60
66
|
req: InstallRequirement,
|
|
61
67
|
build_tracker: BuildTracker,
|
|
62
|
-
|
|
68
|
+
build_env_installer: BuildEnvironmentInstaller,
|
|
63
69
|
build_isolation: bool,
|
|
64
70
|
check_build_deps: bool,
|
|
65
71
|
) -> BaseDistribution:
|
|
@@ -69,7 +75,7 @@ def _get_prepared_distribution(
|
|
|
69
75
|
if tracker_id is not None:
|
|
70
76
|
with build_tracker.track(req, tracker_id):
|
|
71
77
|
abstract_dist.prepare_distribution_metadata(
|
|
72
|
-
|
|
78
|
+
build_env_installer, build_isolation, check_build_deps
|
|
73
79
|
)
|
|
74
80
|
return abstract_dist.get_metadata_distribution()
|
|
75
81
|
|
|
@@ -83,7 +89,7 @@ def unpack_vcs_link(link: Link, location: str, verbosity: int) -> None:
|
|
|
83
89
|
@dataclass
|
|
84
90
|
class File:
|
|
85
91
|
path: str
|
|
86
|
-
content_type:
|
|
92
|
+
content_type: str | None = None
|
|
87
93
|
|
|
88
94
|
def __post_init__(self) -> None:
|
|
89
95
|
if self.content_type is None:
|
|
@@ -98,8 +104,8 @@ class File:
|
|
|
98
104
|
def get_http_url(
|
|
99
105
|
link: Link,
|
|
100
106
|
download: Downloader,
|
|
101
|
-
download_dir:
|
|
102
|
-
hashes:
|
|
107
|
+
download_dir: str | None = None,
|
|
108
|
+
hashes: Hashes | None = None,
|
|
103
109
|
) -> File:
|
|
104
110
|
temp_dir = TempDirectory(kind="unpack", globally_managed=True)
|
|
105
111
|
# If a download dir is specified, is the file already downloaded there?
|
|
@@ -120,7 +126,7 @@ def get_http_url(
|
|
|
120
126
|
|
|
121
127
|
|
|
122
128
|
def get_file_url(
|
|
123
|
-
link: Link, download_dir:
|
|
129
|
+
link: Link, download_dir: str | None = None, hashes: Hashes | None = None
|
|
124
130
|
) -> File:
|
|
125
131
|
"""Get file and optionally check its hash."""
|
|
126
132
|
# If a download dir is specified, is the file already there and valid?
|
|
@@ -148,9 +154,9 @@ def unpack_url(
|
|
|
148
154
|
location: str,
|
|
149
155
|
download: Downloader,
|
|
150
156
|
verbosity: int,
|
|
151
|
-
download_dir:
|
|
152
|
-
hashes:
|
|
153
|
-
) ->
|
|
157
|
+
download_dir: str | None = None,
|
|
158
|
+
hashes: Hashes | None = None,
|
|
159
|
+
) -> File | None:
|
|
154
160
|
"""Unpack link into location, downloading if required.
|
|
155
161
|
|
|
156
162
|
:param hashes: A Hashes object, one of whose embedded hashes must match,
|
|
@@ -189,9 +195,9 @@ def unpack_url(
|
|
|
189
195
|
def _check_download_dir(
|
|
190
196
|
link: Link,
|
|
191
197
|
download_dir: str,
|
|
192
|
-
hashes:
|
|
198
|
+
hashes: Hashes | None,
|
|
193
199
|
warn_on_hash_mismatch: bool = True,
|
|
194
|
-
) ->
|
|
200
|
+
) -> str | None:
|
|
195
201
|
"""Check download_dir for previously downloaded file with correct hash
|
|
196
202
|
If a correct file is found return its path else None
|
|
197
203
|
"""
|
|
@@ -219,16 +225,18 @@ def _check_download_dir(
|
|
|
219
225
|
class RequirementPreparer:
|
|
220
226
|
"""Prepares a Requirement"""
|
|
221
227
|
|
|
222
|
-
def __init__(
|
|
228
|
+
def __init__( # noqa: PLR0913 (too many parameters)
|
|
223
229
|
self,
|
|
230
|
+
*,
|
|
224
231
|
build_dir: str,
|
|
225
|
-
download_dir:
|
|
232
|
+
download_dir: str | None,
|
|
226
233
|
src_dir: str,
|
|
227
234
|
build_isolation: bool,
|
|
235
|
+
build_isolation_installer: BuildEnvironmentInstaller,
|
|
228
236
|
check_build_deps: bool,
|
|
229
237
|
build_tracker: BuildTracker,
|
|
230
238
|
session: PipSession,
|
|
231
|
-
progress_bar:
|
|
239
|
+
progress_bar: BarType,
|
|
232
240
|
finder: PackageFinder,
|
|
233
241
|
require_hashes: bool,
|
|
234
242
|
use_user_site: bool,
|
|
@@ -244,7 +252,6 @@ class RequirementPreparer:
|
|
|
244
252
|
self.build_tracker = build_tracker
|
|
245
253
|
self._session = session
|
|
246
254
|
self._download = Downloader(session, progress_bar, resume_retries)
|
|
247
|
-
self._batch_download = BatchDownloader(session, progress_bar, resume_retries)
|
|
248
255
|
self.finder = finder
|
|
249
256
|
|
|
250
257
|
# Where still-packed archives should be written to. If None, they are
|
|
@@ -253,6 +260,7 @@ class RequirementPreparer:
|
|
|
253
260
|
|
|
254
261
|
# Is build isolation allowed?
|
|
255
262
|
self.build_isolation = build_isolation
|
|
263
|
+
self.build_env_installer = build_isolation_installer
|
|
256
264
|
|
|
257
265
|
# Should check build dependencies?
|
|
258
266
|
self.check_build_deps = check_build_deps
|
|
@@ -273,7 +281,7 @@ class RequirementPreparer:
|
|
|
273
281
|
self.legacy_resolver = legacy_resolver
|
|
274
282
|
|
|
275
283
|
# Memoized downloaded files, as mapping of url: path.
|
|
276
|
-
self._downloaded:
|
|
284
|
+
self._downloaded: dict[str, str] = {}
|
|
277
285
|
|
|
278
286
|
# Previous "header" printed for a link-based InstallRequirement
|
|
279
287
|
self._previous_requirement_header = ("", "")
|
|
@@ -291,7 +299,7 @@ class RequirementPreparer:
|
|
|
291
299
|
# would already be included if we used req directly)
|
|
292
300
|
if req.req and req.comes_from:
|
|
293
301
|
if isinstance(req.comes_from, str):
|
|
294
|
-
comes_from:
|
|
302
|
+
comes_from: str | None = req.comes_from
|
|
295
303
|
else:
|
|
296
304
|
comes_from = req.comes_from.from_path()
|
|
297
305
|
if comes_from:
|
|
@@ -363,7 +371,7 @@ class RequirementPreparer:
|
|
|
363
371
|
def _fetch_metadata_only(
|
|
364
372
|
self,
|
|
365
373
|
req: InstallRequirement,
|
|
366
|
-
) ->
|
|
374
|
+
) -> BaseDistribution | None:
|
|
367
375
|
if self.legacy_resolver:
|
|
368
376
|
logger.debug(
|
|
369
377
|
"Metadata-only fetching is not used in the legacy resolver",
|
|
@@ -382,7 +390,7 @@ class RequirementPreparer:
|
|
|
382
390
|
def _fetch_metadata_using_link_data_attr(
|
|
383
391
|
self,
|
|
384
392
|
req: InstallRequirement,
|
|
385
|
-
) ->
|
|
393
|
+
) -> BaseDistribution | None:
|
|
386
394
|
"""Fetch metadata from the data-dist-info-metadata attribute, if possible."""
|
|
387
395
|
# (1) Get the link to the metadata file, if provided by the backend.
|
|
388
396
|
metadata_link = req.link.metadata_link()
|
|
@@ -423,7 +431,7 @@ class RequirementPreparer:
|
|
|
423
431
|
def _fetch_metadata_using_lazy_wheel(
|
|
424
432
|
self,
|
|
425
433
|
link: Link,
|
|
426
|
-
) ->
|
|
434
|
+
) -> BaseDistribution | None:
|
|
427
435
|
"""Fetch metadata using lazy wheel, if possible."""
|
|
428
436
|
# --use-feature=fast-deps must be provided.
|
|
429
437
|
if not self.use_lazy_wheel:
|
|
@@ -462,15 +470,12 @@ class RequirementPreparer:
|
|
|
462
470
|
# Map each link to the requirement that owns it. This allows us to set
|
|
463
471
|
# `req.local_file_path` on the appropriate requirement after passing
|
|
464
472
|
# all the links at once into BatchDownloader.
|
|
465
|
-
links_to_fully_download:
|
|
473
|
+
links_to_fully_download: dict[Link, InstallRequirement] = {}
|
|
466
474
|
for req in partially_downloaded_reqs:
|
|
467
475
|
assert req.link
|
|
468
476
|
links_to_fully_download[req.link] = req
|
|
469
477
|
|
|
470
|
-
batch_download = self.
|
|
471
|
-
links_to_fully_download.keys(),
|
|
472
|
-
temp_dir,
|
|
473
|
-
)
|
|
478
|
+
batch_download = self._download.batch(links_to_fully_download.keys(), temp_dir)
|
|
474
479
|
for link, (filepath, _) in batch_download:
|
|
475
480
|
logger.debug("Downloading link %s to %s", link, filepath)
|
|
476
481
|
req = links_to_fully_download[link]
|
|
@@ -547,7 +552,7 @@ class RequirementPreparer:
|
|
|
547
552
|
|
|
548
553
|
# Prepare requirements we found were already downloaded for some
|
|
549
554
|
# reason. The other downloads will be completed separately.
|
|
550
|
-
partially_downloaded_reqs:
|
|
555
|
+
partially_downloaded_reqs: list[InstallRequirement] = []
|
|
551
556
|
for req in reqs:
|
|
552
557
|
if req.needs_more_preparation:
|
|
553
558
|
partially_downloaded_reqs.append(req)
|
|
@@ -647,7 +652,7 @@ class RequirementPreparer:
|
|
|
647
652
|
dist = _get_prepared_distribution(
|
|
648
653
|
req,
|
|
649
654
|
self.build_tracker,
|
|
650
|
-
self.
|
|
655
|
+
self.build_env_installer,
|
|
651
656
|
self.build_isolation,
|
|
652
657
|
self.check_build_deps,
|
|
653
658
|
)
|
|
@@ -703,7 +708,7 @@ class RequirementPreparer:
|
|
|
703
708
|
dist = _get_prepared_distribution(
|
|
704
709
|
req,
|
|
705
710
|
self.build_tracker,
|
|
706
|
-
self.
|
|
711
|
+
self.build_env_installer,
|
|
707
712
|
self.build_isolation,
|
|
708
713
|
self.check_build_deps,
|
|
709
714
|
)
|
pip/_internal/pyproject.py
CHANGED
|
@@ -1,13 +1,9 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import importlib.util
|
|
2
4
|
import os
|
|
3
|
-
import sys
|
|
4
5
|
from collections import namedtuple
|
|
5
|
-
from typing import Any
|
|
6
|
-
|
|
7
|
-
if sys.version_info >= (3, 11):
|
|
8
|
-
import tomllib
|
|
9
|
-
else:
|
|
10
|
-
from pip._vendor import tomli as tomllib
|
|
6
|
+
from typing import Any
|
|
11
7
|
|
|
12
8
|
from pip._vendor.packaging.requirements import InvalidRequirement
|
|
13
9
|
|
|
@@ -16,6 +12,7 @@ from pip._internal.exceptions import (
|
|
|
16
12
|
InvalidPyProjectBuildRequires,
|
|
17
13
|
MissingPyProjectBuildRequires,
|
|
18
14
|
)
|
|
15
|
+
from pip._internal.utils.compat import tomllib
|
|
19
16
|
from pip._internal.utils.packaging import get_requirement
|
|
20
17
|
|
|
21
18
|
|
|
@@ -33,8 +30,8 @@ BuildSystemDetails = namedtuple(
|
|
|
33
30
|
|
|
34
31
|
|
|
35
32
|
def load_pyproject_toml(
|
|
36
|
-
use_pep517:
|
|
37
|
-
) ->
|
|
33
|
+
use_pep517: bool | None, pyproject_toml: str, setup_py: str, req_name: str
|
|
34
|
+
) -> BuildSystemDetails | None:
|
|
38
35
|
"""Load the pyproject.toml file.
|
|
39
36
|
|
|
40
37
|
Parameters:
|
|
@@ -166,7 +163,7 @@ def load_pyproject_toml(
|
|
|
166
163
|
|
|
167
164
|
backend = build_system.get("build-backend")
|
|
168
165
|
backend_path = build_system.get("backend-path", [])
|
|
169
|
-
check:
|
|
166
|
+
check: list[str] = []
|
|
170
167
|
if backend is None:
|
|
171
168
|
# If the user didn't specify a backend, we assume they want to use
|
|
172
169
|
# the setuptools backend. But we can't be sure they have included
|
pip/_internal/req/__init__.py
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import collections
|
|
2
4
|
import logging
|
|
5
|
+
from collections.abc import Generator, Sequence
|
|
3
6
|
from dataclasses import dataclass
|
|
4
|
-
from typing import Generator, List, Optional, Sequence, Tuple
|
|
5
7
|
|
|
6
|
-
from pip._internal.cli.progress_bars import get_install_progress_renderer
|
|
8
|
+
from pip._internal.cli.progress_bars import BarType, get_install_progress_renderer
|
|
7
9
|
from pip._internal.utils.logging import indent_log
|
|
8
10
|
|
|
9
11
|
from .req_file import parse_requirements
|
|
@@ -26,24 +28,24 @@ class InstallationResult:
|
|
|
26
28
|
|
|
27
29
|
|
|
28
30
|
def _validate_requirements(
|
|
29
|
-
requirements:
|
|
30
|
-
) -> Generator[
|
|
31
|
+
requirements: list[InstallRequirement],
|
|
32
|
+
) -> Generator[tuple[str, InstallRequirement], None, None]:
|
|
31
33
|
for req in requirements:
|
|
32
34
|
assert req.name, f"invalid to-be-installed requirement: {req}"
|
|
33
35
|
yield req.name, req
|
|
34
36
|
|
|
35
37
|
|
|
36
38
|
def install_given_reqs(
|
|
37
|
-
requirements:
|
|
39
|
+
requirements: list[InstallRequirement],
|
|
38
40
|
global_options: Sequence[str],
|
|
39
|
-
root:
|
|
40
|
-
home:
|
|
41
|
-
prefix:
|
|
41
|
+
root: str | None,
|
|
42
|
+
home: str | None,
|
|
43
|
+
prefix: str | None,
|
|
42
44
|
warn_script_location: bool,
|
|
43
45
|
use_user_site: bool,
|
|
44
46
|
pycompile: bool,
|
|
45
|
-
progress_bar:
|
|
46
|
-
) ->
|
|
47
|
+
progress_bar: BarType,
|
|
48
|
+
) -> list[InstallationResult]:
|
|
47
49
|
"""
|
|
48
50
|
Install everything in the given list.
|
|
49
51
|
|