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.
- pip/__init__.py +3 -3
- pip/_internal/__init__.py +2 -2
- pip/_internal/build_env.py +186 -94
- pip/_internal/cache.py +17 -15
- pip/_internal/cli/autocompletion.py +13 -4
- pip/_internal/cli/base_command.py +18 -7
- pip/_internal/cli/cmdoptions.py +57 -80
- 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 +24 -20
- pip/_internal/cli/progress_bars.py +19 -12
- pip/_internal/cli/req_command.py +57 -33
- 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 +6 -10
- 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 +63 -53
- pip/_internal/commands/list.py +35 -26
- pip/_internal/commands/lock.py +4 -8
- 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 +7 -13
- pip/_internal/configuration.py +40 -27
- pip/_internal/distributions/base.py +6 -4
- pip/_internal/distributions/installed.py +8 -4
- pip/_internal/distributions/sdist.py +33 -27
- pip/_internal/distributions/wheel.py +6 -4
- pip/_internal/exceptions.py +78 -42
- pip/_internal/index/collector.py +24 -29
- pip/_internal/index/package_finder.py +73 -64
- 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 +14 -7
- 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 +20 -19
- 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 +12 -71
- pip/_internal/network/auth.py +20 -22
- pip/_internal/network/cache.py +28 -17
- pip/_internal/network/download.py +169 -141
- pip/_internal/network/lazy_wheel.py +15 -10
- 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 +7 -6
- pip/_internal/operations/build/wheel_editable.py +7 -6
- pip/_internal/operations/check.py +21 -26
- pip/_internal/operations/freeze.py +12 -9
- pip/_internal/operations/install/wheel.py +49 -41
- pip/_internal/operations/prepare.py +42 -31
- pip/_internal/pyproject.py +7 -69
- pip/_internal/req/__init__.py +12 -12
- pip/_internal/req/constructors.py +68 -62
- pip/_internal/req/req_dependency_group.py +7 -11
- pip/_internal/req/req_file.py +32 -36
- pip/_internal/req/req_install.py +64 -170
- 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 +49 -37
- pip/_internal/resolution/resolvelib/factory.py +72 -50
- pip/_internal/resolution/resolvelib/found_candidates.py +11 -9
- pip/_internal/resolution/resolvelib/provider.py +24 -20
- pip/_internal/resolution/resolvelib/reporter.py +26 -11
- pip/_internal/resolution/resolvelib/requirements.py +8 -6
- pip/_internal/resolution/resolvelib/resolver.py +41 -29
- pip/_internal/self_outdated_check.py +19 -9
- 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 +20 -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 +37 -45
- pip/_internal/utils/packaging.py +3 -2
- pip/_internal/utils/retry.py +7 -4
- pip/_internal/utils/subprocess.py +20 -17
- pip/_internal/utils/temp_dir.py +10 -12
- pip/_internal/utils/unpacking.py +31 -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 +30 -101
- pip/_vendor/README.rst +180 -0
- pip/_vendor/cachecontrol/LICENSE.txt +13 -0
- pip/_vendor/cachecontrol/__init__.py +1 -1
- pip/_vendor/certifi/LICENSE +20 -0
- pip/_vendor/certifi/__init__.py +1 -1
- pip/_vendor/certifi/cacert.pem +164 -261
- pip/_vendor/certifi/core.py +1 -32
- pip/_vendor/dependency_groups/LICENSE.txt +9 -0
- pip/_vendor/distlib/LICENSE.txt +284 -0
- pip/_vendor/distlib/__init__.py +2 -2
- pip/_vendor/distlib/scripts.py +1 -1
- pip/_vendor/distro/LICENSE +202 -0
- pip/_vendor/idna/LICENSE.md +31 -0
- pip/_vendor/msgpack/COPYING +14 -0
- pip/_vendor/msgpack/__init__.py +2 -2
- pip/_vendor/packaging/LICENSE +3 -0
- pip/_vendor/packaging/LICENSE.APACHE +177 -0
- pip/_vendor/packaging/LICENSE.BSD +23 -0
- pip/_vendor/pkg_resources/LICENSE +17 -0
- pip/_vendor/pkg_resources/__init__.py +1 -1
- pip/_vendor/platformdirs/LICENSE +21 -0
- pip/_vendor/platformdirs/api.py +1 -1
- pip/_vendor/platformdirs/macos.py +10 -8
- pip/_vendor/platformdirs/version.py +16 -3
- pip/_vendor/pygments/LICENSE +25 -0
- pip/_vendor/pygments/__init__.py +1 -1
- pip/_vendor/pyproject_hooks/LICENSE +21 -0
- pip/_vendor/requests/LICENSE +175 -0
- pip/_vendor/requests/__version__.py +2 -2
- pip/_vendor/requests/adapters.py +17 -40
- pip/_vendor/requests/compat.py +12 -0
- pip/_vendor/requests/models.py +3 -1
- pip/_vendor/requests/sessions.py +1 -1
- pip/_vendor/requests/utils.py +6 -16
- pip/_vendor/resolvelib/LICENSE +13 -0
- 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/abstract.py +3 -3
- pip/_vendor/resolvelib/resolvers/resolution.py +96 -10
- pip/_vendor/rich/LICENSE +19 -0
- 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/style.py +7 -11
- pip/_vendor/rich/syntax.py +24 -5
- pip/_vendor/rich/traceback.py +32 -17
- pip/_vendor/tomli/LICENSE +21 -0
- pip/_vendor/tomli/__init__.py +1 -1
- pip/_vendor/tomli/_parser.py +28 -21
- pip/_vendor/tomli/_re.py +8 -5
- pip/_vendor/tomli_w/LICENSE +21 -0
- pip/_vendor/truststore/LICENSE +21 -0
- pip/_vendor/truststore/__init__.py +1 -1
- pip/_vendor/truststore/_api.py +15 -7
- pip/_vendor/truststore/_openssl.py +3 -1
- pip/_vendor/urllib3/LICENSE.txt +21 -0
- pip/_vendor/vendor.txt +11 -12
- {pip-25.1.1.dist-info → pip-25.3.dist-info}/METADATA +32 -11
- {pip-25.1.1.dist-info → pip-25.3.dist-info}/RECORD +221 -192
- {pip-25.1.1.dist-info → pip-25.3.dist-info}/WHEEL +1 -2
- pip-25.3.dist-info/entry_points.txt +4 -0
- {pip-25.1.1.dist-info → pip-25.3.dist-info}/licenses/AUTHORS.txt +21 -0
- pip-25.3.dist-info/licenses/src/pip/_vendor/cachecontrol/LICENSE.txt +13 -0
- pip-25.3.dist-info/licenses/src/pip/_vendor/certifi/LICENSE +20 -0
- pip-25.3.dist-info/licenses/src/pip/_vendor/dependency_groups/LICENSE.txt +9 -0
- pip-25.3.dist-info/licenses/src/pip/_vendor/distlib/LICENSE.txt +284 -0
- pip-25.3.dist-info/licenses/src/pip/_vendor/distro/LICENSE +202 -0
- pip-25.3.dist-info/licenses/src/pip/_vendor/idna/LICENSE.md +31 -0
- pip-25.3.dist-info/licenses/src/pip/_vendor/msgpack/COPYING +14 -0
- pip-25.3.dist-info/licenses/src/pip/_vendor/packaging/LICENSE +3 -0
- pip-25.3.dist-info/licenses/src/pip/_vendor/packaging/LICENSE.APACHE +177 -0
- pip-25.3.dist-info/licenses/src/pip/_vendor/packaging/LICENSE.BSD +23 -0
- pip-25.3.dist-info/licenses/src/pip/_vendor/pkg_resources/LICENSE +17 -0
- pip-25.3.dist-info/licenses/src/pip/_vendor/platformdirs/LICENSE +21 -0
- pip-25.3.dist-info/licenses/src/pip/_vendor/pygments/LICENSE +25 -0
- pip-25.3.dist-info/licenses/src/pip/_vendor/pyproject_hooks/LICENSE +21 -0
- pip-25.3.dist-info/licenses/src/pip/_vendor/requests/LICENSE +175 -0
- pip-25.3.dist-info/licenses/src/pip/_vendor/resolvelib/LICENSE +13 -0
- pip-25.3.dist-info/licenses/src/pip/_vendor/rich/LICENSE +19 -0
- pip-25.3.dist-info/licenses/src/pip/_vendor/tomli/LICENSE +21 -0
- pip-25.3.dist-info/licenses/src/pip/_vendor/tomli_w/LICENSE +21 -0
- pip-25.3.dist-info/licenses/src/pip/_vendor/truststore/LICENSE +21 -0
- pip-25.3.dist-info/licenses/src/pip/_vendor/urllib3/LICENSE.txt +21 -0
- pip/_internal/operations/build/metadata_legacy.py +0 -73
- pip/_internal/operations/build/wheel_legacy.py +0 -118
- pip/_internal/operations/install/editable_legacy.py +0 -46
- pip/_internal/utils/setuptools_build.py +0 -147
- 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.1.dist-info/entry_points.txt +0 -3
- pip-25.1.1.dist-info/top_level.txt +0 -1
- {pip-25.1.1.dist-info → pip-25.3.dist-info}/licenses/LICENSE.txt +0 -0
|
@@ -1,10 +1,13 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import importlib.metadata
|
|
2
4
|
import logging
|
|
3
5
|
import os
|
|
4
6
|
import pathlib
|
|
5
7
|
import sys
|
|
6
8
|
import zipfile
|
|
7
|
-
from
|
|
9
|
+
from collections.abc import Iterator, Sequence
|
|
10
|
+
from typing import Optional
|
|
8
11
|
|
|
9
12
|
from pip._vendor.packaging.utils import (
|
|
10
13
|
InvalidWheelFilename,
|
|
@@ -47,10 +50,10 @@ class _DistributionFinder:
|
|
|
47
50
|
installations as well. It's useful feature, after all.
|
|
48
51
|
"""
|
|
49
52
|
|
|
50
|
-
FoundResult =
|
|
53
|
+
FoundResult = tuple[importlib.metadata.Distribution, Optional[BasePath]]
|
|
51
54
|
|
|
52
55
|
def __init__(self) -> None:
|
|
53
|
-
self._found_names:
|
|
56
|
+
self._found_names: set[NormalizedName] = set()
|
|
54
57
|
|
|
55
58
|
def _find_impl(self, location: str) -> Iterator[FoundResult]:
|
|
56
59
|
"""Find distributions in a location."""
|
|
@@ -80,7 +83,7 @@ class _DistributionFinder:
|
|
|
80
83
|
"""
|
|
81
84
|
for dist, info_location in self._find_impl(location):
|
|
82
85
|
if info_location is None:
|
|
83
|
-
installed_location:
|
|
86
|
+
installed_location: BasePath | None = None
|
|
84
87
|
else:
|
|
85
88
|
installed_location = info_location.parent
|
|
86
89
|
yield Distribution(dist, info_location, installed_location)
|
|
@@ -119,7 +122,7 @@ class Environment(BaseEnvironment):
|
|
|
119
122
|
return cls(sys.path)
|
|
120
123
|
|
|
121
124
|
@classmethod
|
|
122
|
-
def from_paths(cls, paths:
|
|
125
|
+
def from_paths(cls, paths: list[str] | None) -> BaseEnvironment:
|
|
123
126
|
if paths is None:
|
|
124
127
|
return cls(sys.path)
|
|
125
128
|
return cls(paths)
|
|
@@ -130,7 +133,7 @@ class Environment(BaseEnvironment):
|
|
|
130
133
|
yield from finder.find(location)
|
|
131
134
|
yield from finder.find_legacy_editables(location)
|
|
132
135
|
|
|
133
|
-
def get_distribution(self, name: str) ->
|
|
136
|
+
def get_distribution(self, name: str) -> BaseDistribution | None:
|
|
134
137
|
canonical_name = canonicalize_name(name)
|
|
135
138
|
matches = (
|
|
136
139
|
distribution
|
|
@@ -1,16 +1,13 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import email.message
|
|
2
4
|
import email.parser
|
|
3
5
|
import logging
|
|
4
6
|
import os
|
|
5
7
|
import zipfile
|
|
8
|
+
from collections.abc import Collection, Iterable, Iterator, Mapping
|
|
6
9
|
from typing import (
|
|
7
|
-
Collection,
|
|
8
|
-
Iterable,
|
|
9
|
-
Iterator,
|
|
10
|
-
List,
|
|
11
|
-
Mapping,
|
|
12
10
|
NamedTuple,
|
|
13
|
-
Optional,
|
|
14
11
|
)
|
|
15
12
|
|
|
16
13
|
from pip._vendor import pkg_resources
|
|
@@ -73,7 +70,7 @@ class InMemoryMetadata:
|
|
|
73
70
|
def metadata_isdir(self, name: str) -> bool:
|
|
74
71
|
return False
|
|
75
72
|
|
|
76
|
-
def metadata_listdir(self, name: str) ->
|
|
73
|
+
def metadata_listdir(self, name: str) -> list[str]:
|
|
77
74
|
return []
|
|
78
75
|
|
|
79
76
|
def run_script(self, script_name: str, namespace: str) -> None:
|
|
@@ -85,7 +82,7 @@ class Distribution(BaseDistribution):
|
|
|
85
82
|
self._dist = dist
|
|
86
83
|
# This is populated lazily, to avoid loading metadata for all possible
|
|
87
84
|
# distributions eagerly.
|
|
88
|
-
self.__extra_mapping:
|
|
85
|
+
self.__extra_mapping: Mapping[NormalizedName, str] | None = None
|
|
89
86
|
|
|
90
87
|
@property
|
|
91
88
|
def _extra_mapping(self) -> Mapping[NormalizedName, str]:
|
|
@@ -155,11 +152,11 @@ class Distribution(BaseDistribution):
|
|
|
155
152
|
return cls(dist)
|
|
156
153
|
|
|
157
154
|
@property
|
|
158
|
-
def location(self) ->
|
|
155
|
+
def location(self) -> str | None:
|
|
159
156
|
return self._dist.location
|
|
160
157
|
|
|
161
158
|
@property
|
|
162
|
-
def installed_location(self) ->
|
|
159
|
+
def installed_location(self) -> str | None:
|
|
163
160
|
egg_link = egg_link_path_from_location(self.raw_name)
|
|
164
161
|
if egg_link:
|
|
165
162
|
location = egg_link
|
|
@@ -170,7 +167,7 @@ class Distribution(BaseDistribution):
|
|
|
170
167
|
return normalize_path(location)
|
|
171
168
|
|
|
172
169
|
@property
|
|
173
|
-
def info_location(self) ->
|
|
170
|
+
def info_location(self) -> str | None:
|
|
174
171
|
return self._dist.egg_info
|
|
175
172
|
|
|
176
173
|
@property
|
|
@@ -259,14 +256,14 @@ class Environment(BaseEnvironment):
|
|
|
259
256
|
return cls(pkg_resources.working_set)
|
|
260
257
|
|
|
261
258
|
@classmethod
|
|
262
|
-
def from_paths(cls, paths:
|
|
259
|
+
def from_paths(cls, paths: list[str] | None) -> BaseEnvironment:
|
|
263
260
|
return cls(pkg_resources.WorkingSet(paths))
|
|
264
261
|
|
|
265
262
|
def _iter_distributions(self) -> Iterator[BaseDistribution]:
|
|
266
263
|
for dist in self._ws:
|
|
267
264
|
yield Distribution(dist)
|
|
268
265
|
|
|
269
|
-
def _search_distribution(self, name: str) ->
|
|
266
|
+
def _search_distribution(self, name: str) -> BaseDistribution | None:
|
|
270
267
|
"""Find a distribution matching the ``name`` in the environment.
|
|
271
268
|
|
|
272
269
|
This searches from *all* distributions available in the environment, to
|
|
@@ -278,7 +275,7 @@ class Environment(BaseEnvironment):
|
|
|
278
275
|
return dist
|
|
279
276
|
return None
|
|
280
277
|
|
|
281
|
-
def get_distribution(self, name: str) ->
|
|
278
|
+
def get_distribution(self, name: str) -> BaseDistribution | None:
|
|
282
279
|
# Search the distribution by looking through the working set.
|
|
283
280
|
dist = self._search_distribution(name)
|
|
284
281
|
if dist:
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
"""PEP 610"""
|
|
2
2
|
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
3
5
|
import json
|
|
4
6
|
import re
|
|
5
7
|
import urllib.parse
|
|
8
|
+
from collections.abc import Iterable
|
|
6
9
|
from dataclasses import dataclass
|
|
7
|
-
from typing import Any, ClassVar,
|
|
10
|
+
from typing import Any, ClassVar, TypeVar, Union
|
|
8
11
|
|
|
9
12
|
__all__ = [
|
|
10
13
|
"DirectUrl",
|
|
@@ -25,8 +28,8 @@ class DirectUrlValidationError(Exception):
|
|
|
25
28
|
|
|
26
29
|
|
|
27
30
|
def _get(
|
|
28
|
-
d:
|
|
29
|
-
) ->
|
|
31
|
+
d: dict[str, Any], expected_type: type[T], key: str, default: T | None = None
|
|
32
|
+
) -> T | None:
|
|
30
33
|
"""Get value from dictionary and verify expected type."""
|
|
31
34
|
if key not in d:
|
|
32
35
|
return default
|
|
@@ -39,7 +42,7 @@ def _get(
|
|
|
39
42
|
|
|
40
43
|
|
|
41
44
|
def _get_required(
|
|
42
|
-
d:
|
|
45
|
+
d: dict[str, Any], expected_type: type[T], key: str, default: T | None = None
|
|
43
46
|
) -> T:
|
|
44
47
|
value = _get(d, expected_type, key, default)
|
|
45
48
|
if value is None:
|
|
@@ -47,7 +50,7 @@ def _get_required(
|
|
|
47
50
|
return value
|
|
48
51
|
|
|
49
52
|
|
|
50
|
-
def _exactly_one_of(infos: Iterable[
|
|
53
|
+
def _exactly_one_of(infos: Iterable[InfoType | None]) -> InfoType:
|
|
51
54
|
infos = [info for info in infos if info is not None]
|
|
52
55
|
if not infos:
|
|
53
56
|
raise DirectUrlValidationError(
|
|
@@ -61,7 +64,7 @@ def _exactly_one_of(infos: Iterable[Optional["InfoType"]]) -> "InfoType":
|
|
|
61
64
|
return infos[0]
|
|
62
65
|
|
|
63
66
|
|
|
64
|
-
def _filter_none(**kwargs: Any) ->
|
|
67
|
+
def _filter_none(**kwargs: Any) -> dict[str, Any]:
|
|
65
68
|
"""Make dict excluding None values."""
|
|
66
69
|
return {k: v for k, v in kwargs.items() if v is not None}
|
|
67
70
|
|
|
@@ -72,10 +75,10 @@ class VcsInfo:
|
|
|
72
75
|
|
|
73
76
|
vcs: str
|
|
74
77
|
commit_id: str
|
|
75
|
-
requested_revision:
|
|
78
|
+
requested_revision: str | None = None
|
|
76
79
|
|
|
77
80
|
@classmethod
|
|
78
|
-
def _from_dict(cls, d:
|
|
81
|
+
def _from_dict(cls, d: dict[str, Any] | None) -> VcsInfo | None:
|
|
79
82
|
if d is None:
|
|
80
83
|
return None
|
|
81
84
|
return cls(
|
|
@@ -84,7 +87,7 @@ class VcsInfo:
|
|
|
84
87
|
requested_revision=_get(d, str, "requested_revision"),
|
|
85
88
|
)
|
|
86
89
|
|
|
87
|
-
def _to_dict(self) ->
|
|
90
|
+
def _to_dict(self) -> dict[str, Any]:
|
|
88
91
|
return _filter_none(
|
|
89
92
|
vcs=self.vcs,
|
|
90
93
|
requested_revision=self.requested_revision,
|
|
@@ -97,19 +100,19 @@ class ArchiveInfo:
|
|
|
97
100
|
|
|
98
101
|
def __init__(
|
|
99
102
|
self,
|
|
100
|
-
hash:
|
|
101
|
-
hashes:
|
|
103
|
+
hash: str | None = None,
|
|
104
|
+
hashes: dict[str, str] | None = None,
|
|
102
105
|
) -> None:
|
|
103
106
|
# set hashes before hash, since the hash setter will further populate hashes
|
|
104
107
|
self.hashes = hashes
|
|
105
108
|
self.hash = hash
|
|
106
109
|
|
|
107
110
|
@property
|
|
108
|
-
def hash(self) ->
|
|
111
|
+
def hash(self) -> str | None:
|
|
109
112
|
return self._hash
|
|
110
113
|
|
|
111
114
|
@hash.setter
|
|
112
|
-
def hash(self, value:
|
|
115
|
+
def hash(self, value: str | None) -> None:
|
|
113
116
|
if value is not None:
|
|
114
117
|
# Auto-populate the hashes key to upgrade to the new format automatically.
|
|
115
118
|
# We don't back-populate the legacy hash key from hashes.
|
|
@@ -127,12 +130,12 @@ class ArchiveInfo:
|
|
|
127
130
|
self._hash = value
|
|
128
131
|
|
|
129
132
|
@classmethod
|
|
130
|
-
def _from_dict(cls, d:
|
|
133
|
+
def _from_dict(cls, d: dict[str, Any] | None) -> ArchiveInfo | None:
|
|
131
134
|
if d is None:
|
|
132
135
|
return None
|
|
133
136
|
return cls(hash=_get(d, str, "hash"), hashes=_get(d, dict, "hashes"))
|
|
134
137
|
|
|
135
|
-
def _to_dict(self) ->
|
|
138
|
+
def _to_dict(self) -> dict[str, Any]:
|
|
136
139
|
return _filter_none(hash=self.hash, hashes=self.hashes)
|
|
137
140
|
|
|
138
141
|
|
|
@@ -143,12 +146,12 @@ class DirInfo:
|
|
|
143
146
|
editable: bool = False
|
|
144
147
|
|
|
145
148
|
@classmethod
|
|
146
|
-
def _from_dict(cls, d:
|
|
149
|
+
def _from_dict(cls, d: dict[str, Any] | None) -> DirInfo | None:
|
|
147
150
|
if d is None:
|
|
148
151
|
return None
|
|
149
152
|
return cls(editable=_get_required(d, bool, "editable", default=False))
|
|
150
153
|
|
|
151
|
-
def _to_dict(self) ->
|
|
154
|
+
def _to_dict(self) -> dict[str, Any]:
|
|
152
155
|
return _filter_none(editable=self.editable or None)
|
|
153
156
|
|
|
154
157
|
|
|
@@ -159,7 +162,7 @@ InfoType = Union[ArchiveInfo, DirInfo, VcsInfo]
|
|
|
159
162
|
class DirectUrl:
|
|
160
163
|
url: str
|
|
161
164
|
info: InfoType
|
|
162
|
-
subdirectory:
|
|
165
|
+
subdirectory: str | None = None
|
|
163
166
|
|
|
164
167
|
def _remove_auth_from_netloc(self, netloc: str) -> str:
|
|
165
168
|
if "@" not in netloc:
|
|
@@ -192,7 +195,7 @@ class DirectUrl:
|
|
|
192
195
|
self.from_dict(self.to_dict())
|
|
193
196
|
|
|
194
197
|
@classmethod
|
|
195
|
-
def from_dict(cls, d:
|
|
198
|
+
def from_dict(cls, d: dict[str, Any]) -> DirectUrl:
|
|
196
199
|
return DirectUrl(
|
|
197
200
|
url=_get_required(d, str, "url"),
|
|
198
201
|
subdirectory=_get(d, str, "subdirectory"),
|
|
@@ -205,7 +208,7 @@ class DirectUrl:
|
|
|
205
208
|
),
|
|
206
209
|
)
|
|
207
210
|
|
|
208
|
-
def to_dict(self) ->
|
|
211
|
+
def to_dict(self) -> dict[str, Any]:
|
|
209
212
|
res = _filter_none(
|
|
210
213
|
url=self.redacted_url,
|
|
211
214
|
subdirectory=self.subdirectory,
|
|
@@ -214,7 +217,7 @@ class DirectUrl:
|
|
|
214
217
|
return res
|
|
215
218
|
|
|
216
219
|
@classmethod
|
|
217
|
-
def from_json(cls, s: str) ->
|
|
220
|
+
def from_json(cls, s: str) -> DirectUrl:
|
|
218
221
|
return cls.from_dict(json.loads(s))
|
|
219
222
|
|
|
220
223
|
def to_json(self) -> str:
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from
|
|
1
|
+
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from pip._vendor.packaging.utils import canonicalize_name
|
|
4
4
|
|
|
@@ -12,8 +12,8 @@ class FormatControl:
|
|
|
12
12
|
|
|
13
13
|
def __init__(
|
|
14
14
|
self,
|
|
15
|
-
no_binary:
|
|
16
|
-
only_binary:
|
|
15
|
+
no_binary: set[str] | None = None,
|
|
16
|
+
only_binary: set[str] | None = None,
|
|
17
17
|
) -> None:
|
|
18
18
|
if no_binary is None:
|
|
19
19
|
no_binary = set()
|
|
@@ -36,7 +36,7 @@ class FormatControl:
|
|
|
36
36
|
return f"{self.__class__.__name__}({self.no_binary}, {self.only_binary})"
|
|
37
37
|
|
|
38
38
|
@staticmethod
|
|
39
|
-
def handle_mutual_excludes(value: str, target:
|
|
39
|
+
def handle_mutual_excludes(value: str, target: set[str], other: set[str]) -> None:
|
|
40
40
|
if value.startswith("-"):
|
|
41
41
|
raise CommandError(
|
|
42
42
|
"--no-binary / --only-binary option requires 1 argument."
|
|
@@ -58,7 +58,7 @@ class FormatControl:
|
|
|
58
58
|
other.discard(name)
|
|
59
59
|
target.add(name)
|
|
60
60
|
|
|
61
|
-
def get_allowed_formats(self, canonical_name: str) ->
|
|
61
|
+
def get_allowed_formats(self, canonical_name: str) -> frozenset[str]:
|
|
62
62
|
result = {"binary", "source"}
|
|
63
63
|
if canonical_name in self.only_binary:
|
|
64
64
|
result.discard("source")
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
from
|
|
1
|
+
from collections.abc import Sequence
|
|
2
|
+
from typing import Any
|
|
2
3
|
|
|
3
4
|
from pip._vendor.packaging.markers import default_environment
|
|
4
5
|
|
|
@@ -11,7 +12,7 @@ class InstallationReport:
|
|
|
11
12
|
self._install_requirements = install_requirements
|
|
12
13
|
|
|
13
14
|
@classmethod
|
|
14
|
-
def _install_req_to_dict(cls, ireq: InstallRequirement) ->
|
|
15
|
+
def _install_req_to_dict(cls, ireq: InstallRequirement) -> dict[str, Any]:
|
|
15
16
|
assert ireq.download_info, f"No download_info for {ireq}"
|
|
16
17
|
res = {
|
|
17
18
|
# PEP 610 json for the download URL. download_info.archive_info.hashes may
|
|
@@ -39,7 +40,7 @@ class InstallationReport:
|
|
|
39
40
|
res["requested_extras"] = sorted(ireq.extras)
|
|
40
41
|
return res
|
|
41
42
|
|
|
42
|
-
def to_dict(self) ->
|
|
43
|
+
def to_dict(self) -> dict[str, Any]:
|
|
43
44
|
return {
|
|
44
45
|
"version": "1",
|
|
45
46
|
"pip_version": __version__,
|
pip/_internal/models/link.py
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import functools
|
|
2
4
|
import itertools
|
|
3
5
|
import logging
|
|
@@ -5,17 +7,12 @@ import os
|
|
|
5
7
|
import posixpath
|
|
6
8
|
import re
|
|
7
9
|
import urllib.parse
|
|
10
|
+
from collections.abc import Mapping
|
|
8
11
|
from dataclasses import dataclass
|
|
9
12
|
from typing import (
|
|
10
13
|
TYPE_CHECKING,
|
|
11
14
|
Any,
|
|
12
|
-
Dict,
|
|
13
|
-
List,
|
|
14
|
-
Mapping,
|
|
15
15
|
NamedTuple,
|
|
16
|
-
Optional,
|
|
17
|
-
Tuple,
|
|
18
|
-
Union,
|
|
19
16
|
)
|
|
20
17
|
|
|
21
18
|
from pip._internal.utils.deprecation import deprecated
|
|
@@ -69,8 +66,8 @@ class LinkHash:
|
|
|
69
66
|
assert self.name in _SUPPORTED_HASHES
|
|
70
67
|
|
|
71
68
|
@classmethod
|
|
72
|
-
@functools.
|
|
73
|
-
def find_hash_url_fragment(cls, url: str) ->
|
|
69
|
+
@functools.cache
|
|
70
|
+
def find_hash_url_fragment(cls, url: str) -> LinkHash | None:
|
|
74
71
|
"""Search a string for a checksum algorithm name and encoded output value."""
|
|
75
72
|
match = cls._hash_url_fragment_re.search(url)
|
|
76
73
|
if match is None:
|
|
@@ -78,14 +75,14 @@ class LinkHash:
|
|
|
78
75
|
name, value = match.groups()
|
|
79
76
|
return cls(name=name, value=value)
|
|
80
77
|
|
|
81
|
-
def as_dict(self) ->
|
|
78
|
+
def as_dict(self) -> dict[str, str]:
|
|
82
79
|
return {self.name: self.value}
|
|
83
80
|
|
|
84
81
|
def as_hashes(self) -> Hashes:
|
|
85
82
|
"""Return a Hashes instance which checks only for the current hash."""
|
|
86
83
|
return Hashes({self.name: [self.value]})
|
|
87
84
|
|
|
88
|
-
def is_hash_allowed(self, hashes:
|
|
85
|
+
def is_hash_allowed(self, hashes: Hashes | None) -> bool:
|
|
89
86
|
"""
|
|
90
87
|
Return True if the current hash is allowed by `hashes`.
|
|
91
88
|
"""
|
|
@@ -98,14 +95,14 @@ class LinkHash:
|
|
|
98
95
|
class MetadataFile:
|
|
99
96
|
"""Information about a core metadata file associated with a distribution."""
|
|
100
97
|
|
|
101
|
-
hashes:
|
|
98
|
+
hashes: dict[str, str] | None
|
|
102
99
|
|
|
103
100
|
def __post_init__(self) -> None:
|
|
104
101
|
if self.hashes is not None:
|
|
105
102
|
assert all(name in _SUPPORTED_HASHES for name in self.hashes)
|
|
106
103
|
|
|
107
104
|
|
|
108
|
-
def supported_hashes(hashes:
|
|
105
|
+
def supported_hashes(hashes: dict[str, str] | None) -> dict[str, str] | None:
|
|
109
106
|
# Remove any unsupported hash types from the mapping. If this leaves no
|
|
110
107
|
# supported hashes, return None
|
|
111
108
|
if hashes is None:
|
|
@@ -134,7 +131,11 @@ def _clean_file_url_path(part: str) -> str:
|
|
|
134
131
|
# should not be quoted. On Linux where drive letters do not
|
|
135
132
|
# exist, the colon should be quoted. We rely on urllib.request
|
|
136
133
|
# to do the right thing here.
|
|
137
|
-
|
|
134
|
+
ret = urllib.request.pathname2url(urllib.request.url2pathname(part))
|
|
135
|
+
if ret.startswith("///"):
|
|
136
|
+
# Remove any URL authority section, leaving only the URL path.
|
|
137
|
+
ret = ret.removeprefix("//")
|
|
138
|
+
return ret
|
|
138
139
|
|
|
139
140
|
|
|
140
141
|
# percent-encoded: /
|
|
@@ -175,7 +176,11 @@ def _ensure_quoted_url(url: str) -> str:
|
|
|
175
176
|
# If the netloc is empty, then the URL refers to a local filesystem path.
|
|
176
177
|
is_local_path = not result.netloc
|
|
177
178
|
path = _clean_url_path(result.path, is_local_path=is_local_path)
|
|
178
|
-
|
|
179
|
+
# Temporarily replace scheme with file to ensure the URL generated by
|
|
180
|
+
# urlunsplit() contains an empty netloc (file://) as per RFC 1738.
|
|
181
|
+
ret = urllib.parse.urlunsplit(result._replace(scheme="file", path=path))
|
|
182
|
+
ret = result.scheme + ret[4:] # Restore original scheme.
|
|
183
|
+
return ret
|
|
179
184
|
|
|
180
185
|
|
|
181
186
|
def _absolute_link_url(base_url: str, url: str) -> str:
|
|
@@ -209,12 +214,12 @@ class Link:
|
|
|
209
214
|
def __init__(
|
|
210
215
|
self,
|
|
211
216
|
url: str,
|
|
212
|
-
comes_from:
|
|
213
|
-
requires_python:
|
|
214
|
-
yanked_reason:
|
|
215
|
-
metadata_file_data:
|
|
217
|
+
comes_from: str | IndexContent | None = None,
|
|
218
|
+
requires_python: str | None = None,
|
|
219
|
+
yanked_reason: str | None = None,
|
|
220
|
+
metadata_file_data: MetadataFile | None = None,
|
|
216
221
|
cache_link_parsing: bool = True,
|
|
217
|
-
hashes:
|
|
222
|
+
hashes: Mapping[str, str] | None = None,
|
|
218
223
|
) -> None:
|
|
219
224
|
"""
|
|
220
225
|
:param url: url of the resource pointed to (href of the link)
|
|
@@ -274,9 +279,9 @@ class Link:
|
|
|
274
279
|
@classmethod
|
|
275
280
|
def from_json(
|
|
276
281
|
cls,
|
|
277
|
-
file_data:
|
|
282
|
+
file_data: dict[str, Any],
|
|
278
283
|
page_url: str,
|
|
279
|
-
) ->
|
|
284
|
+
) -> Link | None:
|
|
280
285
|
"""
|
|
281
286
|
Convert an pypi json document from a simple repository page into a Link.
|
|
282
287
|
"""
|
|
@@ -325,10 +330,10 @@ class Link:
|
|
|
325
330
|
@classmethod
|
|
326
331
|
def from_element(
|
|
327
332
|
cls,
|
|
328
|
-
anchor_attribs:
|
|
333
|
+
anchor_attribs: dict[str, str | None],
|
|
329
334
|
page_url: str,
|
|
330
335
|
base_url: str,
|
|
331
|
-
) ->
|
|
336
|
+
) -> Link | None:
|
|
332
337
|
"""
|
|
333
338
|
Convert an anchor element's attributes in a simple repository page to a Link.
|
|
334
339
|
"""
|
|
@@ -441,7 +446,7 @@ class Link:
|
|
|
441
446
|
def path(self) -> str:
|
|
442
447
|
return self._path
|
|
443
448
|
|
|
444
|
-
def splitext(self) ->
|
|
449
|
+
def splitext(self) -> tuple[str, str]:
|
|
445
450
|
return splitext(posixpath.basename(self.path.rstrip("/")))
|
|
446
451
|
|
|
447
452
|
@property
|
|
@@ -460,7 +465,7 @@ class Link:
|
|
|
460
465
|
r"^([A-Z0-9]|[A-Z0-9][A-Z0-9._-]*[A-Z0-9])$", re.IGNORECASE
|
|
461
466
|
)
|
|
462
467
|
|
|
463
|
-
def _egg_fragment(self) ->
|
|
468
|
+
def _egg_fragment(self) -> str | None:
|
|
464
469
|
match = self._egg_fragment_re.search(self._url)
|
|
465
470
|
if not match:
|
|
466
471
|
return None
|
|
@@ -472,7 +477,7 @@ class Link:
|
|
|
472
477
|
deprecated(
|
|
473
478
|
reason=f"{self} contains an egg fragment with a non-PEP 508 name.",
|
|
474
479
|
replacement="to use the req @ url syntax, and remove the egg fragment",
|
|
475
|
-
gone_in="
|
|
480
|
+
gone_in="26.0",
|
|
476
481
|
issue=13157,
|
|
477
482
|
)
|
|
478
483
|
|
|
@@ -481,13 +486,13 @@ class Link:
|
|
|
481
486
|
_subdirectory_fragment_re = re.compile(r"[#&]subdirectory=([^&]*)")
|
|
482
487
|
|
|
483
488
|
@property
|
|
484
|
-
def subdirectory_fragment(self) ->
|
|
489
|
+
def subdirectory_fragment(self) -> str | None:
|
|
485
490
|
match = self._subdirectory_fragment_re.search(self._url)
|
|
486
491
|
if not match:
|
|
487
492
|
return None
|
|
488
493
|
return match.group(1)
|
|
489
494
|
|
|
490
|
-
def metadata_link(self) ->
|
|
495
|
+
def metadata_link(self) -> Link | None:
|
|
491
496
|
"""Return a link to the associated core metadata file (if any)."""
|
|
492
497
|
if self.metadata_file_data is None:
|
|
493
498
|
return None
|
|
@@ -500,11 +505,11 @@ class Link:
|
|
|
500
505
|
return Hashes({k: [v] for k, v in self._hashes.items()})
|
|
501
506
|
|
|
502
507
|
@property
|
|
503
|
-
def hash(self) ->
|
|
508
|
+
def hash(self) -> str | None:
|
|
504
509
|
return next(iter(self._hashes.values()), None)
|
|
505
510
|
|
|
506
511
|
@property
|
|
507
|
-
def hash_name(self) ->
|
|
512
|
+
def hash_name(self) -> str | None:
|
|
508
513
|
return next(iter(self._hashes), None)
|
|
509
514
|
|
|
510
515
|
@property
|
|
@@ -536,7 +541,7 @@ class Link:
|
|
|
536
541
|
def has_hash(self) -> bool:
|
|
537
542
|
return bool(self._hashes)
|
|
538
543
|
|
|
539
|
-
def is_hash_allowed(self, hashes:
|
|
544
|
+
def is_hash_allowed(self, hashes: Hashes | None) -> bool:
|
|
540
545
|
"""
|
|
541
546
|
Return True if the link has a hash and it is allowed by `hashes`.
|
|
542
547
|
"""
|
|
@@ -572,9 +577,9 @@ class _CleanResult(NamedTuple):
|
|
|
572
577
|
"""
|
|
573
578
|
|
|
574
579
|
parsed: urllib.parse.SplitResult
|
|
575
|
-
query:
|
|
580
|
+
query: dict[str, list[str]]
|
|
576
581
|
subdirectory: str
|
|
577
|
-
hashes:
|
|
582
|
+
hashes: dict[str, str]
|
|
578
583
|
|
|
579
584
|
|
|
580
585
|
def _clean_link(link: Link) -> _CleanResult:
|
|
@@ -603,6 +608,6 @@ def _clean_link(link: Link) -> _CleanResult:
|
|
|
603
608
|
)
|
|
604
609
|
|
|
605
610
|
|
|
606
|
-
@functools.
|
|
611
|
+
@functools.cache
|
|
607
612
|
def links_equivalent(link1: Link, link2: Link) -> bool:
|
|
608
613
|
return _clean_link(link1) == _clean_link(link2)
|