pip 25.1__py3-none-any.whl → 25.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pip/__init__.py +3 -3
- pip/_internal/__init__.py +2 -2
- pip/_internal/build_env.py +118 -94
- pip/_internal/cache.py +16 -14
- pip/_internal/cli/autocompletion.py +13 -4
- pip/_internal/cli/base_command.py +18 -7
- pip/_internal/cli/cmdoptions.py +14 -9
- pip/_internal/cli/command_context.py +4 -3
- pip/_internal/cli/index_command.py +11 -9
- pip/_internal/cli/main.py +3 -2
- pip/_internal/cli/main_parser.py +4 -3
- pip/_internal/cli/parser.py +26 -22
- pip/_internal/cli/progress_bars.py +19 -12
- pip/_internal/cli/req_command.py +16 -12
- pip/_internal/cli/spinners.py +81 -5
- pip/_internal/commands/__init__.py +5 -3
- pip/_internal/commands/cache.py +18 -15
- pip/_internal/commands/check.py +1 -2
- pip/_internal/commands/completion.py +1 -2
- pip/_internal/commands/configuration.py +26 -18
- pip/_internal/commands/debug.py +8 -6
- pip/_internal/commands/download.py +2 -3
- pip/_internal/commands/freeze.py +2 -3
- pip/_internal/commands/hash.py +1 -2
- pip/_internal/commands/help.py +1 -2
- pip/_internal/commands/index.py +15 -9
- pip/_internal/commands/inspect.py +4 -4
- pip/_internal/commands/install.py +45 -40
- pip/_internal/commands/list.py +35 -26
- pip/_internal/commands/lock.py +1 -2
- pip/_internal/commands/search.py +14 -12
- pip/_internal/commands/show.py +14 -11
- pip/_internal/commands/uninstall.py +1 -2
- pip/_internal/commands/wheel.py +2 -3
- pip/_internal/configuration.py +39 -25
- pip/_internal/distributions/base.py +6 -4
- pip/_internal/distributions/installed.py +8 -4
- pip/_internal/distributions/sdist.py +20 -13
- pip/_internal/distributions/wheel.py +6 -4
- pip/_internal/exceptions.py +58 -39
- pip/_internal/index/collector.py +24 -29
- pip/_internal/index/package_finder.py +70 -61
- pip/_internal/index/sources.py +17 -14
- pip/_internal/locations/__init__.py +18 -16
- pip/_internal/locations/_distutils.py +12 -11
- pip/_internal/locations/_sysconfig.py +5 -4
- pip/_internal/locations/base.py +4 -3
- pip/_internal/main.py +2 -2
- pip/_internal/metadata/__init__.py +8 -6
- pip/_internal/metadata/_json.py +5 -4
- pip/_internal/metadata/base.py +22 -27
- pip/_internal/metadata/importlib/_compat.py +6 -4
- pip/_internal/metadata/importlib/_dists.py +12 -17
- pip/_internal/metadata/importlib/_envs.py +9 -6
- pip/_internal/metadata/pkg_resources.py +11 -14
- pip/_internal/models/direct_url.py +24 -21
- pip/_internal/models/format_control.py +5 -5
- pip/_internal/models/installation_report.py +4 -3
- pip/_internal/models/link.py +39 -34
- pip/_internal/models/pylock.py +27 -22
- pip/_internal/models/search_scope.py +6 -7
- pip/_internal/models/selection_prefs.py +3 -3
- pip/_internal/models/target_python.py +10 -9
- pip/_internal/models/wheel.py +7 -5
- pip/_internal/network/auth.py +20 -22
- pip/_internal/network/cache.py +22 -6
- pip/_internal/network/download.py +169 -141
- pip/_internal/network/lazy_wheel.py +10 -7
- pip/_internal/network/session.py +32 -27
- pip/_internal/network/utils.py +2 -2
- pip/_internal/network/xmlrpc.py +2 -2
- pip/_internal/operations/build/build_tracker.py +10 -8
- pip/_internal/operations/build/wheel.py +3 -2
- pip/_internal/operations/build/wheel_editable.py +3 -2
- pip/_internal/operations/build/wheel_legacy.py +9 -8
- pip/_internal/operations/check.py +21 -26
- pip/_internal/operations/freeze.py +12 -9
- pip/_internal/operations/install/editable_legacy.py +5 -3
- pip/_internal/operations/install/wheel.py +53 -44
- pip/_internal/operations/prepare.py +35 -30
- pip/_internal/pyproject.py +7 -10
- pip/_internal/req/__init__.py +12 -10
- pip/_internal/req/constructors.py +33 -31
- pip/_internal/req/req_dependency_group.py +9 -8
- pip/_internal/req/req_file.py +32 -35
- pip/_internal/req/req_install.py +37 -34
- pip/_internal/req/req_set.py +4 -5
- pip/_internal/req/req_uninstall.py +20 -17
- pip/_internal/resolution/base.py +3 -3
- pip/_internal/resolution/legacy/resolver.py +21 -20
- pip/_internal/resolution/resolvelib/base.py +16 -13
- pip/_internal/resolution/resolvelib/candidates.py +29 -26
- pip/_internal/resolution/resolvelib/factory.py +41 -50
- pip/_internal/resolution/resolvelib/found_candidates.py +11 -9
- pip/_internal/resolution/resolvelib/provider.py +15 -20
- pip/_internal/resolution/resolvelib/reporter.py +5 -3
- pip/_internal/resolution/resolvelib/requirements.py +8 -6
- pip/_internal/resolution/resolvelib/resolver.py +39 -23
- pip/_internal/self_outdated_check.py +8 -6
- pip/_internal/utils/appdirs.py +1 -2
- pip/_internal/utils/compat.py +7 -1
- pip/_internal/utils/compatibility_tags.py +17 -16
- pip/_internal/utils/deprecation.py +11 -9
- pip/_internal/utils/direct_url_helpers.py +2 -2
- pip/_internal/utils/egg_link.py +6 -5
- pip/_internal/utils/entrypoints.py +3 -2
- pip/_internal/utils/filesystem.py +8 -5
- pip/_internal/utils/filetypes.py +4 -6
- pip/_internal/utils/glibc.py +6 -5
- pip/_internal/utils/hashes.py +9 -6
- pip/_internal/utils/logging.py +8 -5
- pip/_internal/utils/misc.py +54 -44
- pip/_internal/utils/packaging.py +3 -2
- pip/_internal/utils/retry.py +7 -4
- pip/_internal/utils/setuptools_build.py +12 -10
- pip/_internal/utils/subprocess.py +20 -17
- pip/_internal/utils/temp_dir.py +10 -12
- pip/_internal/utils/unpacking.py +6 -4
- pip/_internal/utils/urls.py +1 -1
- pip/_internal/utils/virtualenv.py +3 -2
- pip/_internal/utils/wheel.py +3 -4
- pip/_internal/vcs/bazaar.py +26 -8
- pip/_internal/vcs/git.py +59 -24
- pip/_internal/vcs/mercurial.py +34 -11
- pip/_internal/vcs/subversion.py +27 -16
- pip/_internal/vcs/versioncontrol.py +56 -51
- pip/_internal/wheel_builder.py +14 -12
- pip/_vendor/cachecontrol/__init__.py +1 -1
- pip/_vendor/certifi/__init__.py +1 -1
- pip/_vendor/certifi/cacert.pem +102 -221
- pip/_vendor/certifi/core.py +1 -32
- pip/_vendor/dependency_groups/_implementation.py +7 -11
- pip/_vendor/distlib/__init__.py +2 -2
- pip/_vendor/distlib/scripts.py +1 -1
- pip/_vendor/msgpack/__init__.py +2 -2
- pip/_vendor/pkg_resources/__init__.py +1 -1
- pip/_vendor/platformdirs/version.py +2 -2
- pip/_vendor/pygments/__init__.py +1 -1
- pip/_vendor/requests/__version__.py +2 -2
- pip/_vendor/requests/compat.py +12 -0
- pip/_vendor/requests/models.py +3 -1
- pip/_vendor/requests/utils.py +6 -16
- pip/_vendor/resolvelib/__init__.py +3 -3
- pip/_vendor/resolvelib/reporters.py +1 -1
- pip/_vendor/resolvelib/resolvers/__init__.py +4 -4
- pip/_vendor/resolvelib/resolvers/resolution.py +91 -10
- pip/_vendor/rich/__main__.py +12 -40
- pip/_vendor/rich/_inspect.py +1 -1
- pip/_vendor/rich/_ratio.py +1 -7
- pip/_vendor/rich/align.py +1 -7
- pip/_vendor/rich/box.py +1 -7
- pip/_vendor/rich/console.py +25 -20
- pip/_vendor/rich/control.py +1 -7
- pip/_vendor/rich/diagnose.py +1 -0
- pip/_vendor/rich/emoji.py +1 -6
- pip/_vendor/rich/live.py +32 -7
- pip/_vendor/rich/live_render.py +1 -7
- pip/_vendor/rich/logging.py +1 -1
- pip/_vendor/rich/panel.py +3 -4
- pip/_vendor/rich/progress.py +15 -15
- pip/_vendor/rich/spinner.py +7 -13
- pip/_vendor/rich/syntax.py +24 -5
- pip/_vendor/rich/traceback.py +32 -17
- pip/_vendor/truststore/_api.py +1 -1
- pip/_vendor/vendor.txt +10 -11
- {pip-25.1.dist-info → pip-25.2.dist-info}/METADATA +26 -4
- {pip-25.1.dist-info → pip-25.2.dist-info}/RECORD +194 -181
- {pip-25.1.dist-info → pip-25.2.dist-info}/WHEEL +1 -1
- {pip-25.1.dist-info → pip-25.2.dist-info}/licenses/AUTHORS.txt +12 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/cachecontrol/LICENSE.txt +13 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/certifi/LICENSE +20 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/dependency_groups/LICENSE.txt +9 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/distlib/LICENSE.txt +284 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/distro/LICENSE +202 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/idna/LICENSE.md +31 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/msgpack/COPYING +14 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/packaging/LICENSE +3 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/packaging/LICENSE.APACHE +177 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/packaging/LICENSE.BSD +23 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/pkg_resources/LICENSE +17 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/platformdirs/LICENSE +21 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/pygments/LICENSE +25 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/pyproject_hooks/LICENSE +21 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/requests/LICENSE +175 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/resolvelib/LICENSE +13 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/rich/LICENSE +19 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/tomli/LICENSE +21 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/tomli/LICENSE-HEADER +3 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/tomli_w/LICENSE +21 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/truststore/LICENSE +21 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/urllib3/LICENSE.txt +21 -0
- pip/_vendor/distlib/database.py +0 -1329
- pip/_vendor/distlib/index.py +0 -508
- pip/_vendor/distlib/locators.py +0 -1295
- pip/_vendor/distlib/manifest.py +0 -384
- pip/_vendor/distlib/markers.py +0 -162
- pip/_vendor/distlib/metadata.py +0 -1031
- pip/_vendor/distlib/version.py +0 -750
- pip/_vendor/distlib/wheel.py +0 -1100
- pip/_vendor/typing_extensions.py +0 -4584
- {pip-25.1.dist-info → pip-25.2.dist-info}/entry_points.txt +0 -0
- {pip-25.1.dist-info → pip-25.2.dist-info}/licenses/LICENSE.txt +0 -0
- {pip-25.1.dist-info → pip-25.2.dist-info}/top_level.txt +0 -0
pip/_internal/locations/base.py
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import functools
|
|
2
4
|
import os
|
|
3
5
|
import site
|
|
4
6
|
import sys
|
|
5
7
|
import sysconfig
|
|
6
|
-
import typing
|
|
7
8
|
|
|
8
9
|
from pip._internal.exceptions import InstallationError
|
|
9
10
|
from pip._internal.utils import appdirs
|
|
@@ -71,11 +72,11 @@ def get_src_prefix() -> str:
|
|
|
71
72
|
try:
|
|
72
73
|
# Use getusersitepackages if this is present, as it ensures that the
|
|
73
74
|
# value is initialised properly.
|
|
74
|
-
user_site:
|
|
75
|
+
user_site: str | None = site.getusersitepackages()
|
|
75
76
|
except AttributeError:
|
|
76
77
|
user_site = site.USER_SITE
|
|
77
78
|
|
|
78
79
|
|
|
79
|
-
@functools.
|
|
80
|
+
@functools.cache
|
|
80
81
|
def is_osx_framework() -> bool:
|
|
81
82
|
return bool(sysconfig.get_config_var("PYTHONFRAMEWORK"))
|
pip/_internal/main.py
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import contextlib
|
|
2
4
|
import functools
|
|
3
5
|
import os
|
|
4
6
|
import sys
|
|
5
|
-
from typing import
|
|
7
|
+
from typing import Literal, Protocol, cast
|
|
6
8
|
|
|
7
9
|
from pip._internal.utils.deprecation import deprecated
|
|
8
10
|
from pip._internal.utils.misc import strtobool
|
|
@@ -81,12 +83,12 @@ def _emit_pkg_resources_deprecation_if_needed() -> None:
|
|
|
81
83
|
|
|
82
84
|
|
|
83
85
|
class Backend(Protocol):
|
|
84
|
-
NAME:
|
|
85
|
-
Distribution:
|
|
86
|
-
Environment:
|
|
86
|
+
NAME: Literal["importlib", "pkg_resources"]
|
|
87
|
+
Distribution: type[BaseDistribution]
|
|
88
|
+
Environment: type[BaseEnvironment]
|
|
87
89
|
|
|
88
90
|
|
|
89
|
-
@functools.
|
|
91
|
+
@functools.cache
|
|
90
92
|
def select_backend() -> Backend:
|
|
91
93
|
if _should_use_importlib_metadata():
|
|
92
94
|
from . import importlib
|
|
@@ -110,7 +112,7 @@ def get_default_environment() -> BaseEnvironment:
|
|
|
110
112
|
return select_backend().Environment.default()
|
|
111
113
|
|
|
112
114
|
|
|
113
|
-
def get_environment(paths:
|
|
115
|
+
def get_environment(paths: list[str] | None) -> BaseEnvironment:
|
|
114
116
|
"""Get a representation of the environment specified by ``paths``.
|
|
115
117
|
|
|
116
118
|
This returns an Environment instance from the chosen backend based on the
|
pip/_internal/metadata/_json.py
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
# Extracted from https://github.com/pfmoore/pkg_metadata
|
|
2
|
+
from __future__ import annotations
|
|
2
3
|
|
|
3
4
|
from email.header import Header, decode_header, make_header
|
|
4
5
|
from email.message import Message
|
|
5
|
-
from typing import Any,
|
|
6
|
+
from typing import Any, cast
|
|
6
7
|
|
|
7
8
|
METADATA_FIELDS = [
|
|
8
9
|
# Name, Multiple-Use
|
|
@@ -40,10 +41,10 @@ def json_name(field: str) -> str:
|
|
|
40
41
|
return field.lower().replace("-", "_")
|
|
41
42
|
|
|
42
43
|
|
|
43
|
-
def msg_to_json(msg: Message) ->
|
|
44
|
+
def msg_to_json(msg: Message) -> dict[str, Any]:
|
|
44
45
|
"""Convert a Message object into a JSON-compatible dictionary."""
|
|
45
46
|
|
|
46
|
-
def sanitise_header(h:
|
|
47
|
+
def sanitise_header(h: Header | str) -> str:
|
|
47
48
|
if isinstance(h, Header):
|
|
48
49
|
chunks = []
|
|
49
50
|
for bytes, encoding in decode_header(h):
|
|
@@ -65,7 +66,7 @@ def msg_to_json(msg: Message) -> Dict[str, Any]:
|
|
|
65
66
|
continue
|
|
66
67
|
key = json_name(field)
|
|
67
68
|
if multi:
|
|
68
|
-
value:
|
|
69
|
+
value: str | list[str] = [
|
|
69
70
|
sanitise_header(v) for v in msg.get_all(field) # type: ignore
|
|
70
71
|
]
|
|
71
72
|
else:
|
pip/_internal/metadata/base.py
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import csv
|
|
2
4
|
import email.message
|
|
3
5
|
import functools
|
|
@@ -6,19 +8,12 @@ import logging
|
|
|
6
8
|
import pathlib
|
|
7
9
|
import re
|
|
8
10
|
import zipfile
|
|
11
|
+
from collections.abc import Collection, Container, Iterable, Iterator
|
|
9
12
|
from typing import (
|
|
10
13
|
IO,
|
|
11
14
|
Any,
|
|
12
|
-
Collection,
|
|
13
|
-
Container,
|
|
14
|
-
Dict,
|
|
15
|
-
Iterable,
|
|
16
|
-
Iterator,
|
|
17
|
-
List,
|
|
18
15
|
NamedTuple,
|
|
19
|
-
Optional,
|
|
20
16
|
Protocol,
|
|
21
|
-
Tuple,
|
|
22
17
|
Union,
|
|
23
18
|
)
|
|
24
19
|
|
|
@@ -61,8 +56,8 @@ class BaseEntryPoint(Protocol):
|
|
|
61
56
|
|
|
62
57
|
|
|
63
58
|
def _convert_installed_files_path(
|
|
64
|
-
entry:
|
|
65
|
-
info:
|
|
59
|
+
entry: tuple[str, ...],
|
|
60
|
+
info: tuple[str, ...],
|
|
66
61
|
) -> str:
|
|
67
62
|
"""Convert a legacy installed-files.txt path into modern RECORD path.
|
|
68
63
|
|
|
@@ -98,7 +93,7 @@ class RequiresEntry(NamedTuple):
|
|
|
98
93
|
|
|
99
94
|
class BaseDistribution(Protocol):
|
|
100
95
|
@classmethod
|
|
101
|
-
def from_directory(cls, directory: str) ->
|
|
96
|
+
def from_directory(cls, directory: str) -> BaseDistribution:
|
|
102
97
|
"""Load the distribution from a metadata directory.
|
|
103
98
|
|
|
104
99
|
:param directory: Path to a metadata directory, e.g. ``.dist-info``.
|
|
@@ -111,7 +106,7 @@ class BaseDistribution(Protocol):
|
|
|
111
106
|
metadata_contents: bytes,
|
|
112
107
|
filename: str,
|
|
113
108
|
project_name: str,
|
|
114
|
-
) ->
|
|
109
|
+
) -> BaseDistribution:
|
|
115
110
|
"""Load the distribution from the contents of a METADATA file.
|
|
116
111
|
|
|
117
112
|
This is used to implement PEP 658 by generating a "shallow" dist object that can
|
|
@@ -124,7 +119,7 @@ class BaseDistribution(Protocol):
|
|
|
124
119
|
raise NotImplementedError()
|
|
125
120
|
|
|
126
121
|
@classmethod
|
|
127
|
-
def from_wheel(cls, wheel:
|
|
122
|
+
def from_wheel(cls, wheel: Wheel, name: str) -> BaseDistribution:
|
|
128
123
|
"""Load the distribution from a given wheel.
|
|
129
124
|
|
|
130
125
|
:param wheel: A concrete wheel definition.
|
|
@@ -144,7 +139,7 @@ class BaseDistribution(Protocol):
|
|
|
144
139
|
return f"{self.raw_name} {self.raw_version}"
|
|
145
140
|
|
|
146
141
|
@property
|
|
147
|
-
def location(self) ->
|
|
142
|
+
def location(self) -> str | None:
|
|
148
143
|
"""Where the distribution is loaded from.
|
|
149
144
|
|
|
150
145
|
A string value is not necessarily a filesystem path, since distributions
|
|
@@ -158,7 +153,7 @@ class BaseDistribution(Protocol):
|
|
|
158
153
|
raise NotImplementedError()
|
|
159
154
|
|
|
160
155
|
@property
|
|
161
|
-
def editable_project_location(self) ->
|
|
156
|
+
def editable_project_location(self) -> str | None:
|
|
162
157
|
"""The project location for editable distributions.
|
|
163
158
|
|
|
164
159
|
This is the directory where pyproject.toml or setup.py is located.
|
|
@@ -180,7 +175,7 @@ class BaseDistribution(Protocol):
|
|
|
180
175
|
return None
|
|
181
176
|
|
|
182
177
|
@property
|
|
183
|
-
def installed_location(self) ->
|
|
178
|
+
def installed_location(self) -> str | None:
|
|
184
179
|
"""The distribution's "installed" location.
|
|
185
180
|
|
|
186
181
|
This should generally be a ``site-packages`` directory. This is
|
|
@@ -193,7 +188,7 @@ class BaseDistribution(Protocol):
|
|
|
193
188
|
raise NotImplementedError()
|
|
194
189
|
|
|
195
190
|
@property
|
|
196
|
-
def info_location(self) ->
|
|
191
|
+
def info_location(self) -> str | None:
|
|
197
192
|
"""Location of the .[egg|dist]-info directory or file.
|
|
198
193
|
|
|
199
194
|
Similarly to ``location``, a string value is not necessarily a
|
|
@@ -290,7 +285,7 @@ class BaseDistribution(Protocol):
|
|
|
290
285
|
return self.raw_name.replace("-", "_")
|
|
291
286
|
|
|
292
287
|
@property
|
|
293
|
-
def direct_url(self) ->
|
|
288
|
+
def direct_url(self) -> DirectUrl | None:
|
|
294
289
|
"""Obtain a DirectUrl from this distribution.
|
|
295
290
|
|
|
296
291
|
Returns None if the distribution has no `direct_url.json` metadata,
|
|
@@ -398,7 +393,7 @@ class BaseDistribution(Protocol):
|
|
|
398
393
|
return metadata
|
|
399
394
|
|
|
400
395
|
@property
|
|
401
|
-
def metadata_dict(self) ->
|
|
396
|
+
def metadata_dict(self) -> dict[str, Any]:
|
|
402
397
|
"""PEP 566 compliant JSON-serializable representation of METADATA or PKG-INFO.
|
|
403
398
|
|
|
404
399
|
This should return an empty dict if the metadata file is unavailable.
|
|
@@ -409,7 +404,7 @@ class BaseDistribution(Protocol):
|
|
|
409
404
|
return msg_to_json(self.metadata)
|
|
410
405
|
|
|
411
406
|
@property
|
|
412
|
-
def metadata_version(self) ->
|
|
407
|
+
def metadata_version(self) -> str | None:
|
|
413
408
|
"""Value of "Metadata-Version:" in distribution metadata, if available."""
|
|
414
409
|
return self.metadata.get("Metadata-Version")
|
|
415
410
|
|
|
@@ -463,7 +458,7 @@ class BaseDistribution(Protocol):
|
|
|
463
458
|
"""
|
|
464
459
|
raise NotImplementedError()
|
|
465
460
|
|
|
466
|
-
def _iter_declared_entries_from_record(self) ->
|
|
461
|
+
def _iter_declared_entries_from_record(self) -> Iterator[str] | None:
|
|
467
462
|
try:
|
|
468
463
|
text = self.read_text("RECORD")
|
|
469
464
|
except FileNotFoundError:
|
|
@@ -471,7 +466,7 @@ class BaseDistribution(Protocol):
|
|
|
471
466
|
# This extra Path-str cast normalizes entries.
|
|
472
467
|
return (str(pathlib.Path(row[0])) for row in csv.reader(text.splitlines()))
|
|
473
468
|
|
|
474
|
-
def _iter_declared_entries_from_legacy(self) ->
|
|
469
|
+
def _iter_declared_entries_from_legacy(self) -> Iterator[str] | None:
|
|
475
470
|
try:
|
|
476
471
|
text = self.read_text("installed-files.txt")
|
|
477
472
|
except FileNotFoundError:
|
|
@@ -492,7 +487,7 @@ class BaseDistribution(Protocol):
|
|
|
492
487
|
for p in paths
|
|
493
488
|
)
|
|
494
489
|
|
|
495
|
-
def iter_declared_entries(self) ->
|
|
490
|
+
def iter_declared_entries(self) -> Iterator[str] | None:
|
|
496
491
|
"""Iterate through file entries declared in this distribution.
|
|
497
492
|
|
|
498
493
|
For modern .dist-info distributions, this is the files listed in the
|
|
@@ -585,14 +580,14 @@ class BaseEnvironment:
|
|
|
585
580
|
"""An environment containing distributions to introspect."""
|
|
586
581
|
|
|
587
582
|
@classmethod
|
|
588
|
-
def default(cls) ->
|
|
583
|
+
def default(cls) -> BaseEnvironment:
|
|
589
584
|
raise NotImplementedError()
|
|
590
585
|
|
|
591
586
|
@classmethod
|
|
592
|
-
def from_paths(cls, paths:
|
|
587
|
+
def from_paths(cls, paths: list[str] | None) -> BaseEnvironment:
|
|
593
588
|
raise NotImplementedError()
|
|
594
589
|
|
|
595
|
-
def get_distribution(self, name: str) ->
|
|
590
|
+
def get_distribution(self, name: str) -> BaseDistribution | None:
|
|
596
591
|
"""Given a requirement name, return the installed distributions.
|
|
597
592
|
|
|
598
593
|
The name may not be normalized. The implementation must canonicalize
|
|
@@ -600,7 +595,7 @@ class BaseEnvironment:
|
|
|
600
595
|
"""
|
|
601
596
|
raise NotImplementedError()
|
|
602
597
|
|
|
603
|
-
def _iter_distributions(self) -> Iterator[
|
|
598
|
+
def _iter_distributions(self) -> Iterator[BaseDistribution]:
|
|
604
599
|
"""Iterate through installed distributions.
|
|
605
600
|
|
|
606
601
|
This function should be implemented by subclass, but never called
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import importlib.metadata
|
|
2
4
|
import os
|
|
3
|
-
from typing import Any,
|
|
5
|
+
from typing import Any, Protocol, cast
|
|
4
6
|
|
|
5
7
|
from pip._vendor.packaging.utils import NormalizedName, canonicalize_name
|
|
6
8
|
|
|
@@ -30,11 +32,11 @@ class BasePath(Protocol):
|
|
|
30
32
|
raise NotImplementedError()
|
|
31
33
|
|
|
32
34
|
@property
|
|
33
|
-
def parent(self) ->
|
|
35
|
+
def parent(self) -> BasePath:
|
|
34
36
|
raise NotImplementedError()
|
|
35
37
|
|
|
36
38
|
|
|
37
|
-
def get_info_location(d: importlib.metadata.Distribution) ->
|
|
39
|
+
def get_info_location(d: importlib.metadata.Distribution) -> BasePath | None:
|
|
38
40
|
"""Find the path to the distribution's metadata directory.
|
|
39
41
|
|
|
40
42
|
HACK: This relies on importlib.metadata's private ``_path`` attribute. Not
|
|
@@ -48,7 +50,7 @@ def get_info_location(d: importlib.metadata.Distribution) -> Optional[BasePath]:
|
|
|
48
50
|
|
|
49
51
|
def parse_name_and_version_from_info_directory(
|
|
50
52
|
dist: importlib.metadata.Distribution,
|
|
51
|
-
) ->
|
|
53
|
+
) -> tuple[str | None, str | None]:
|
|
52
54
|
"""Get a name and version from the metadata directory name.
|
|
53
55
|
|
|
54
56
|
This is much faster than reading distribution metadata.
|
|
@@ -1,17 +1,12 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import email.message
|
|
2
4
|
import importlib.metadata
|
|
3
5
|
import pathlib
|
|
4
6
|
import zipfile
|
|
7
|
+
from collections.abc import Collection, Iterable, Iterator, Mapping, Sequence
|
|
5
8
|
from os import PathLike
|
|
6
9
|
from typing import (
|
|
7
|
-
Collection,
|
|
8
|
-
Dict,
|
|
9
|
-
Iterable,
|
|
10
|
-
Iterator,
|
|
11
|
-
Mapping,
|
|
12
|
-
Optional,
|
|
13
|
-
Sequence,
|
|
14
|
-
Union,
|
|
15
10
|
cast,
|
|
16
11
|
)
|
|
17
12
|
|
|
@@ -64,7 +59,7 @@ class WheelDistribution(importlib.metadata.Distribution):
|
|
|
64
59
|
zf: zipfile.ZipFile,
|
|
65
60
|
name: str,
|
|
66
61
|
location: str,
|
|
67
|
-
) ->
|
|
62
|
+
) -> WheelDistribution:
|
|
68
63
|
info_dir, _ = parse_wheel(zf, name)
|
|
69
64
|
paths = (
|
|
70
65
|
(name, pathlib.PurePosixPath(name.split("/", 1)[-1]))
|
|
@@ -84,7 +79,7 @@ class WheelDistribution(importlib.metadata.Distribution):
|
|
|
84
79
|
return iter(self._files)
|
|
85
80
|
raise FileNotFoundError(path)
|
|
86
81
|
|
|
87
|
-
def read_text(self, filename: str) ->
|
|
82
|
+
def read_text(self, filename: str) -> str | None:
|
|
88
83
|
try:
|
|
89
84
|
data = self._files[pathlib.PurePosixPath(filename)]
|
|
90
85
|
except KeyError:
|
|
@@ -97,7 +92,7 @@ class WheelDistribution(importlib.metadata.Distribution):
|
|
|
97
92
|
raise UnsupportedWheel(error)
|
|
98
93
|
return text
|
|
99
94
|
|
|
100
|
-
def locate_file(self, path:
|
|
95
|
+
def locate_file(self, path: str | PathLike[str]) -> pathlib.Path:
|
|
101
96
|
# This method doesn't make sense for our in-memory wheel, but the API
|
|
102
97
|
# requires us to define it.
|
|
103
98
|
raise NotImplementedError
|
|
@@ -107,8 +102,8 @@ class Distribution(BaseDistribution):
|
|
|
107
102
|
def __init__(
|
|
108
103
|
self,
|
|
109
104
|
dist: importlib.metadata.Distribution,
|
|
110
|
-
info_location:
|
|
111
|
-
installed_location:
|
|
105
|
+
info_location: BasePath | None,
|
|
106
|
+
installed_location: BasePath | None,
|
|
112
107
|
) -> None:
|
|
113
108
|
self._dist = dist
|
|
114
109
|
self._info_location = info_location
|
|
@@ -147,19 +142,19 @@ class Distribution(BaseDistribution):
|
|
|
147
142
|
return cls(dist, dist.info_location, pathlib.PurePosixPath(wheel.location))
|
|
148
143
|
|
|
149
144
|
@property
|
|
150
|
-
def location(self) ->
|
|
145
|
+
def location(self) -> str | None:
|
|
151
146
|
if self._info_location is None:
|
|
152
147
|
return None
|
|
153
148
|
return str(self._info_location.parent)
|
|
154
149
|
|
|
155
150
|
@property
|
|
156
|
-
def info_location(self) ->
|
|
151
|
+
def info_location(self) -> str | None:
|
|
157
152
|
if self._info_location is None:
|
|
158
153
|
return None
|
|
159
154
|
return str(self._info_location)
|
|
160
155
|
|
|
161
156
|
@property
|
|
162
|
-
def installed_location(self) ->
|
|
157
|
+
def installed_location(self) -> str | None:
|
|
163
158
|
if self._installed_location is None:
|
|
164
159
|
return None
|
|
165
160
|
return normalize_path(str(self._installed_location))
|
|
@@ -215,7 +210,7 @@ class Distribution(BaseDistribution):
|
|
|
215
210
|
]
|
|
216
211
|
|
|
217
212
|
def iter_dependencies(self, extras: Collection[str] = ()) -> Iterable[Requirement]:
|
|
218
|
-
contexts: Sequence[
|
|
213
|
+
contexts: Sequence[dict[str, str]] = [{"extra": e} for e in extras]
|
|
219
214
|
for req_string in self.metadata.get_all("Requires-Dist", []):
|
|
220
215
|
# strip() because email.message.Message.get_all() may return a leading \n
|
|
221
216
|
# in case a long header was wrapped.
|
|
@@ -1,10 +1,13 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import importlib.metadata
|
|
2
4
|
import logging
|
|
3
5
|
import os
|
|
4
6
|
import pathlib
|
|
5
7
|
import sys
|
|
6
8
|
import zipfile
|
|
7
|
-
from
|
|
9
|
+
from collections.abc import Iterator, Sequence
|
|
10
|
+
from typing import Optional
|
|
8
11
|
|
|
9
12
|
from pip._vendor.packaging.utils import (
|
|
10
13
|
InvalidWheelFilename,
|
|
@@ -47,10 +50,10 @@ class _DistributionFinder:
|
|
|
47
50
|
installations as well. It's useful feature, after all.
|
|
48
51
|
"""
|
|
49
52
|
|
|
50
|
-
FoundResult =
|
|
53
|
+
FoundResult = tuple[importlib.metadata.Distribution, Optional[BasePath]]
|
|
51
54
|
|
|
52
55
|
def __init__(self) -> None:
|
|
53
|
-
self._found_names:
|
|
56
|
+
self._found_names: set[NormalizedName] = set()
|
|
54
57
|
|
|
55
58
|
def _find_impl(self, location: str) -> Iterator[FoundResult]:
|
|
56
59
|
"""Find distributions in a location."""
|
|
@@ -80,7 +83,7 @@ class _DistributionFinder:
|
|
|
80
83
|
"""
|
|
81
84
|
for dist, info_location in self._find_impl(location):
|
|
82
85
|
if info_location is None:
|
|
83
|
-
installed_location:
|
|
86
|
+
installed_location: BasePath | None = None
|
|
84
87
|
else:
|
|
85
88
|
installed_location = info_location.parent
|
|
86
89
|
yield Distribution(dist, info_location, installed_location)
|
|
@@ -119,7 +122,7 @@ class Environment(BaseEnvironment):
|
|
|
119
122
|
return cls(sys.path)
|
|
120
123
|
|
|
121
124
|
@classmethod
|
|
122
|
-
def from_paths(cls, paths:
|
|
125
|
+
def from_paths(cls, paths: list[str] | None) -> BaseEnvironment:
|
|
123
126
|
if paths is None:
|
|
124
127
|
return cls(sys.path)
|
|
125
128
|
return cls(paths)
|
|
@@ -130,7 +133,7 @@ class Environment(BaseEnvironment):
|
|
|
130
133
|
yield from finder.find(location)
|
|
131
134
|
yield from finder.find_legacy_editables(location)
|
|
132
135
|
|
|
133
|
-
def get_distribution(self, name: str) ->
|
|
136
|
+
def get_distribution(self, name: str) -> BaseDistribution | None:
|
|
134
137
|
canonical_name = canonicalize_name(name)
|
|
135
138
|
matches = (
|
|
136
139
|
distribution
|
|
@@ -1,16 +1,13 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import email.message
|
|
2
4
|
import email.parser
|
|
3
5
|
import logging
|
|
4
6
|
import os
|
|
5
7
|
import zipfile
|
|
8
|
+
from collections.abc import Collection, Iterable, Iterator, Mapping
|
|
6
9
|
from typing import (
|
|
7
|
-
Collection,
|
|
8
|
-
Iterable,
|
|
9
|
-
Iterator,
|
|
10
|
-
List,
|
|
11
|
-
Mapping,
|
|
12
10
|
NamedTuple,
|
|
13
|
-
Optional,
|
|
14
11
|
)
|
|
15
12
|
|
|
16
13
|
from pip._vendor import pkg_resources
|
|
@@ -73,7 +70,7 @@ class InMemoryMetadata:
|
|
|
73
70
|
def metadata_isdir(self, name: str) -> bool:
|
|
74
71
|
return False
|
|
75
72
|
|
|
76
|
-
def metadata_listdir(self, name: str) ->
|
|
73
|
+
def metadata_listdir(self, name: str) -> list[str]:
|
|
77
74
|
return []
|
|
78
75
|
|
|
79
76
|
def run_script(self, script_name: str, namespace: str) -> None:
|
|
@@ -85,7 +82,7 @@ class Distribution(BaseDistribution):
|
|
|
85
82
|
self._dist = dist
|
|
86
83
|
# This is populated lazily, to avoid loading metadata for all possible
|
|
87
84
|
# distributions eagerly.
|
|
88
|
-
self.__extra_mapping:
|
|
85
|
+
self.__extra_mapping: Mapping[NormalizedName, str] | None = None
|
|
89
86
|
|
|
90
87
|
@property
|
|
91
88
|
def _extra_mapping(self) -> Mapping[NormalizedName, str]:
|
|
@@ -155,11 +152,11 @@ class Distribution(BaseDistribution):
|
|
|
155
152
|
return cls(dist)
|
|
156
153
|
|
|
157
154
|
@property
|
|
158
|
-
def location(self) ->
|
|
155
|
+
def location(self) -> str | None:
|
|
159
156
|
return self._dist.location
|
|
160
157
|
|
|
161
158
|
@property
|
|
162
|
-
def installed_location(self) ->
|
|
159
|
+
def installed_location(self) -> str | None:
|
|
163
160
|
egg_link = egg_link_path_from_location(self.raw_name)
|
|
164
161
|
if egg_link:
|
|
165
162
|
location = egg_link
|
|
@@ -170,7 +167,7 @@ class Distribution(BaseDistribution):
|
|
|
170
167
|
return normalize_path(location)
|
|
171
168
|
|
|
172
169
|
@property
|
|
173
|
-
def info_location(self) ->
|
|
170
|
+
def info_location(self) -> str | None:
|
|
174
171
|
return self._dist.egg_info
|
|
175
172
|
|
|
176
173
|
@property
|
|
@@ -259,14 +256,14 @@ class Environment(BaseEnvironment):
|
|
|
259
256
|
return cls(pkg_resources.working_set)
|
|
260
257
|
|
|
261
258
|
@classmethod
|
|
262
|
-
def from_paths(cls, paths:
|
|
259
|
+
def from_paths(cls, paths: list[str] | None) -> BaseEnvironment:
|
|
263
260
|
return cls(pkg_resources.WorkingSet(paths))
|
|
264
261
|
|
|
265
262
|
def _iter_distributions(self) -> Iterator[BaseDistribution]:
|
|
266
263
|
for dist in self._ws:
|
|
267
264
|
yield Distribution(dist)
|
|
268
265
|
|
|
269
|
-
def _search_distribution(self, name: str) ->
|
|
266
|
+
def _search_distribution(self, name: str) -> BaseDistribution | None:
|
|
270
267
|
"""Find a distribution matching the ``name`` in the environment.
|
|
271
268
|
|
|
272
269
|
This searches from *all* distributions available in the environment, to
|
|
@@ -278,7 +275,7 @@ class Environment(BaseEnvironment):
|
|
|
278
275
|
return dist
|
|
279
276
|
return None
|
|
280
277
|
|
|
281
|
-
def get_distribution(self, name: str) ->
|
|
278
|
+
def get_distribution(self, name: str) -> BaseDistribution | None:
|
|
282
279
|
# Search the distribution by looking through the working set.
|
|
283
280
|
dist = self._search_distribution(name)
|
|
284
281
|
if dist:
|