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/network/utils.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from
|
|
1
|
+
from collections.abc import Generator
|
|
2
2
|
|
|
3
3
|
from pip._vendor.requests.models import Response
|
|
4
4
|
|
|
@@ -23,7 +23,7 @@ from pip._internal.exceptions import NetworkConnectionError
|
|
|
23
23
|
# you're not asking for a compressed file and will then decompress it
|
|
24
24
|
# before sending because if that's the case I don't think it'll ever be
|
|
25
25
|
# possible to make this work.
|
|
26
|
-
HEADERS:
|
|
26
|
+
HEADERS: dict[str, str] = {"Accept-Encoding": "identity"}
|
|
27
27
|
|
|
28
28
|
DOWNLOAD_CHUNK_SIZE = 256 * 1024
|
|
29
29
|
|
pip/_internal/network/xmlrpc.py
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import logging
|
|
4
4
|
import urllib.parse
|
|
5
5
|
import xmlrpc.client
|
|
6
|
-
from typing import TYPE_CHECKING
|
|
6
|
+
from typing import TYPE_CHECKING
|
|
7
7
|
|
|
8
8
|
from pip._internal.exceptions import NetworkConnectionError
|
|
9
9
|
from pip._internal.network.session import PipSession
|
|
@@ -36,7 +36,7 @@ class PipXmlrpcTransport(xmlrpc.client.Transport):
|
|
|
36
36
|
handler: str,
|
|
37
37
|
request_body: "SizedBuffer",
|
|
38
38
|
verbose: bool = False,
|
|
39
|
-
) ->
|
|
39
|
+
) -> tuple["_Marshallable", ...]:
|
|
40
40
|
assert isinstance(host, str)
|
|
41
41
|
parts = (self._scheme, host, handler, None, None, None)
|
|
42
42
|
url = urllib.parse.urlunparse(parts)
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import contextlib
|
|
2
4
|
import hashlib
|
|
3
5
|
import logging
|
|
4
6
|
import os
|
|
7
|
+
from collections.abc import Generator
|
|
5
8
|
from types import TracebackType
|
|
6
|
-
from typing import Dict, Generator, Optional, Type, Union
|
|
7
9
|
|
|
8
10
|
from pip._internal.req.req_install import InstallRequirement
|
|
9
11
|
from pip._internal.utils.temp_dir import TempDirectory
|
|
@@ -17,7 +19,7 @@ def update_env_context_manager(**changes: str) -> Generator[None, None, None]:
|
|
|
17
19
|
|
|
18
20
|
# Save values from the target and change them.
|
|
19
21
|
non_existent_marker = object()
|
|
20
|
-
saved_values:
|
|
22
|
+
saved_values: dict[str, object | str] = {}
|
|
21
23
|
for name, new_value in changes.items():
|
|
22
24
|
try:
|
|
23
25
|
saved_values[name] = target[name]
|
|
@@ -38,7 +40,7 @@ def update_env_context_manager(**changes: str) -> Generator[None, None, None]:
|
|
|
38
40
|
|
|
39
41
|
|
|
40
42
|
@contextlib.contextmanager
|
|
41
|
-
def get_build_tracker() -> Generator[
|
|
43
|
+
def get_build_tracker() -> Generator[BuildTracker, None, None]:
|
|
42
44
|
root = os.environ.get("PIP_BUILD_TRACKER")
|
|
43
45
|
with contextlib.ExitStack() as ctx:
|
|
44
46
|
if root is None:
|
|
@@ -65,18 +67,18 @@ class BuildTracker:
|
|
|
65
67
|
|
|
66
68
|
def __init__(self, root: str) -> None:
|
|
67
69
|
self._root = root
|
|
68
|
-
self._entries:
|
|
70
|
+
self._entries: dict[TrackerId, InstallRequirement] = {}
|
|
69
71
|
logger.debug("Created build tracker: %s", self._root)
|
|
70
72
|
|
|
71
|
-
def __enter__(self) ->
|
|
73
|
+
def __enter__(self) -> BuildTracker:
|
|
72
74
|
logger.debug("Entered build tracker: %s", self._root)
|
|
73
75
|
return self
|
|
74
76
|
|
|
75
77
|
def __exit__(
|
|
76
78
|
self,
|
|
77
|
-
exc_type:
|
|
78
|
-
exc_val:
|
|
79
|
-
exc_tb:
|
|
79
|
+
exc_type: type[BaseException] | None,
|
|
80
|
+
exc_val: BaseException | None,
|
|
81
|
+
exc_tb: TracebackType | None,
|
|
80
82
|
) -> None:
|
|
81
83
|
self.cleanup()
|
|
82
84
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import logging
|
|
2
4
|
import os
|
|
3
|
-
from typing import Optional
|
|
4
5
|
|
|
5
6
|
from pip._vendor.pyproject_hooks import BuildBackendHookCaller
|
|
6
7
|
|
|
@@ -13,25 +14,25 @@ def build_wheel_pep517(
|
|
|
13
14
|
name: str,
|
|
14
15
|
backend: BuildBackendHookCaller,
|
|
15
16
|
metadata_directory: str,
|
|
16
|
-
|
|
17
|
-
) ->
|
|
17
|
+
wheel_directory: str,
|
|
18
|
+
) -> str | None:
|
|
18
19
|
"""Build one InstallRequirement using the PEP 517 build process.
|
|
19
20
|
|
|
20
21
|
Returns path to wheel if successfully built. Otherwise, returns None.
|
|
21
22
|
"""
|
|
22
23
|
assert metadata_directory is not None
|
|
23
24
|
try:
|
|
24
|
-
logger.debug("Destination directory: %s",
|
|
25
|
+
logger.debug("Destination directory: %s", wheel_directory)
|
|
25
26
|
|
|
26
27
|
runner = runner_with_spinner_message(
|
|
27
28
|
f"Building wheel for {name} (pyproject.toml)"
|
|
28
29
|
)
|
|
29
30
|
with backend.subprocess_runner(runner):
|
|
30
31
|
wheel_name = backend.build_wheel(
|
|
31
|
-
|
|
32
|
+
wheel_directory=wheel_directory,
|
|
32
33
|
metadata_directory=metadata_directory,
|
|
33
34
|
)
|
|
34
35
|
except Exception:
|
|
35
36
|
logger.error("Failed building wheel for %s", name)
|
|
36
37
|
return None
|
|
37
|
-
return os.path.join(
|
|
38
|
+
return os.path.join(wheel_directory, wheel_name)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import logging
|
|
2
4
|
import os
|
|
3
|
-
from typing import Optional
|
|
4
5
|
|
|
5
6
|
from pip._vendor.pyproject_hooks import BuildBackendHookCaller, HookMissing
|
|
6
7
|
|
|
@@ -13,15 +14,15 @@ def build_wheel_editable(
|
|
|
13
14
|
name: str,
|
|
14
15
|
backend: BuildBackendHookCaller,
|
|
15
16
|
metadata_directory: str,
|
|
16
|
-
|
|
17
|
-
) ->
|
|
17
|
+
wheel_directory: str,
|
|
18
|
+
) -> str | None:
|
|
18
19
|
"""Build one InstallRequirement using the PEP 660 build process.
|
|
19
20
|
|
|
20
21
|
Returns path to wheel if successfully built. Otherwise, returns None.
|
|
21
22
|
"""
|
|
22
23
|
assert metadata_directory is not None
|
|
23
24
|
try:
|
|
24
|
-
logger.debug("Destination directory: %s",
|
|
25
|
+
logger.debug("Destination directory: %s", wheel_directory)
|
|
25
26
|
|
|
26
27
|
runner = runner_with_spinner_message(
|
|
27
28
|
f"Building editable for {name} (pyproject.toml)"
|
|
@@ -29,7 +30,7 @@ def build_wheel_editable(
|
|
|
29
30
|
with backend.subprocess_runner(runner):
|
|
30
31
|
try:
|
|
31
32
|
wheel_name = backend.build_editable(
|
|
32
|
-
|
|
33
|
+
wheel_directory=wheel_directory,
|
|
33
34
|
metadata_directory=metadata_directory,
|
|
34
35
|
)
|
|
35
36
|
except HookMissing as e:
|
|
@@ -43,4 +44,4 @@ def build_wheel_editable(
|
|
|
43
44
|
except Exception:
|
|
44
45
|
logger.error("Failed building editable for %s", name)
|
|
45
46
|
return None
|
|
46
|
-
return os.path.join(
|
|
47
|
+
return os.path.join(wheel_directory, wheel_name)
|
|
@@ -1,20 +1,15 @@
|
|
|
1
1
|
"""Validation of dependencies of packages"""
|
|
2
2
|
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
3
5
|
import logging
|
|
6
|
+
from collections.abc import Generator, Iterable
|
|
4
7
|
from contextlib import suppress
|
|
5
8
|
from email.parser import Parser
|
|
6
9
|
from functools import reduce
|
|
7
10
|
from typing import (
|
|
8
11
|
Callable,
|
|
9
|
-
Dict,
|
|
10
|
-
FrozenSet,
|
|
11
|
-
Generator,
|
|
12
|
-
Iterable,
|
|
13
|
-
List,
|
|
14
12
|
NamedTuple,
|
|
15
|
-
Optional,
|
|
16
|
-
Set,
|
|
17
|
-
Tuple,
|
|
18
13
|
)
|
|
19
14
|
|
|
20
15
|
from pip._vendor.packaging.requirements import Requirement
|
|
@@ -32,21 +27,21 @@ logger = logging.getLogger(__name__)
|
|
|
32
27
|
|
|
33
28
|
class PackageDetails(NamedTuple):
|
|
34
29
|
version: Version
|
|
35
|
-
dependencies:
|
|
30
|
+
dependencies: list[Requirement]
|
|
36
31
|
|
|
37
32
|
|
|
38
33
|
# Shorthands
|
|
39
|
-
PackageSet =
|
|
40
|
-
Missing =
|
|
41
|
-
Conflicting =
|
|
34
|
+
PackageSet = dict[NormalizedName, PackageDetails]
|
|
35
|
+
Missing = tuple[NormalizedName, Requirement]
|
|
36
|
+
Conflicting = tuple[NormalizedName, Version, Requirement]
|
|
42
37
|
|
|
43
|
-
MissingDict =
|
|
44
|
-
ConflictingDict =
|
|
45
|
-
CheckResult =
|
|
46
|
-
ConflictDetails =
|
|
38
|
+
MissingDict = dict[NormalizedName, list[Missing]]
|
|
39
|
+
ConflictingDict = dict[NormalizedName, list[Conflicting]]
|
|
40
|
+
CheckResult = tuple[MissingDict, ConflictingDict]
|
|
41
|
+
ConflictDetails = tuple[PackageSet, CheckResult]
|
|
47
42
|
|
|
48
43
|
|
|
49
|
-
def create_package_set_from_installed() ->
|
|
44
|
+
def create_package_set_from_installed() -> tuple[PackageSet, bool]:
|
|
50
45
|
"""Converts a list of distributions into a PackageSet."""
|
|
51
46
|
package_set = {}
|
|
52
47
|
problems = False
|
|
@@ -64,7 +59,7 @@ def create_package_set_from_installed() -> Tuple[PackageSet, bool]:
|
|
|
64
59
|
|
|
65
60
|
|
|
66
61
|
def check_package_set(
|
|
67
|
-
package_set: PackageSet, should_ignore:
|
|
62
|
+
package_set: PackageSet, should_ignore: Callable[[str], bool] | None = None
|
|
68
63
|
) -> CheckResult:
|
|
69
64
|
"""Check if a package set is consistent
|
|
70
65
|
|
|
@@ -77,8 +72,8 @@ def check_package_set(
|
|
|
77
72
|
|
|
78
73
|
for package_name, package_detail in package_set.items():
|
|
79
74
|
# Info about dependencies of package_name
|
|
80
|
-
missing_deps:
|
|
81
|
-
conflicting_deps:
|
|
75
|
+
missing_deps: set[Missing] = set()
|
|
76
|
+
conflicting_deps: set[Conflicting] = set()
|
|
82
77
|
|
|
83
78
|
if should_ignore and should_ignore(package_name):
|
|
84
79
|
continue
|
|
@@ -108,7 +103,7 @@ def check_package_set(
|
|
|
108
103
|
return missing, conflicting
|
|
109
104
|
|
|
110
105
|
|
|
111
|
-
def check_install_conflicts(to_install:
|
|
106
|
+
def check_install_conflicts(to_install: list[InstallRequirement]) -> ConflictDetails:
|
|
112
107
|
"""For checking if the dependency graph would be consistent after \
|
|
113
108
|
installing given requirements
|
|
114
109
|
"""
|
|
@@ -135,7 +130,7 @@ def check_unsupported(
|
|
|
135
130
|
for p in packages:
|
|
136
131
|
with suppress(FileNotFoundError):
|
|
137
132
|
wheel_file = p.read_text("WHEEL")
|
|
138
|
-
wheel_tags:
|
|
133
|
+
wheel_tags: frozenset[Tag] = reduce(
|
|
139
134
|
frozenset.union,
|
|
140
135
|
map(parse_tag, Parser().parsestr(wheel_file).get_all("Tag", [])),
|
|
141
136
|
frozenset(),
|
|
@@ -145,8 +140,8 @@ def check_unsupported(
|
|
|
145
140
|
|
|
146
141
|
|
|
147
142
|
def _simulate_installation_of(
|
|
148
|
-
to_install:
|
|
149
|
-
) ->
|
|
143
|
+
to_install: list[InstallRequirement], package_set: PackageSet
|
|
144
|
+
) -> set[NormalizedName]:
|
|
150
145
|
"""Computes the version of packages after installing to_install."""
|
|
151
146
|
# Keep track of packages that were installed
|
|
152
147
|
installed = set()
|
|
@@ -164,8 +159,8 @@ def _simulate_installation_of(
|
|
|
164
159
|
|
|
165
160
|
|
|
166
161
|
def _create_whitelist(
|
|
167
|
-
would_be_installed:
|
|
168
|
-
) ->
|
|
162
|
+
would_be_installed: set[NormalizedName], package_set: PackageSet
|
|
163
|
+
) -> set[NormalizedName]:
|
|
169
164
|
packages_affected = set(would_be_installed)
|
|
170
165
|
|
|
171
166
|
for package_name in package_set:
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import collections
|
|
2
4
|
import logging
|
|
3
5
|
import os
|
|
6
|
+
from collections.abc import Container, Generator, Iterable
|
|
4
7
|
from dataclasses import dataclass, field
|
|
5
|
-
from typing import
|
|
8
|
+
from typing import NamedTuple
|
|
6
9
|
|
|
7
10
|
from pip._vendor.packaging.utils import NormalizedName, canonicalize_name
|
|
8
11
|
from pip._vendor.packaging.version import InvalidVersion
|
|
@@ -21,19 +24,19 @@ logger = logging.getLogger(__name__)
|
|
|
21
24
|
|
|
22
25
|
class _EditableInfo(NamedTuple):
|
|
23
26
|
requirement: str
|
|
24
|
-
comments:
|
|
27
|
+
comments: list[str]
|
|
25
28
|
|
|
26
29
|
|
|
27
30
|
def freeze(
|
|
28
|
-
requirement:
|
|
31
|
+
requirement: list[str] | None = None,
|
|
29
32
|
local_only: bool = False,
|
|
30
33
|
user_only: bool = False,
|
|
31
|
-
paths:
|
|
34
|
+
paths: list[str] | None = None,
|
|
32
35
|
isolated: bool = False,
|
|
33
36
|
exclude_editable: bool = False,
|
|
34
37
|
skip: Container[str] = (),
|
|
35
38
|
) -> Generator[str, None, None]:
|
|
36
|
-
installations:
|
|
39
|
+
installations: dict[str, FrozenRequirement] = {}
|
|
37
40
|
|
|
38
41
|
dists = get_environment(paths).iter_installed_distributions(
|
|
39
42
|
local_only=local_only,
|
|
@@ -51,10 +54,10 @@ def freeze(
|
|
|
51
54
|
# should only be emitted once, even if the same option is in multiple
|
|
52
55
|
# requirements files, so we need to keep track of what has been emitted
|
|
53
56
|
# so that we don't emit it again if it's seen again
|
|
54
|
-
emitted_options:
|
|
57
|
+
emitted_options: set[str] = set()
|
|
55
58
|
# keep track of which files a requirement is in so that we can
|
|
56
59
|
# give an accurate warning if a requirement appears multiple times.
|
|
57
|
-
req_files:
|
|
60
|
+
req_files: dict[str, list[str]] = collections.defaultdict(list)
|
|
58
61
|
for req_file_path in requirement:
|
|
59
62
|
with open(req_file_path) as req_file:
|
|
60
63
|
for line in req_file:
|
|
@@ -83,7 +86,7 @@ def freeze(
|
|
|
83
86
|
yield line
|
|
84
87
|
continue
|
|
85
88
|
|
|
86
|
-
if line.startswith("-e"
|
|
89
|
+
if line.startswith(("-e", "--editable")):
|
|
87
90
|
if line.startswith("-e"):
|
|
88
91
|
line = line[2:].strip()
|
|
89
92
|
else:
|
|
@@ -233,7 +236,7 @@ class FrozenRequirement:
|
|
|
233
236
|
return canonicalize_name(self.name)
|
|
234
237
|
|
|
235
238
|
@classmethod
|
|
236
|
-
def from_dist(cls, dist: BaseDistribution) ->
|
|
239
|
+
def from_dist(cls, dist: BaseDistribution) -> FrozenRequirement:
|
|
237
240
|
editable = dist.editable
|
|
238
241
|
if editable:
|
|
239
242
|
req, comments = _get_editable_info(dist)
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
"""Support for installing and building the "wheel" binary package format."""
|
|
2
2
|
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
3
5
|
import collections
|
|
4
6
|
import compileall
|
|
5
7
|
import contextlib
|
|
@@ -10,8 +12,10 @@ import os.path
|
|
|
10
12
|
import re
|
|
11
13
|
import shutil
|
|
12
14
|
import sys
|
|
15
|
+
import textwrap
|
|
13
16
|
import warnings
|
|
14
17
|
from base64 import urlsafe_b64encode
|
|
18
|
+
from collections.abc import Generator, Iterable, Iterator, Sequence
|
|
15
19
|
from email.message import Message
|
|
16
20
|
from itertools import chain, filterfalse, starmap
|
|
17
21
|
from typing import (
|
|
@@ -19,17 +23,8 @@ from typing import (
|
|
|
19
23
|
Any,
|
|
20
24
|
BinaryIO,
|
|
21
25
|
Callable,
|
|
22
|
-
Dict,
|
|
23
|
-
Generator,
|
|
24
|
-
Iterable,
|
|
25
|
-
Iterator,
|
|
26
|
-
List,
|
|
27
26
|
NewType,
|
|
28
|
-
Optional,
|
|
29
27
|
Protocol,
|
|
30
|
-
Sequence,
|
|
31
|
-
Set,
|
|
32
|
-
Tuple,
|
|
33
28
|
Union,
|
|
34
29
|
cast,
|
|
35
30
|
)
|
|
@@ -60,7 +55,7 @@ from pip._internal.utils.wheel import parse_wheel
|
|
|
60
55
|
|
|
61
56
|
|
|
62
57
|
class File(Protocol):
|
|
63
|
-
src_record_path:
|
|
58
|
+
src_record_path: RecordPath
|
|
64
59
|
dest_path: str
|
|
65
60
|
changed: bool
|
|
66
61
|
|
|
@@ -71,17 +66,17 @@ class File(Protocol):
|
|
|
71
66
|
logger = logging.getLogger(__name__)
|
|
72
67
|
|
|
73
68
|
RecordPath = NewType("RecordPath", str)
|
|
74
|
-
InstalledCSVRow =
|
|
69
|
+
InstalledCSVRow = tuple[RecordPath, str, Union[int, str]]
|
|
75
70
|
|
|
76
71
|
|
|
77
|
-
def rehash(path: str, blocksize: int = 1 << 20) ->
|
|
72
|
+
def rehash(path: str, blocksize: int = 1 << 20) -> tuple[str, str]:
|
|
78
73
|
"""Return (encoded_digest, length) for path using hashlib.sha256()"""
|
|
79
74
|
h, length = hash_file(path, blocksize)
|
|
80
75
|
digest = "sha256=" + urlsafe_b64encode(h.digest()).decode("latin1").rstrip("=")
|
|
81
76
|
return (digest, str(length))
|
|
82
77
|
|
|
83
78
|
|
|
84
|
-
def csv_io_kwargs(mode: str) ->
|
|
79
|
+
def csv_io_kwargs(mode: str) -> dict[str, Any]:
|
|
85
80
|
"""Return keyword arguments to properly open a CSV file
|
|
86
81
|
in the given mode.
|
|
87
82
|
"""
|
|
@@ -112,7 +107,7 @@ def wheel_root_is_purelib(metadata: Message) -> bool:
|
|
|
112
107
|
return metadata.get("Root-Is-Purelib", "").lower() == "true"
|
|
113
108
|
|
|
114
109
|
|
|
115
|
-
def get_entrypoints(dist: BaseDistribution) ->
|
|
110
|
+
def get_entrypoints(dist: BaseDistribution) -> tuple[dict[str, str], dict[str, str]]:
|
|
116
111
|
console_scripts = {}
|
|
117
112
|
gui_scripts = {}
|
|
118
113
|
for entry_point in dist.iter_entry_points():
|
|
@@ -123,7 +118,7 @@ def get_entrypoints(dist: BaseDistribution) -> Tuple[Dict[str, str], Dict[str, s
|
|
|
123
118
|
return console_scripts, gui_scripts
|
|
124
119
|
|
|
125
120
|
|
|
126
|
-
def message_about_scripts_not_on_PATH(scripts: Sequence[str]) ->
|
|
121
|
+
def message_about_scripts_not_on_PATH(scripts: Sequence[str]) -> str | None:
|
|
127
122
|
"""Determine if any scripts are not on PATH and format a warning.
|
|
128
123
|
Returns a warning message if one or more scripts are not on PATH,
|
|
129
124
|
otherwise None.
|
|
@@ -132,7 +127,7 @@ def message_about_scripts_not_on_PATH(scripts: Sequence[str]) -> Optional[str]:
|
|
|
132
127
|
return None
|
|
133
128
|
|
|
134
129
|
# Group scripts by the path they were installed in
|
|
135
|
-
grouped_by_dir:
|
|
130
|
+
grouped_by_dir: dict[str, set[str]] = collections.defaultdict(set)
|
|
136
131
|
for destfile in scripts:
|
|
137
132
|
parent_dir = os.path.dirname(destfile)
|
|
138
133
|
script_name = os.path.basename(destfile)
|
|
@@ -148,7 +143,7 @@ def message_about_scripts_not_on_PATH(scripts: Sequence[str]) -> Optional[str]:
|
|
|
148
143
|
not_warn_dirs.append(
|
|
149
144
|
os.path.normcase(os.path.normpath(os.path.dirname(sys.executable)))
|
|
150
145
|
)
|
|
151
|
-
warn_for:
|
|
146
|
+
warn_for: dict[str, set[str]] = {
|
|
152
147
|
parent_dir: scripts
|
|
153
148
|
for parent_dir, scripts in grouped_by_dir.items()
|
|
154
149
|
if os.path.normcase(os.path.normpath(parent_dir)) not in not_warn_dirs
|
|
@@ -159,7 +154,7 @@ def message_about_scripts_not_on_PATH(scripts: Sequence[str]) -> Optional[str]:
|
|
|
159
154
|
# Format a message
|
|
160
155
|
msg_lines = []
|
|
161
156
|
for parent_dir, dir_scripts in warn_for.items():
|
|
162
|
-
sorted_scripts:
|
|
157
|
+
sorted_scripts: list[str] = sorted(dir_scripts)
|
|
163
158
|
if len(sorted_scripts) == 1:
|
|
164
159
|
start_text = f"script {sorted_scripts[0]} is"
|
|
165
160
|
else:
|
|
@@ -197,7 +192,7 @@ def message_about_scripts_not_on_PATH(scripts: Sequence[str]) -> Optional[str]:
|
|
|
197
192
|
|
|
198
193
|
def _normalized_outrows(
|
|
199
194
|
outrows: Iterable[InstalledCSVRow],
|
|
200
|
-
) ->
|
|
195
|
+
) -> list[tuple[str, str, str]]:
|
|
201
196
|
"""Normalize the given rows of a RECORD file.
|
|
202
197
|
|
|
203
198
|
Items in each row are converted into str. Rows are then sorted to make
|
|
@@ -236,17 +231,17 @@ def _fs_to_record_path(path: str, lib_dir: str) -> RecordPath:
|
|
|
236
231
|
|
|
237
232
|
|
|
238
233
|
def get_csv_rows_for_installed(
|
|
239
|
-
old_csv_rows:
|
|
240
|
-
installed:
|
|
241
|
-
changed:
|
|
242
|
-
generated:
|
|
234
|
+
old_csv_rows: list[list[str]],
|
|
235
|
+
installed: dict[RecordPath, RecordPath],
|
|
236
|
+
changed: set[RecordPath],
|
|
237
|
+
generated: list[str],
|
|
243
238
|
lib_dir: str,
|
|
244
|
-
) ->
|
|
239
|
+
) -> list[InstalledCSVRow]:
|
|
245
240
|
"""
|
|
246
241
|
:param installed: A map from archive RECORD path to installation RECORD
|
|
247
242
|
path.
|
|
248
243
|
"""
|
|
249
|
-
installed_rows:
|
|
244
|
+
installed_rows: list[InstalledCSVRow] = []
|
|
250
245
|
for row in old_csv_rows:
|
|
251
246
|
if len(row) > 3:
|
|
252
247
|
logger.warning("RECORD line has more than three elements: %s", row)
|
|
@@ -267,7 +262,7 @@ def get_csv_rows_for_installed(
|
|
|
267
262
|
]
|
|
268
263
|
|
|
269
264
|
|
|
270
|
-
def get_console_script_specs(console:
|
|
265
|
+
def get_console_script_specs(console: dict[str, str]) -> list[str]:
|
|
271
266
|
"""
|
|
272
267
|
Given the mapping from entrypoint name to callable, return the relevant
|
|
273
268
|
console script specs.
|
|
@@ -381,7 +376,7 @@ class ZipBackedFile:
|
|
|
381
376
|
|
|
382
377
|
|
|
383
378
|
class ScriptFile:
|
|
384
|
-
def __init__(self, file:
|
|
379
|
+
def __init__(self, file: File) -> None:
|
|
385
380
|
self._file = file
|
|
386
381
|
self.src_record_path = self._file.src_record_path
|
|
387
382
|
self.dest_path = self._file.dest_path
|
|
@@ -396,7 +391,7 @@ class MissingCallableSuffix(InstallationError):
|
|
|
396
391
|
def __init__(self, entry_point: str) -> None:
|
|
397
392
|
super().__init__(
|
|
398
393
|
f"Invalid script entry point: {entry_point} - A callable "
|
|
399
|
-
"suffix is required.
|
|
394
|
+
"suffix is required. See https://packaging.python.org/"
|
|
400
395
|
"specifications/entry-points/#use-for-scripts for more "
|
|
401
396
|
"information."
|
|
402
397
|
)
|
|
@@ -409,9 +404,22 @@ def _raise_for_invalid_entrypoint(specification: str) -> None:
|
|
|
409
404
|
|
|
410
405
|
|
|
411
406
|
class PipScriptMaker(ScriptMaker):
|
|
407
|
+
# Override distlib's default script template with one that
|
|
408
|
+
# doesn't import `re` module, allowing scripts to load faster.
|
|
409
|
+
script_template = textwrap.dedent(
|
|
410
|
+
"""\
|
|
411
|
+
import sys
|
|
412
|
+
from %(module)s import %(import_name)s
|
|
413
|
+
if __name__ == '__main__':
|
|
414
|
+
if sys.argv[0].endswith('.exe'):
|
|
415
|
+
sys.argv[0] = sys.argv[0][:-4]
|
|
416
|
+
sys.exit(%(func)s())
|
|
417
|
+
"""
|
|
418
|
+
)
|
|
419
|
+
|
|
412
420
|
def make(
|
|
413
|
-
self, specification: str, options:
|
|
414
|
-
) ->
|
|
421
|
+
self, specification: str, options: dict[str, Any] | None = None
|
|
422
|
+
) -> list[str]:
|
|
415
423
|
_raise_for_invalid_entrypoint(specification)
|
|
416
424
|
return super().make(specification, options)
|
|
417
425
|
|
|
@@ -423,7 +431,7 @@ def _install_wheel( # noqa: C901, PLR0915 function is too long
|
|
|
423
431
|
scheme: Scheme,
|
|
424
432
|
pycompile: bool = True,
|
|
425
433
|
warn_script_location: bool = True,
|
|
426
|
-
direct_url:
|
|
434
|
+
direct_url: DirectUrl | None = None,
|
|
427
435
|
requested: bool = False,
|
|
428
436
|
) -> None:
|
|
429
437
|
"""Install a wheel.
|
|
@@ -452,9 +460,9 @@ def _install_wheel( # noqa: C901, PLR0915 function is too long
|
|
|
452
460
|
# installed = files copied from the wheel to the destination
|
|
453
461
|
# changed = files changed while installing (scripts #! line typically)
|
|
454
462
|
# generated = files newly generated during the install (script wrappers)
|
|
455
|
-
installed:
|
|
456
|
-
changed:
|
|
457
|
-
generated:
|
|
463
|
+
installed: dict[RecordPath, RecordPath] = {}
|
|
464
|
+
changed: set[RecordPath] = set()
|
|
465
|
+
generated: list[str] = []
|
|
458
466
|
|
|
459
467
|
def record_installed(
|
|
460
468
|
srcfile: RecordPath, destfile: str, modified: bool = False
|
|
@@ -480,8 +488,8 @@ def _install_wheel( # noqa: C901, PLR0915 function is too long
|
|
|
480
488
|
|
|
481
489
|
def root_scheme_file_maker(
|
|
482
490
|
zip_file: ZipFile, dest: str
|
|
483
|
-
) -> Callable[[RecordPath],
|
|
484
|
-
def make_root_scheme_file(record_path: RecordPath) ->
|
|
491
|
+
) -> Callable[[RecordPath], File]:
|
|
492
|
+
def make_root_scheme_file(record_path: RecordPath) -> File:
|
|
485
493
|
normed_path = os.path.normpath(record_path)
|
|
486
494
|
dest_path = os.path.join(dest, normed_path)
|
|
487
495
|
assert_no_path_traversal(dest, dest_path)
|
|
@@ -491,10 +499,10 @@ def _install_wheel( # noqa: C901, PLR0915 function is too long
|
|
|
491
499
|
|
|
492
500
|
def data_scheme_file_maker(
|
|
493
501
|
zip_file: ZipFile, scheme: Scheme
|
|
494
|
-
) -> Callable[[RecordPath],
|
|
502
|
+
) -> Callable[[RecordPath], File]:
|
|
495
503
|
scheme_paths = {key: getattr(scheme, key) for key in SCHEME_KEYS}
|
|
496
504
|
|
|
497
|
-
def make_data_scheme_file(record_path: RecordPath) ->
|
|
505
|
+
def make_data_scheme_file(record_path: RecordPath) -> File:
|
|
498
506
|
normed_path = os.path.normpath(record_path)
|
|
499
507
|
try:
|
|
500
508
|
_, scheme_key, dest_subpath = normed_path.split(os.path.sep, 2)
|
|
@@ -526,7 +534,7 @@ def _install_wheel( # noqa: C901, PLR0915 function is too long
|
|
|
526
534
|
def is_data_scheme_path(path: RecordPath) -> bool:
|
|
527
535
|
return path.split("/", 1)[0].endswith(".data")
|
|
528
536
|
|
|
529
|
-
paths = cast(
|
|
537
|
+
paths = cast(list[RecordPath], wheel_zip.namelist())
|
|
530
538
|
file_paths = filterfalse(is_dir_path, paths)
|
|
531
539
|
root_scheme_paths, data_scheme_paths = partition(is_data_scheme_path, file_paths)
|
|
532
540
|
|
|
@@ -552,7 +560,7 @@ def _install_wheel( # noqa: C901, PLR0915 function is too long
|
|
|
552
560
|
)
|
|
553
561
|
console, gui = get_entrypoints(distribution)
|
|
554
562
|
|
|
555
|
-
def is_entrypoint_wrapper(file:
|
|
563
|
+
def is_entrypoint_wrapper(file: File) -> bool:
|
|
556
564
|
# EP, EP.exe and EP-script.py are scripts generated for
|
|
557
565
|
# entry point EP by setuptools
|
|
558
566
|
path = file.dest_path
|
|
@@ -721,7 +729,7 @@ def install_wheel(
|
|
|
721
729
|
req_description: str,
|
|
722
730
|
pycompile: bool = True,
|
|
723
731
|
warn_script_location: bool = True,
|
|
724
|
-
direct_url:
|
|
732
|
+
direct_url: DirectUrl | None = None,
|
|
725
733
|
requested: bool = False,
|
|
726
734
|
) -> None:
|
|
727
735
|
with ZipFile(wheel_path, allowZip64=True) as z:
|