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
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.
|
pip/_internal/models/wheel.py
CHANGED
|
@@ -2,97 +2,38 @@
|
|
|
2
2
|
name that have meaning.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
import
|
|
6
|
-
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from collections.abc import Iterable
|
|
7
8
|
|
|
8
9
|
from pip._vendor.packaging.tags import Tag
|
|
9
|
-
from pip._vendor.packaging.utils import BuildTag, parse_wheel_filename
|
|
10
10
|
from pip._vendor.packaging.utils import (
|
|
11
11
|
InvalidWheelFilename as _PackagingInvalidWheelFilename,
|
|
12
12
|
)
|
|
13
|
+
from pip._vendor.packaging.utils import parse_wheel_filename
|
|
13
14
|
|
|
14
15
|
from pip._internal.exceptions import InvalidWheelFilename
|
|
15
|
-
from pip._internal.utils.deprecation import deprecated
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
class Wheel:
|
|
19
19
|
"""A wheel file"""
|
|
20
20
|
|
|
21
|
-
legacy_wheel_file_re = re.compile(
|
|
22
|
-
r"""^(?P<namever>(?P<name>[^\s-]+?)-(?P<ver>[^\s-]*?))
|
|
23
|
-
((-(?P<build>\d[^-]*?))?-(?P<pyver>[^\s-]+?)-(?P<abi>[^\s-]+?)-(?P<plat>[^\s-]+?)
|
|
24
|
-
\.whl|\.dist-info)$""",
|
|
25
|
-
re.VERBOSE,
|
|
26
|
-
)
|
|
27
|
-
|
|
28
21
|
def __init__(self, filename: str) -> None:
|
|
29
22
|
self.filename = filename
|
|
30
23
|
|
|
31
|
-
# To make mypy happy specify type hints that can come from either
|
|
32
|
-
# parse_wheel_filename or the legacy_wheel_file_re match.
|
|
33
|
-
self.name: str
|
|
34
|
-
self._build_tag: Optional[BuildTag] = None
|
|
35
|
-
|
|
36
24
|
try:
|
|
37
25
|
wheel_info = parse_wheel_filename(filename)
|
|
38
|
-
self.name, _version, self._build_tag, self.file_tags = wheel_info
|
|
39
|
-
self.version = str(_version)
|
|
40
26
|
except _PackagingInvalidWheelFilename as e:
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
reason=(
|
|
48
|
-
f"Wheel filename {filename!r} is not correctly normalised. "
|
|
49
|
-
"Future versions of pip will raise the following error:\n"
|
|
50
|
-
f"{e.args[0]}\n\n"
|
|
51
|
-
),
|
|
52
|
-
replacement=(
|
|
53
|
-
"to rename the wheel to use a correctly normalised "
|
|
54
|
-
"name (this may require updating the version in "
|
|
55
|
-
"the project metadata)"
|
|
56
|
-
),
|
|
57
|
-
gone_in="25.3",
|
|
58
|
-
issue=12938,
|
|
59
|
-
)
|
|
60
|
-
|
|
61
|
-
self.name = legacy_wheel_info.group("name").replace("_", "-")
|
|
62
|
-
self.version = legacy_wheel_info.group("ver").replace("_", "-")
|
|
63
|
-
|
|
64
|
-
# Generate the file tags from the legacy wheel filename
|
|
65
|
-
pyversions = legacy_wheel_info.group("pyver").split(".")
|
|
66
|
-
abis = legacy_wheel_info.group("abi").split(".")
|
|
67
|
-
plats = legacy_wheel_info.group("plat").split(".")
|
|
68
|
-
self.file_tags = frozenset(
|
|
69
|
-
Tag(interpreter=py, abi=abi, platform=plat)
|
|
70
|
-
for py in pyversions
|
|
71
|
-
for abi in abis
|
|
72
|
-
for plat in plats
|
|
73
|
-
)
|
|
74
|
-
|
|
75
|
-
@property
|
|
76
|
-
def build_tag(self) -> BuildTag:
|
|
77
|
-
if self._build_tag is not None:
|
|
78
|
-
return self._build_tag
|
|
79
|
-
|
|
80
|
-
# Parse the build tag from the legacy wheel filename
|
|
81
|
-
legacy_wheel_info = self.legacy_wheel_file_re.match(self.filename)
|
|
82
|
-
assert legacy_wheel_info is not None, "guaranteed by filename validation"
|
|
83
|
-
build_tag = legacy_wheel_info.group("build")
|
|
84
|
-
match = re.match(r"^(\d+)(.*)$", build_tag)
|
|
85
|
-
assert match is not None, "guaranteed by filename validation"
|
|
86
|
-
build_tag_groups = match.groups()
|
|
87
|
-
self._build_tag = (int(build_tag_groups[0]), build_tag_groups[1])
|
|
88
|
-
|
|
89
|
-
return self._build_tag
|
|
90
|
-
|
|
91
|
-
def get_formatted_file_tags(self) -> List[str]:
|
|
27
|
+
raise InvalidWheelFilename(e.args[0]) from None
|
|
28
|
+
|
|
29
|
+
self.name, _version, self.build_tag, self.file_tags = wheel_info
|
|
30
|
+
self.version = str(_version)
|
|
31
|
+
|
|
32
|
+
def get_formatted_file_tags(self) -> list[str]:
|
|
92
33
|
"""Return the wheel's tags as a sorted list of strings."""
|
|
93
34
|
return sorted(str(tag) for tag in self.file_tags)
|
|
94
35
|
|
|
95
|
-
def support_index_min(self, tags:
|
|
36
|
+
def support_index_min(self, tags: list[Tag]) -> int:
|
|
96
37
|
"""Return the lowest index that one of the wheel's file_tag combinations
|
|
97
38
|
achieves in the given list of supported tags.
|
|
98
39
|
|
|
@@ -111,7 +52,7 @@ class Wheel:
|
|
|
111
52
|
raise ValueError()
|
|
112
53
|
|
|
113
54
|
def find_most_preferred_tag(
|
|
114
|
-
self, tags:
|
|
55
|
+
self, tags: list[Tag], tag_to_priority: dict[Tag, int]
|
|
115
56
|
) -> int:
|
|
116
57
|
"""Return the priority of the most preferred tag that one of the wheel's file
|
|
117
58
|
tag combinations achieves in the given list of supported tags using the given
|
pip/_internal/network/auth.py
CHANGED
|
@@ -4,6 +4,8 @@ Contains interface (MultiDomainBasicAuth) and associated glue code for
|
|
|
4
4
|
providing credentials in the context of network requests.
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
7
9
|
import logging
|
|
8
10
|
import os
|
|
9
11
|
import shutil
|
|
@@ -12,10 +14,10 @@ import sysconfig
|
|
|
12
14
|
import typing
|
|
13
15
|
import urllib.parse
|
|
14
16
|
from abc import ABC, abstractmethod
|
|
15
|
-
from functools import
|
|
17
|
+
from functools import cache
|
|
16
18
|
from os.path import commonprefix
|
|
17
19
|
from pathlib import Path
|
|
18
|
-
from typing import Any,
|
|
20
|
+
from typing import Any, NamedTuple
|
|
19
21
|
|
|
20
22
|
from pip._vendor.requests.auth import AuthBase, HTTPBasicAuth
|
|
21
23
|
from pip._vendor.requests.models import Request, Response
|
|
@@ -48,9 +50,7 @@ class KeyRingBaseProvider(ABC):
|
|
|
48
50
|
has_keyring: bool
|
|
49
51
|
|
|
50
52
|
@abstractmethod
|
|
51
|
-
def get_auth_info(
|
|
52
|
-
self, url: str, username: Optional[str]
|
|
53
|
-
) -> Optional[AuthInfo]: ...
|
|
53
|
+
def get_auth_info(self, url: str, username: str | None) -> AuthInfo | None: ...
|
|
54
54
|
|
|
55
55
|
@abstractmethod
|
|
56
56
|
def save_auth_info(self, url: str, username: str, password: str) -> None: ...
|
|
@@ -61,7 +61,7 @@ class KeyRingNullProvider(KeyRingBaseProvider):
|
|
|
61
61
|
|
|
62
62
|
has_keyring = False
|
|
63
63
|
|
|
64
|
-
def get_auth_info(self, url: str, username:
|
|
64
|
+
def get_auth_info(self, url: str, username: str | None) -> AuthInfo | None:
|
|
65
65
|
return None
|
|
66
66
|
|
|
67
67
|
def save_auth_info(self, url: str, username: str, password: str) -> None:
|
|
@@ -78,7 +78,7 @@ class KeyRingPythonProvider(KeyRingBaseProvider):
|
|
|
78
78
|
|
|
79
79
|
self.keyring = keyring
|
|
80
80
|
|
|
81
|
-
def get_auth_info(self, url: str, username:
|
|
81
|
+
def get_auth_info(self, url: str, username: str | None) -> AuthInfo | None:
|
|
82
82
|
# Support keyring's get_credential interface which supports getting
|
|
83
83
|
# credentials without a username. This is only available for
|
|
84
84
|
# keyring>=15.2.0.
|
|
@@ -114,7 +114,7 @@ class KeyRingCliProvider(KeyRingBaseProvider):
|
|
|
114
114
|
def __init__(self, cmd: str) -> None:
|
|
115
115
|
self.keyring = cmd
|
|
116
116
|
|
|
117
|
-
def get_auth_info(self, url: str, username:
|
|
117
|
+
def get_auth_info(self, url: str, username: str | None) -> AuthInfo | None:
|
|
118
118
|
# This is the default implementation of keyring.get_credential
|
|
119
119
|
# https://github.com/jaraco/keyring/blob/97689324abcf01bd1793d49063e7ca01e03d7d07/keyring/backend.py#L134-L139
|
|
120
120
|
if username is not None:
|
|
@@ -126,7 +126,7 @@ class KeyRingCliProvider(KeyRingBaseProvider):
|
|
|
126
126
|
def save_auth_info(self, url: str, username: str, password: str) -> None:
|
|
127
127
|
return self._set_password(url, username, password)
|
|
128
128
|
|
|
129
|
-
def _get_password(self, service_name: str, username: str) ->
|
|
129
|
+
def _get_password(self, service_name: str, username: str) -> str | None:
|
|
130
130
|
"""Mirror the implementation of keyring.get_password using cli"""
|
|
131
131
|
if self.keyring is None:
|
|
132
132
|
return None
|
|
@@ -159,7 +159,7 @@ class KeyRingCliProvider(KeyRingBaseProvider):
|
|
|
159
159
|
return None
|
|
160
160
|
|
|
161
161
|
|
|
162
|
-
@
|
|
162
|
+
@cache
|
|
163
163
|
def get_keyring_provider(provider: str) -> KeyRingBaseProvider:
|
|
164
164
|
logger.verbose("Keyring provider requested: %s", provider)
|
|
165
165
|
|
|
@@ -225,19 +225,19 @@ class MultiDomainBasicAuth(AuthBase):
|
|
|
225
225
|
def __init__(
|
|
226
226
|
self,
|
|
227
227
|
prompting: bool = True,
|
|
228
|
-
index_urls:
|
|
228
|
+
index_urls: list[str] | None = None,
|
|
229
229
|
keyring_provider: str = "auto",
|
|
230
230
|
) -> None:
|
|
231
231
|
self.prompting = prompting
|
|
232
232
|
self.index_urls = index_urls
|
|
233
|
-
self.keyring_provider = keyring_provider
|
|
234
|
-
self.passwords:
|
|
233
|
+
self.keyring_provider = keyring_provider
|
|
234
|
+
self.passwords: dict[str, AuthInfo] = {}
|
|
235
235
|
# When the user is prompted to enter credentials and keyring is
|
|
236
236
|
# available, we will offer to save them. If the user accepts,
|
|
237
237
|
# this value is set to the credentials they entered. After the
|
|
238
238
|
# request authenticates, the caller should call
|
|
239
239
|
# ``save_credentials`` to save these.
|
|
240
|
-
self._credentials_to_save:
|
|
240
|
+
self._credentials_to_save: Credentials | None = None
|
|
241
241
|
|
|
242
242
|
@property
|
|
243
243
|
def keyring_provider(self) -> KeyRingBaseProvider:
|
|
@@ -260,9 +260,9 @@ class MultiDomainBasicAuth(AuthBase):
|
|
|
260
260
|
|
|
261
261
|
def _get_keyring_auth(
|
|
262
262
|
self,
|
|
263
|
-
url:
|
|
264
|
-
username:
|
|
265
|
-
) ->
|
|
263
|
+
url: str | None,
|
|
264
|
+
username: str | None,
|
|
265
|
+
) -> AuthInfo | None:
|
|
266
266
|
"""Return the tuple auth for a given url from keyring."""
|
|
267
267
|
# Do nothing if no url was provided
|
|
268
268
|
if not url:
|
|
@@ -284,7 +284,7 @@ class MultiDomainBasicAuth(AuthBase):
|
|
|
284
284
|
get_keyring_provider.cache_clear()
|
|
285
285
|
return None
|
|
286
286
|
|
|
287
|
-
def _get_index_url(self, url: str) ->
|
|
287
|
+
def _get_index_url(self, url: str) -> str | None:
|
|
288
288
|
"""Return the original index URL matching the requested URL.
|
|
289
289
|
|
|
290
290
|
Cached or dynamically generated credentials may work against
|
|
@@ -391,7 +391,7 @@ class MultiDomainBasicAuth(AuthBase):
|
|
|
391
391
|
|
|
392
392
|
def _get_url_and_credentials(
|
|
393
393
|
self, original_url: str
|
|
394
|
-
) ->
|
|
394
|
+
) -> tuple[str, str | None, str | None]:
|
|
395
395
|
"""Return the credentials to use for the provided URL.
|
|
396
396
|
|
|
397
397
|
If allowed, netrc and keyring may be used to obtain the
|
|
@@ -454,9 +454,7 @@ class MultiDomainBasicAuth(AuthBase):
|
|
|
454
454
|
return req
|
|
455
455
|
|
|
456
456
|
# Factored out to allow for easy patching in tests
|
|
457
|
-
def _prompt_for_password(
|
|
458
|
-
self, netloc: str
|
|
459
|
-
) -> Tuple[Optional[str], Optional[str], bool]:
|
|
457
|
+
def _prompt_for_password(self, netloc: str) -> tuple[str | None, str | None, bool]:
|
|
460
458
|
username = ask_input(f"User for {netloc}: ") if self.prompting else None
|
|
461
459
|
if not username:
|
|
462
460
|
return None, None, False
|
pip/_internal/network/cache.py
CHANGED
|
@@ -1,15 +1,23 @@
|
|
|
1
1
|
"""HTTP cache implementation."""
|
|
2
2
|
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
3
5
|
import os
|
|
6
|
+
import shutil
|
|
7
|
+
from collections.abc import Generator
|
|
4
8
|
from contextlib import contextmanager
|
|
5
9
|
from datetime import datetime
|
|
6
|
-
from typing import
|
|
10
|
+
from typing import Any, BinaryIO, Callable
|
|
7
11
|
|
|
8
12
|
from pip._vendor.cachecontrol.cache import SeparateBodyBaseCache
|
|
9
13
|
from pip._vendor.cachecontrol.caches import SeparateBodyFileCache
|
|
10
14
|
from pip._vendor.requests.models import Response
|
|
11
15
|
|
|
12
|
-
from pip._internal.utils.filesystem import
|
|
16
|
+
from pip._internal.utils.filesystem import (
|
|
17
|
+
adjacent_tmp_file,
|
|
18
|
+
copy_directory_permissions,
|
|
19
|
+
replace,
|
|
20
|
+
)
|
|
13
21
|
from pip._internal.utils.misc import ensure_dir
|
|
14
22
|
|
|
15
23
|
|
|
@@ -59,7 +67,7 @@ class SafeFileCache(SeparateBodyBaseCache):
|
|
|
59
67
|
parts = list(hashed[:5]) + [hashed]
|
|
60
68
|
return os.path.join(self.directory, *parts)
|
|
61
69
|
|
|
62
|
-
def get(self, key: str) ->
|
|
70
|
+
def get(self, key: str) -> bytes | None:
|
|
63
71
|
# The cache entry is only valid if both metadata and body exist.
|
|
64
72
|
metadata_path = self._get_cache_path(key)
|
|
65
73
|
body_path = metadata_path + ".body"
|
|
@@ -69,29 +77,27 @@ class SafeFileCache(SeparateBodyBaseCache):
|
|
|
69
77
|
with open(metadata_path, "rb") as f:
|
|
70
78
|
return f.read()
|
|
71
79
|
|
|
72
|
-
def
|
|
80
|
+
def _write_to_file(self, path: str, writer_func: Callable[[BinaryIO], Any]) -> None:
|
|
81
|
+
"""Common file writing logic with proper permissions and atomic replacement."""
|
|
73
82
|
with suppressed_cache_errors():
|
|
74
83
|
ensure_dir(os.path.dirname(path))
|
|
75
84
|
|
|
76
85
|
with adjacent_tmp_file(path) as f:
|
|
77
|
-
f
|
|
86
|
+
writer_func(f)
|
|
78
87
|
# Inherit the read/write permissions of the cache directory
|
|
79
88
|
# to enable multi-user cache use-cases.
|
|
80
|
-
|
|
81
|
-
os.stat(self.directory).st_mode
|
|
82
|
-
& 0o666 # select read/write permissions of cache directory
|
|
83
|
-
| 0o600 # set owner read/write permissions
|
|
84
|
-
)
|
|
85
|
-
# Change permissions only if there is no risk of following a symlink.
|
|
86
|
-
if os.chmod in os.supports_fd:
|
|
87
|
-
os.chmod(f.fileno(), mode)
|
|
88
|
-
elif os.chmod in os.supports_follow_symlinks:
|
|
89
|
-
os.chmod(f.name, mode, follow_symlinks=False)
|
|
89
|
+
copy_directory_permissions(self.directory, f)
|
|
90
90
|
|
|
91
91
|
replace(f.name, path)
|
|
92
92
|
|
|
93
|
+
def _write(self, path: str, data: bytes) -> None:
|
|
94
|
+
self._write_to_file(path, lambda f: f.write(data))
|
|
95
|
+
|
|
96
|
+
def _write_from_io(self, path: str, source_file: BinaryIO) -> None:
|
|
97
|
+
self._write_to_file(path, lambda f: shutil.copyfileobj(source_file, f))
|
|
98
|
+
|
|
93
99
|
def set(
|
|
94
|
-
self, key: str, value: bytes, expires:
|
|
100
|
+
self, key: str, value: bytes, expires: int | datetime | None = None
|
|
95
101
|
) -> None:
|
|
96
102
|
path = self._get_cache_path(key)
|
|
97
103
|
self._write(path, value)
|
|
@@ -103,7 +109,7 @@ class SafeFileCache(SeparateBodyBaseCache):
|
|
|
103
109
|
with suppressed_cache_errors():
|
|
104
110
|
os.remove(path + ".body")
|
|
105
111
|
|
|
106
|
-
def get_body(self, key: str) ->
|
|
112
|
+
def get_body(self, key: str) -> BinaryIO | None:
|
|
107
113
|
# The cache entry is only valid if both metadata and body exist.
|
|
108
114
|
metadata_path = self._get_cache_path(key)
|
|
109
115
|
body_path = metadata_path + ".body"
|
|
@@ -115,3 +121,8 @@ class SafeFileCache(SeparateBodyBaseCache):
|
|
|
115
121
|
def set_body(self, key: str, body: bytes) -> None:
|
|
116
122
|
path = self._get_cache_path(key) + ".body"
|
|
117
123
|
self._write(path, body)
|
|
124
|
+
|
|
125
|
+
def set_body_from_io(self, key: str, body_file: BinaryIO) -> None:
|
|
126
|
+
"""Set the body of the cache entry from a file object."""
|
|
127
|
+
path = self._get_cache_path(key) + ".body"
|
|
128
|
+
self._write_from_io(path, body_file)
|