pip 25.1.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 +44 -39
- 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 +49 -41
- 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 +7 -11
- 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 +37 -45
- 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/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 +9 -10
- {pip-25.1.1.dist-info → pip-25.2.dist-info}/METADATA +26 -4
- {pip-25.1.1.dist-info → pip-25.2.dist-info}/RECORD +193 -180
- {pip-25.1.1.dist-info → pip-25.2.dist-info}/WHEEL +1 -1
- {pip-25.1.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.1.dist-info → pip-25.2.dist-info}/entry_points.txt +0 -0
- {pip-25.1.1.dist-info → pip-25.2.dist-info}/licenses/LICENSE.txt +0 -0
- {pip-25.1.1.dist-info → pip-25.2.dist-info}/top_level.txt +0 -0
|
@@ -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="25.
|
|
480
|
+
gone_in="25.3",
|
|
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)
|
pip/_internal/models/pylock.py
CHANGED
|
@@ -1,17 +1,22 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import dataclasses
|
|
2
4
|
import re
|
|
5
|
+
from collections.abc import Iterable
|
|
3
6
|
from dataclasses import dataclass
|
|
4
7
|
from pathlib import Path
|
|
5
|
-
from typing import
|
|
8
|
+
from typing import TYPE_CHECKING, Any
|
|
6
9
|
|
|
7
10
|
from pip._vendor import tomli_w
|
|
8
|
-
from pip._vendor.typing_extensions import Self
|
|
9
11
|
|
|
10
12
|
from pip._internal.models.direct_url import ArchiveInfo, DirInfo, VcsInfo
|
|
11
13
|
from pip._internal.models.link import Link
|
|
12
14
|
from pip._internal.req.req_install import InstallRequirement
|
|
13
15
|
from pip._internal.utils.urls import url_to_path
|
|
14
16
|
|
|
17
|
+
if TYPE_CHECKING:
|
|
18
|
+
from typing_extensions import Self
|
|
19
|
+
|
|
15
20
|
PYLOCK_FILE_NAME_RE = re.compile(r"^pylock\.([^.]+)\.toml$")
|
|
16
21
|
|
|
17
22
|
|
|
@@ -19,70 +24,70 @@ def is_valid_pylock_file_name(path: Path) -> bool:
|
|
|
19
24
|
return path.name == "pylock.toml" or bool(re.match(PYLOCK_FILE_NAME_RE, path.name))
|
|
20
25
|
|
|
21
26
|
|
|
22
|
-
def _toml_dict_factory(data:
|
|
27
|
+
def _toml_dict_factory(data: list[tuple[str, Any]]) -> dict[str, Any]:
|
|
23
28
|
return {key.replace("_", "-"): value for key, value in data if value is not None}
|
|
24
29
|
|
|
25
30
|
|
|
26
31
|
@dataclass
|
|
27
32
|
class PackageVcs:
|
|
28
33
|
type: str
|
|
29
|
-
url:
|
|
34
|
+
url: str | None
|
|
30
35
|
# (not supported) path: Optional[str]
|
|
31
|
-
requested_revision:
|
|
36
|
+
requested_revision: str | None
|
|
32
37
|
commit_id: str
|
|
33
|
-
subdirectory:
|
|
38
|
+
subdirectory: str | None
|
|
34
39
|
|
|
35
40
|
|
|
36
41
|
@dataclass
|
|
37
42
|
class PackageDirectory:
|
|
38
43
|
path: str
|
|
39
|
-
editable:
|
|
40
|
-
subdirectory:
|
|
44
|
+
editable: bool | None
|
|
45
|
+
subdirectory: str | None
|
|
41
46
|
|
|
42
47
|
|
|
43
48
|
@dataclass
|
|
44
49
|
class PackageArchive:
|
|
45
|
-
url:
|
|
50
|
+
url: str | None
|
|
46
51
|
# (not supported) path: Optional[str]
|
|
47
52
|
# (not supported) size: Optional[int]
|
|
48
53
|
# (not supported) upload_time: Optional[datetime]
|
|
49
|
-
hashes:
|
|
50
|
-
subdirectory:
|
|
54
|
+
hashes: dict[str, str]
|
|
55
|
+
subdirectory: str | None
|
|
51
56
|
|
|
52
57
|
|
|
53
58
|
@dataclass
|
|
54
59
|
class PackageSdist:
|
|
55
60
|
name: str
|
|
56
61
|
# (not supported) upload_time: Optional[datetime]
|
|
57
|
-
url:
|
|
62
|
+
url: str | None
|
|
58
63
|
# (not supported) path: Optional[str]
|
|
59
64
|
# (not supported) size: Optional[int]
|
|
60
|
-
hashes:
|
|
65
|
+
hashes: dict[str, str]
|
|
61
66
|
|
|
62
67
|
|
|
63
68
|
@dataclass
|
|
64
69
|
class PackageWheel:
|
|
65
70
|
name: str
|
|
66
71
|
# (not supported) upload_time: Optional[datetime]
|
|
67
|
-
url:
|
|
72
|
+
url: str | None
|
|
68
73
|
# (not supported) path: Optional[str]
|
|
69
74
|
# (not supported) size: Optional[int]
|
|
70
|
-
hashes:
|
|
75
|
+
hashes: dict[str, str]
|
|
71
76
|
|
|
72
77
|
|
|
73
78
|
@dataclass
|
|
74
79
|
class Package:
|
|
75
80
|
name: str
|
|
76
|
-
version:
|
|
81
|
+
version: str | None = None
|
|
77
82
|
# (not supported) marker: Optional[str]
|
|
78
83
|
# (not supported) requires_python: Optional[str]
|
|
79
84
|
# (not supported) dependencies
|
|
80
|
-
vcs:
|
|
81
|
-
directory:
|
|
82
|
-
archive:
|
|
85
|
+
vcs: PackageVcs | None = None
|
|
86
|
+
directory: PackageDirectory | None = None
|
|
87
|
+
archive: PackageArchive | None = None
|
|
83
88
|
# (not supported) index: Optional[str]
|
|
84
|
-
sdist:
|
|
85
|
-
wheels:
|
|
89
|
+
sdist: PackageSdist | None = None
|
|
90
|
+
wheels: list[PackageWheel] | None = None
|
|
86
91
|
# (not supported) attestation_identities: Optional[List[Dict[str, Any]]]
|
|
87
92
|
# (not supported) tool: Optional[Dict[str, Any]]
|
|
88
93
|
|
|
@@ -162,7 +167,7 @@ class Pylock:
|
|
|
162
167
|
# (not supported) extras: List[str] = []
|
|
163
168
|
# (not supported) dependency_groups: List[str] = []
|
|
164
169
|
created_by: str = "pip"
|
|
165
|
-
packages:
|
|
170
|
+
packages: list[Package] = dataclasses.field(default_factory=list)
|
|
166
171
|
# (not supported) tool: Optional[Dict[str, Any]]
|
|
167
172
|
|
|
168
173
|
def as_toml(self) -> str:
|
|
@@ -4,7 +4,6 @@ import os
|
|
|
4
4
|
import posixpath
|
|
5
5
|
import urllib.parse
|
|
6
6
|
from dataclasses import dataclass
|
|
7
|
-
from typing import List
|
|
8
7
|
|
|
9
8
|
from pip._vendor.packaging.utils import canonicalize_name
|
|
10
9
|
|
|
@@ -23,15 +22,15 @@ class SearchScope:
|
|
|
23
22
|
|
|
24
23
|
__slots__ = ["find_links", "index_urls", "no_index"]
|
|
25
24
|
|
|
26
|
-
find_links:
|
|
27
|
-
index_urls:
|
|
25
|
+
find_links: list[str]
|
|
26
|
+
index_urls: list[str]
|
|
28
27
|
no_index: bool
|
|
29
28
|
|
|
30
29
|
@classmethod
|
|
31
30
|
def create(
|
|
32
31
|
cls,
|
|
33
|
-
find_links:
|
|
34
|
-
index_urls:
|
|
32
|
+
find_links: list[str],
|
|
33
|
+
index_urls: list[str],
|
|
35
34
|
no_index: bool,
|
|
36
35
|
) -> "SearchScope":
|
|
37
36
|
"""
|
|
@@ -42,7 +41,7 @@ class SearchScope:
|
|
|
42
41
|
# it and if it exists, use the normalized version.
|
|
43
42
|
# This is deliberately conservative - it might be fine just to
|
|
44
43
|
# blindly normalize anything starting with a ~...
|
|
45
|
-
built_find_links:
|
|
44
|
+
built_find_links: list[str] = []
|
|
46
45
|
for link in find_links:
|
|
47
46
|
if link.startswith("~"):
|
|
48
47
|
new_link = normalize_path(link)
|
|
@@ -104,7 +103,7 @@ class SearchScope:
|
|
|
104
103
|
)
|
|
105
104
|
return "\n".join(lines)
|
|
106
105
|
|
|
107
|
-
def get_index_urls_locations(self, project_name: str) ->
|
|
106
|
+
def get_index_urls_locations(self, project_name: str) -> list[str]:
|
|
108
107
|
"""Returns the locations found via self.index_urls
|
|
109
108
|
|
|
110
109
|
Checks the url_name on the main (first in the list) index and
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from
|
|
1
|
+
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from pip._internal.models.format_control import FormatControl
|
|
4
4
|
|
|
@@ -27,9 +27,9 @@ class SelectionPreferences:
|
|
|
27
27
|
self,
|
|
28
28
|
allow_yanked: bool,
|
|
29
29
|
allow_all_prereleases: bool = False,
|
|
30
|
-
format_control:
|
|
30
|
+
format_control: FormatControl | None = None,
|
|
31
31
|
prefer_binary: bool = False,
|
|
32
|
-
ignore_requires_python:
|
|
32
|
+
ignore_requires_python: bool | None = None,
|
|
33
33
|
) -> None:
|
|
34
34
|
"""Create a SelectionPreferences object.
|
|
35
35
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import sys
|
|
2
|
-
from typing import List, Optional, Set, Tuple
|
|
3
4
|
|
|
4
5
|
from pip._vendor.packaging.tags import Tag
|
|
5
6
|
|
|
@@ -26,10 +27,10 @@ class TargetPython:
|
|
|
26
27
|
|
|
27
28
|
def __init__(
|
|
28
29
|
self,
|
|
29
|
-
platforms:
|
|
30
|
-
py_version_info:
|
|
31
|
-
abis:
|
|
32
|
-
implementation:
|
|
30
|
+
platforms: list[str] | None = None,
|
|
31
|
+
py_version_info: tuple[int, ...] | None = None,
|
|
32
|
+
abis: list[str] | None = None,
|
|
33
|
+
implementation: str | None = None,
|
|
33
34
|
) -> None:
|
|
34
35
|
"""
|
|
35
36
|
:param platforms: A list of strings or None. If None, searches for
|
|
@@ -62,8 +63,8 @@ class TargetPython:
|
|
|
62
63
|
self.py_version_info = py_version_info
|
|
63
64
|
|
|
64
65
|
# This is used to cache the return value of get_(un)sorted_tags.
|
|
65
|
-
self._valid_tags:
|
|
66
|
-
self._valid_tags_set:
|
|
66
|
+
self._valid_tags: list[Tag] | None = None
|
|
67
|
+
self._valid_tags_set: set[Tag] | None = None
|
|
67
68
|
|
|
68
69
|
def format_given(self) -> str:
|
|
69
70
|
"""
|
|
@@ -85,7 +86,7 @@ class TargetPython:
|
|
|
85
86
|
f"{key}={value!r}" for key, value in key_values if value is not None
|
|
86
87
|
)
|
|
87
88
|
|
|
88
|
-
def get_sorted_tags(self) ->
|
|
89
|
+
def get_sorted_tags(self) -> list[Tag]:
|
|
89
90
|
"""
|
|
90
91
|
Return the supported PEP 425 tags to check wheel candidates against.
|
|
91
92
|
|
|
@@ -110,7 +111,7 @@ class TargetPython:
|
|
|
110
111
|
|
|
111
112
|
return self._valid_tags
|
|
112
113
|
|
|
113
|
-
def get_unsorted_tags(self) ->
|
|
114
|
+
def get_unsorted_tags(self) -> set[Tag]:
|
|
114
115
|
"""Exactly the same as get_sorted_tags, but returns a set.
|
|
115
116
|
|
|
116
117
|
This is important for performance.
|