pip 25.1.1__py3-none-any.whl → 25.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pip/__init__.py +3 -3
- pip/_internal/__init__.py +2 -2
- pip/_internal/build_env.py +118 -94
- pip/_internal/cache.py +16 -14
- pip/_internal/cli/autocompletion.py +13 -4
- pip/_internal/cli/base_command.py +18 -7
- pip/_internal/cli/cmdoptions.py +14 -9
- pip/_internal/cli/command_context.py +4 -3
- pip/_internal/cli/index_command.py +11 -9
- pip/_internal/cli/main.py +3 -2
- pip/_internal/cli/main_parser.py +4 -3
- pip/_internal/cli/parser.py +26 -22
- pip/_internal/cli/progress_bars.py +19 -12
- pip/_internal/cli/req_command.py +16 -12
- pip/_internal/cli/spinners.py +81 -5
- pip/_internal/commands/__init__.py +5 -3
- pip/_internal/commands/cache.py +18 -15
- pip/_internal/commands/check.py +1 -2
- pip/_internal/commands/completion.py +1 -2
- pip/_internal/commands/configuration.py +26 -18
- pip/_internal/commands/debug.py +8 -6
- pip/_internal/commands/download.py +2 -3
- pip/_internal/commands/freeze.py +2 -3
- pip/_internal/commands/hash.py +1 -2
- pip/_internal/commands/help.py +1 -2
- pip/_internal/commands/index.py +15 -9
- pip/_internal/commands/inspect.py +4 -4
- pip/_internal/commands/install.py +44 -39
- pip/_internal/commands/list.py +35 -26
- pip/_internal/commands/lock.py +1 -2
- pip/_internal/commands/search.py +14 -12
- pip/_internal/commands/show.py +14 -11
- pip/_internal/commands/uninstall.py +1 -2
- pip/_internal/commands/wheel.py +2 -3
- pip/_internal/configuration.py +39 -25
- pip/_internal/distributions/base.py +6 -4
- pip/_internal/distributions/installed.py +8 -4
- pip/_internal/distributions/sdist.py +20 -13
- pip/_internal/distributions/wheel.py +6 -4
- pip/_internal/exceptions.py +58 -39
- pip/_internal/index/collector.py +24 -29
- pip/_internal/index/package_finder.py +70 -61
- pip/_internal/index/sources.py +17 -14
- pip/_internal/locations/__init__.py +18 -16
- pip/_internal/locations/_distutils.py +12 -11
- pip/_internal/locations/_sysconfig.py +5 -4
- pip/_internal/locations/base.py +4 -3
- pip/_internal/main.py +2 -2
- pip/_internal/metadata/__init__.py +8 -6
- pip/_internal/metadata/_json.py +5 -4
- pip/_internal/metadata/base.py +22 -27
- pip/_internal/metadata/importlib/_compat.py +6 -4
- pip/_internal/metadata/importlib/_dists.py +12 -17
- pip/_internal/metadata/importlib/_envs.py +9 -6
- pip/_internal/metadata/pkg_resources.py +11 -14
- pip/_internal/models/direct_url.py +24 -21
- pip/_internal/models/format_control.py +5 -5
- pip/_internal/models/installation_report.py +4 -3
- pip/_internal/models/link.py +39 -34
- pip/_internal/models/pylock.py +27 -22
- pip/_internal/models/search_scope.py +6 -7
- pip/_internal/models/selection_prefs.py +3 -3
- pip/_internal/models/target_python.py +10 -9
- pip/_internal/models/wheel.py +7 -5
- pip/_internal/network/auth.py +20 -22
- pip/_internal/network/cache.py +22 -6
- pip/_internal/network/download.py +169 -141
- pip/_internal/network/lazy_wheel.py +10 -7
- pip/_internal/network/session.py +32 -27
- pip/_internal/network/utils.py +2 -2
- pip/_internal/network/xmlrpc.py +2 -2
- pip/_internal/operations/build/build_tracker.py +10 -8
- pip/_internal/operations/build/wheel.py +3 -2
- pip/_internal/operations/build/wheel_editable.py +3 -2
- pip/_internal/operations/build/wheel_legacy.py +9 -8
- pip/_internal/operations/check.py +21 -26
- pip/_internal/operations/freeze.py +12 -9
- pip/_internal/operations/install/editable_legacy.py +5 -3
- pip/_internal/operations/install/wheel.py +49 -41
- pip/_internal/operations/prepare.py +35 -30
- pip/_internal/pyproject.py +7 -10
- pip/_internal/req/__init__.py +12 -10
- pip/_internal/req/constructors.py +33 -31
- pip/_internal/req/req_dependency_group.py +7 -11
- pip/_internal/req/req_file.py +32 -35
- pip/_internal/req/req_install.py +37 -34
- pip/_internal/req/req_set.py +4 -5
- pip/_internal/req/req_uninstall.py +20 -17
- pip/_internal/resolution/base.py +3 -3
- pip/_internal/resolution/legacy/resolver.py +21 -20
- pip/_internal/resolution/resolvelib/base.py +16 -13
- pip/_internal/resolution/resolvelib/candidates.py +29 -26
- pip/_internal/resolution/resolvelib/factory.py +41 -50
- pip/_internal/resolution/resolvelib/found_candidates.py +11 -9
- pip/_internal/resolution/resolvelib/provider.py +15 -20
- pip/_internal/resolution/resolvelib/reporter.py +5 -3
- pip/_internal/resolution/resolvelib/requirements.py +8 -6
- pip/_internal/resolution/resolvelib/resolver.py +39 -23
- pip/_internal/self_outdated_check.py +8 -6
- pip/_internal/utils/appdirs.py +1 -2
- pip/_internal/utils/compat.py +7 -1
- pip/_internal/utils/compatibility_tags.py +17 -16
- pip/_internal/utils/deprecation.py +11 -9
- pip/_internal/utils/direct_url_helpers.py +2 -2
- pip/_internal/utils/egg_link.py +6 -5
- pip/_internal/utils/entrypoints.py +3 -2
- pip/_internal/utils/filesystem.py +8 -5
- pip/_internal/utils/filetypes.py +4 -6
- pip/_internal/utils/glibc.py +6 -5
- pip/_internal/utils/hashes.py +9 -6
- pip/_internal/utils/logging.py +8 -5
- pip/_internal/utils/misc.py +37 -45
- pip/_internal/utils/packaging.py +3 -2
- pip/_internal/utils/retry.py +7 -4
- pip/_internal/utils/setuptools_build.py +12 -10
- pip/_internal/utils/subprocess.py +20 -17
- pip/_internal/utils/temp_dir.py +10 -12
- pip/_internal/utils/unpacking.py +6 -4
- pip/_internal/utils/urls.py +1 -1
- pip/_internal/utils/virtualenv.py +3 -2
- pip/_internal/utils/wheel.py +3 -4
- pip/_internal/vcs/bazaar.py +26 -8
- pip/_internal/vcs/git.py +59 -24
- pip/_internal/vcs/mercurial.py +34 -11
- pip/_internal/vcs/subversion.py +27 -16
- pip/_internal/vcs/versioncontrol.py +56 -51
- pip/_internal/wheel_builder.py +14 -12
- pip/_vendor/cachecontrol/__init__.py +1 -1
- pip/_vendor/certifi/__init__.py +1 -1
- pip/_vendor/certifi/cacert.pem +102 -221
- pip/_vendor/certifi/core.py +1 -32
- pip/_vendor/distlib/__init__.py +2 -2
- pip/_vendor/distlib/scripts.py +1 -1
- pip/_vendor/msgpack/__init__.py +2 -2
- pip/_vendor/pkg_resources/__init__.py +1 -1
- pip/_vendor/platformdirs/version.py +2 -2
- pip/_vendor/pygments/__init__.py +1 -1
- pip/_vendor/requests/__version__.py +2 -2
- pip/_vendor/requests/compat.py +12 -0
- pip/_vendor/requests/models.py +3 -1
- pip/_vendor/requests/utils.py +6 -16
- pip/_vendor/resolvelib/__init__.py +3 -3
- pip/_vendor/resolvelib/reporters.py +1 -1
- pip/_vendor/resolvelib/resolvers/__init__.py +4 -4
- pip/_vendor/resolvelib/resolvers/resolution.py +91 -10
- pip/_vendor/rich/__main__.py +12 -40
- pip/_vendor/rich/_inspect.py +1 -1
- pip/_vendor/rich/_ratio.py +1 -7
- pip/_vendor/rich/align.py +1 -7
- pip/_vendor/rich/box.py +1 -7
- pip/_vendor/rich/console.py +25 -20
- pip/_vendor/rich/control.py +1 -7
- pip/_vendor/rich/diagnose.py +1 -0
- pip/_vendor/rich/emoji.py +1 -6
- pip/_vendor/rich/live.py +32 -7
- pip/_vendor/rich/live_render.py +1 -7
- pip/_vendor/rich/logging.py +1 -1
- pip/_vendor/rich/panel.py +3 -4
- pip/_vendor/rich/progress.py +15 -15
- pip/_vendor/rich/spinner.py +7 -13
- pip/_vendor/rich/syntax.py +24 -5
- pip/_vendor/rich/traceback.py +32 -17
- pip/_vendor/truststore/_api.py +1 -1
- pip/_vendor/vendor.txt +9 -10
- {pip-25.1.1.dist-info → pip-25.2.dist-info}/METADATA +26 -4
- {pip-25.1.1.dist-info → pip-25.2.dist-info}/RECORD +193 -180
- {pip-25.1.1.dist-info → pip-25.2.dist-info}/WHEEL +1 -1
- {pip-25.1.1.dist-info → pip-25.2.dist-info}/licenses/AUTHORS.txt +12 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/cachecontrol/LICENSE.txt +13 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/certifi/LICENSE +20 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/dependency_groups/LICENSE.txt +9 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/distlib/LICENSE.txt +284 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/distro/LICENSE +202 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/idna/LICENSE.md +31 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/msgpack/COPYING +14 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/packaging/LICENSE +3 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/packaging/LICENSE.APACHE +177 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/packaging/LICENSE.BSD +23 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/pkg_resources/LICENSE +17 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/platformdirs/LICENSE +21 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/pygments/LICENSE +25 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/pyproject_hooks/LICENSE +21 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/requests/LICENSE +175 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/resolvelib/LICENSE +13 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/rich/LICENSE +19 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/tomli/LICENSE +21 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/tomli/LICENSE-HEADER +3 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/tomli_w/LICENSE +21 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/truststore/LICENSE +21 -0
- pip-25.2.dist-info/licenses/src/pip/_vendor/urllib3/LICENSE.txt +21 -0
- pip/_vendor/distlib/database.py +0 -1329
- pip/_vendor/distlib/index.py +0 -508
- pip/_vendor/distlib/locators.py +0 -1295
- pip/_vendor/distlib/manifest.py +0 -384
- pip/_vendor/distlib/markers.py +0 -162
- pip/_vendor/distlib/metadata.py +0 -1031
- pip/_vendor/distlib/version.py +0 -750
- pip/_vendor/distlib/wheel.py +0 -1100
- pip/_vendor/typing_extensions.py +0 -4584
- {pip-25.1.1.dist-info → pip-25.2.dist-info}/entry_points.txt +0 -0
- {pip-25.1.1.dist-info → pip-25.2.dist-info}/licenses/LICENSE.txt +0 -0
- {pip-25.1.1.dist-info → pip-25.2.dist-info}/top_level.txt +0 -0
|
@@ -1,20 +1,17 @@
|
|
|
1
1
|
"""Routines related to PyPI, indexes"""
|
|
2
2
|
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
3
5
|
import enum
|
|
4
6
|
import functools
|
|
5
7
|
import itertools
|
|
6
8
|
import logging
|
|
7
9
|
import re
|
|
10
|
+
from collections.abc import Iterable
|
|
8
11
|
from dataclasses import dataclass
|
|
9
12
|
from typing import (
|
|
10
13
|
TYPE_CHECKING,
|
|
11
|
-
Dict,
|
|
12
|
-
FrozenSet,
|
|
13
|
-
Iterable,
|
|
14
|
-
List,
|
|
15
14
|
Optional,
|
|
16
|
-
Set,
|
|
17
|
-
Tuple,
|
|
18
15
|
Union,
|
|
19
16
|
)
|
|
20
17
|
|
|
@@ -48,20 +45,20 @@ from pip._internal.utils.packaging import check_requires_python
|
|
|
48
45
|
from pip._internal.utils.unpacking import SUPPORTED_EXTENSIONS
|
|
49
46
|
|
|
50
47
|
if TYPE_CHECKING:
|
|
51
|
-
from
|
|
48
|
+
from typing_extensions import TypeGuard
|
|
52
49
|
|
|
53
50
|
__all__ = ["FormatControl", "BestCandidateResult", "PackageFinder"]
|
|
54
51
|
|
|
55
52
|
|
|
56
53
|
logger = getLogger(__name__)
|
|
57
54
|
|
|
58
|
-
BuildTag = Union[
|
|
59
|
-
CandidateSortingKey =
|
|
55
|
+
BuildTag = Union[tuple[()], tuple[int, str]]
|
|
56
|
+
CandidateSortingKey = tuple[int, int, int, _BaseVersion, Optional[int], BuildTag]
|
|
60
57
|
|
|
61
58
|
|
|
62
59
|
def _check_link_requires_python(
|
|
63
60
|
link: Link,
|
|
64
|
-
version_info:
|
|
61
|
+
version_info: tuple[int, int, int],
|
|
65
62
|
ignore_requires_python: bool = False,
|
|
66
63
|
) -> bool:
|
|
67
64
|
"""
|
|
@@ -131,10 +128,10 @@ class LinkEvaluator:
|
|
|
131
128
|
self,
|
|
132
129
|
project_name: str,
|
|
133
130
|
canonical_name: str,
|
|
134
|
-
formats:
|
|
131
|
+
formats: frozenset[str],
|
|
135
132
|
target_python: TargetPython,
|
|
136
133
|
allow_yanked: bool,
|
|
137
|
-
ignore_requires_python:
|
|
134
|
+
ignore_requires_python: bool | None = None,
|
|
138
135
|
) -> None:
|
|
139
136
|
"""
|
|
140
137
|
:param project_name: The user supplied package name.
|
|
@@ -164,7 +161,7 @@ class LinkEvaluator:
|
|
|
164
161
|
|
|
165
162
|
self.project_name = project_name
|
|
166
163
|
|
|
167
|
-
def evaluate_link(self, link: Link) ->
|
|
164
|
+
def evaluate_link(self, link: Link) -> tuple[LinkType, str]:
|
|
168
165
|
"""
|
|
169
166
|
Determine whether a link is a candidate for installation.
|
|
170
167
|
|
|
@@ -251,7 +248,19 @@ class LinkEvaluator:
|
|
|
251
248
|
ignore_requires_python=self._ignore_requires_python,
|
|
252
249
|
)
|
|
253
250
|
if not supports_python:
|
|
254
|
-
|
|
251
|
+
requires_python = link.requires_python
|
|
252
|
+
if requires_python:
|
|
253
|
+
|
|
254
|
+
def get_version_sort_key(v: str) -> tuple[int, ...]:
|
|
255
|
+
return tuple(int(s) for s in v.split(".") if s.isdigit())
|
|
256
|
+
|
|
257
|
+
requires_python = ",".join(
|
|
258
|
+
sorted(
|
|
259
|
+
(str(s) for s in specifiers.SpecifierSet(requires_python)),
|
|
260
|
+
key=get_version_sort_key,
|
|
261
|
+
)
|
|
262
|
+
)
|
|
263
|
+
reason = f"{version} Requires-Python {requires_python}"
|
|
255
264
|
return (LinkType.requires_python_mismatch, reason)
|
|
256
265
|
|
|
257
266
|
logger.debug("Found link %s, version: %s", link, version)
|
|
@@ -260,10 +269,10 @@ class LinkEvaluator:
|
|
|
260
269
|
|
|
261
270
|
|
|
262
271
|
def filter_unallowed_hashes(
|
|
263
|
-
candidates:
|
|
264
|
-
hashes:
|
|
272
|
+
candidates: list[InstallationCandidate],
|
|
273
|
+
hashes: Hashes | None,
|
|
265
274
|
project_name: str,
|
|
266
|
-
) ->
|
|
275
|
+
) -> list[InstallationCandidate]:
|
|
267
276
|
"""
|
|
268
277
|
Filter out candidates whose hashes aren't allowed, and return a new
|
|
269
278
|
list of candidates.
|
|
@@ -357,9 +366,9 @@ class BestCandidateResult:
|
|
|
357
366
|
if no applicable candidates were found.
|
|
358
367
|
"""
|
|
359
368
|
|
|
360
|
-
all_candidates:
|
|
361
|
-
applicable_candidates:
|
|
362
|
-
best_candidate:
|
|
369
|
+
all_candidates: list[InstallationCandidate]
|
|
370
|
+
applicable_candidates: list[InstallationCandidate]
|
|
371
|
+
best_candidate: InstallationCandidate | None
|
|
363
372
|
|
|
364
373
|
def __post_init__(self) -> None:
|
|
365
374
|
assert set(self.applicable_candidates) <= set(self.all_candidates)
|
|
@@ -380,12 +389,12 @@ class CandidateEvaluator:
|
|
|
380
389
|
def create(
|
|
381
390
|
cls,
|
|
382
391
|
project_name: str,
|
|
383
|
-
target_python:
|
|
392
|
+
target_python: TargetPython | None = None,
|
|
384
393
|
prefer_binary: bool = False,
|
|
385
394
|
allow_all_prereleases: bool = False,
|
|
386
|
-
specifier:
|
|
387
|
-
hashes:
|
|
388
|
-
) ->
|
|
395
|
+
specifier: specifiers.BaseSpecifier | None = None,
|
|
396
|
+
hashes: Hashes | None = None,
|
|
397
|
+
) -> CandidateEvaluator:
|
|
389
398
|
"""Create a CandidateEvaluator object.
|
|
390
399
|
|
|
391
400
|
:param target_python: The target Python interpreter to use when
|
|
@@ -415,11 +424,11 @@ class CandidateEvaluator:
|
|
|
415
424
|
def __init__(
|
|
416
425
|
self,
|
|
417
426
|
project_name: str,
|
|
418
|
-
supported_tags:
|
|
427
|
+
supported_tags: list[Tag],
|
|
419
428
|
specifier: specifiers.BaseSpecifier,
|
|
420
429
|
prefer_binary: bool = False,
|
|
421
430
|
allow_all_prereleases: bool = False,
|
|
422
|
-
hashes:
|
|
431
|
+
hashes: Hashes | None = None,
|
|
423
432
|
) -> None:
|
|
424
433
|
"""
|
|
425
434
|
:param supported_tags: The PEP 425 tags supported by the target
|
|
@@ -440,8 +449,8 @@ class CandidateEvaluator:
|
|
|
440
449
|
|
|
441
450
|
def get_applicable_candidates(
|
|
442
451
|
self,
|
|
443
|
-
candidates:
|
|
444
|
-
) ->
|
|
452
|
+
candidates: list[InstallationCandidate],
|
|
453
|
+
) -> list[InstallationCandidate]:
|
|
445
454
|
"""
|
|
446
455
|
Return the applicable candidates from a list of candidates.
|
|
447
456
|
"""
|
|
@@ -540,8 +549,8 @@ class CandidateEvaluator:
|
|
|
540
549
|
|
|
541
550
|
def sort_best_candidate(
|
|
542
551
|
self,
|
|
543
|
-
candidates:
|
|
544
|
-
) ->
|
|
552
|
+
candidates: list[InstallationCandidate],
|
|
553
|
+
) -> InstallationCandidate | None:
|
|
545
554
|
"""
|
|
546
555
|
Return the best candidate per the instance's sort order, or None if
|
|
547
556
|
no candidate is acceptable.
|
|
@@ -553,7 +562,7 @@ class CandidateEvaluator:
|
|
|
553
562
|
|
|
554
563
|
def compute_best_candidate(
|
|
555
564
|
self,
|
|
556
|
-
candidates:
|
|
565
|
+
candidates: list[InstallationCandidate],
|
|
557
566
|
) -> BestCandidateResult:
|
|
558
567
|
"""
|
|
559
568
|
Compute and return a `BestCandidateResult` instance.
|
|
@@ -581,9 +590,9 @@ class PackageFinder:
|
|
|
581
590
|
link_collector: LinkCollector,
|
|
582
591
|
target_python: TargetPython,
|
|
583
592
|
allow_yanked: bool,
|
|
584
|
-
format_control:
|
|
585
|
-
candidate_prefs:
|
|
586
|
-
ignore_requires_python:
|
|
593
|
+
format_control: FormatControl | None = None,
|
|
594
|
+
candidate_prefs: CandidatePreferences | None = None,
|
|
595
|
+
ignore_requires_python: bool | None = None,
|
|
587
596
|
) -> None:
|
|
588
597
|
"""
|
|
589
598
|
This constructor is primarily meant to be used by the create() class
|
|
@@ -609,12 +618,12 @@ class PackageFinder:
|
|
|
609
618
|
self.format_control = format_control
|
|
610
619
|
|
|
611
620
|
# These are boring links that have already been logged somehow.
|
|
612
|
-
self._logged_links:
|
|
621
|
+
self._logged_links: set[tuple[Link, LinkType, str]] = set()
|
|
613
622
|
|
|
614
623
|
# Cache of the result of finding candidates
|
|
615
|
-
self._all_candidates:
|
|
616
|
-
self._best_candidates:
|
|
617
|
-
|
|
624
|
+
self._all_candidates: dict[str, list[InstallationCandidate]] = {}
|
|
625
|
+
self._best_candidates: dict[
|
|
626
|
+
tuple[str, specifiers.BaseSpecifier | None, Hashes | None],
|
|
618
627
|
BestCandidateResult,
|
|
619
628
|
] = {}
|
|
620
629
|
|
|
@@ -627,8 +636,8 @@ class PackageFinder:
|
|
|
627
636
|
cls,
|
|
628
637
|
link_collector: LinkCollector,
|
|
629
638
|
selection_prefs: SelectionPreferences,
|
|
630
|
-
target_python:
|
|
631
|
-
) ->
|
|
639
|
+
target_python: TargetPython | None = None,
|
|
640
|
+
) -> PackageFinder:
|
|
632
641
|
"""Create a PackageFinder.
|
|
633
642
|
|
|
634
643
|
:param selection_prefs: The candidate selection preferences, as a
|
|
@@ -667,15 +676,15 @@ class PackageFinder:
|
|
|
667
676
|
self._link_collector.search_scope = search_scope
|
|
668
677
|
|
|
669
678
|
@property
|
|
670
|
-
def find_links(self) ->
|
|
679
|
+
def find_links(self) -> list[str]:
|
|
671
680
|
return self._link_collector.find_links
|
|
672
681
|
|
|
673
682
|
@property
|
|
674
|
-
def index_urls(self) ->
|
|
683
|
+
def index_urls(self) -> list[str]:
|
|
675
684
|
return self.search_scope.index_urls
|
|
676
685
|
|
|
677
686
|
@property
|
|
678
|
-
def proxy(self) ->
|
|
687
|
+
def proxy(self) -> str | None:
|
|
679
688
|
return self._link_collector.session.pip_proxy
|
|
680
689
|
|
|
681
690
|
@property
|
|
@@ -684,7 +693,7 @@ class PackageFinder:
|
|
|
684
693
|
yield build_netloc(*host_port)
|
|
685
694
|
|
|
686
695
|
@property
|
|
687
|
-
def custom_cert(self) ->
|
|
696
|
+
def custom_cert(self) -> str | None:
|
|
688
697
|
# session.verify is either a boolean (use default bundle/no SSL
|
|
689
698
|
# verification) or a string path to a custom CA bundle to use. We only
|
|
690
699
|
# care about the latter.
|
|
@@ -692,7 +701,7 @@ class PackageFinder:
|
|
|
692
701
|
return verify if isinstance(verify, str) else None
|
|
693
702
|
|
|
694
703
|
@property
|
|
695
|
-
def client_cert(self) ->
|
|
704
|
+
def client_cert(self) -> str | None:
|
|
696
705
|
cert = self._link_collector.session.cert
|
|
697
706
|
assert not isinstance(cert, tuple), "pip only supports PEM client certs"
|
|
698
707
|
return cert
|
|
@@ -711,7 +720,7 @@ class PackageFinder:
|
|
|
711
720
|
def set_prefer_binary(self) -> None:
|
|
712
721
|
self._candidate_prefs.prefer_binary = True
|
|
713
722
|
|
|
714
|
-
def requires_python_skipped_reasons(self) ->
|
|
723
|
+
def requires_python_skipped_reasons(self) -> list[str]:
|
|
715
724
|
reasons = {
|
|
716
725
|
detail
|
|
717
726
|
for _, result, detail in self._logged_links
|
|
@@ -732,13 +741,13 @@ class PackageFinder:
|
|
|
732
741
|
ignore_requires_python=self._ignore_requires_python,
|
|
733
742
|
)
|
|
734
743
|
|
|
735
|
-
def _sort_links(self, links: Iterable[Link]) ->
|
|
744
|
+
def _sort_links(self, links: Iterable[Link]) -> list[Link]:
|
|
736
745
|
"""
|
|
737
746
|
Returns elements of links in order, non-egg links first, egg links
|
|
738
747
|
second, while eliminating duplicates
|
|
739
748
|
"""
|
|
740
749
|
eggs, no_eggs = [], []
|
|
741
|
-
seen:
|
|
750
|
+
seen: set[Link] = set()
|
|
742
751
|
for link in links:
|
|
743
752
|
if link not in seen:
|
|
744
753
|
seen.add(link)
|
|
@@ -758,7 +767,7 @@ class PackageFinder:
|
|
|
758
767
|
|
|
759
768
|
def get_install_candidate(
|
|
760
769
|
self, link_evaluator: LinkEvaluator, link: Link
|
|
761
|
-
) ->
|
|
770
|
+
) -> InstallationCandidate | None:
|
|
762
771
|
"""
|
|
763
772
|
If the link is a candidate for install, convert it to an
|
|
764
773
|
InstallationCandidate and return it. Otherwise, return None.
|
|
@@ -779,7 +788,7 @@ class PackageFinder:
|
|
|
779
788
|
|
|
780
789
|
def evaluate_links(
|
|
781
790
|
self, link_evaluator: LinkEvaluator, links: Iterable[Link]
|
|
782
|
-
) ->
|
|
791
|
+
) -> list[InstallationCandidate]:
|
|
783
792
|
"""
|
|
784
793
|
Convert links that are candidates to InstallationCandidate objects.
|
|
785
794
|
"""
|
|
@@ -793,7 +802,7 @@ class PackageFinder:
|
|
|
793
802
|
|
|
794
803
|
def process_project_url(
|
|
795
804
|
self, project_url: Link, link_evaluator: LinkEvaluator
|
|
796
|
-
) ->
|
|
805
|
+
) -> list[InstallationCandidate]:
|
|
797
806
|
logger.debug(
|
|
798
807
|
"Fetching project page and analyzing links: %s",
|
|
799
808
|
project_url,
|
|
@@ -812,7 +821,7 @@ class PackageFinder:
|
|
|
812
821
|
|
|
813
822
|
return package_links
|
|
814
823
|
|
|
815
|
-
def find_all_candidates(self, project_name: str) ->
|
|
824
|
+
def find_all_candidates(self, project_name: str) -> list[InstallationCandidate]:
|
|
816
825
|
"""Find all available InstallationCandidate for project_name
|
|
817
826
|
|
|
818
827
|
This checks index_urls and find_links.
|
|
@@ -872,8 +881,8 @@ class PackageFinder:
|
|
|
872
881
|
def make_candidate_evaluator(
|
|
873
882
|
self,
|
|
874
883
|
project_name: str,
|
|
875
|
-
specifier:
|
|
876
|
-
hashes:
|
|
884
|
+
specifier: specifiers.BaseSpecifier | None = None,
|
|
885
|
+
hashes: Hashes | None = None,
|
|
877
886
|
) -> CandidateEvaluator:
|
|
878
887
|
"""Create a CandidateEvaluator object to use."""
|
|
879
888
|
candidate_prefs = self._candidate_prefs
|
|
@@ -889,8 +898,8 @@ class PackageFinder:
|
|
|
889
898
|
def find_best_candidate(
|
|
890
899
|
self,
|
|
891
900
|
project_name: str,
|
|
892
|
-
specifier:
|
|
893
|
-
hashes:
|
|
901
|
+
specifier: specifiers.BaseSpecifier | None = None,
|
|
902
|
+
hashes: Hashes | None = None,
|
|
894
903
|
) -> BestCandidateResult:
|
|
895
904
|
"""Find matches for the given project and specifier.
|
|
896
905
|
|
|
@@ -917,7 +926,7 @@ class PackageFinder:
|
|
|
917
926
|
|
|
918
927
|
def find_requirement(
|
|
919
928
|
self, req: InstallRequirement, upgrade: bool
|
|
920
|
-
) ->
|
|
929
|
+
) -> InstallationCandidate | None:
|
|
921
930
|
"""Try to find a Link matching req
|
|
922
931
|
|
|
923
932
|
Expects req, an InstallRequirement and upgrade, a boolean
|
|
@@ -935,7 +944,7 @@ class PackageFinder:
|
|
|
935
944
|
)
|
|
936
945
|
best_candidate = best_candidate_result.best_candidate
|
|
937
946
|
|
|
938
|
-
installed_version:
|
|
947
|
+
installed_version: _BaseVersion | None = None
|
|
939
948
|
if req.satisfied_by is not None:
|
|
940
949
|
installed_version = req.satisfied_by.version
|
|
941
950
|
|
|
@@ -965,8 +974,8 @@ class PackageFinder:
|
|
|
965
974
|
raise DistributionNotFound(f"No matching distribution found for {req}")
|
|
966
975
|
|
|
967
976
|
def _should_install_candidate(
|
|
968
|
-
candidate:
|
|
969
|
-
) ->
|
|
977
|
+
candidate: InstallationCandidate | None,
|
|
978
|
+
) -> TypeGuard[InstallationCandidate]:
|
|
970
979
|
if installed_version is None:
|
|
971
980
|
return True
|
|
972
981
|
if best_candidate is None:
|
|
@@ -1032,7 +1041,7 @@ def _find_name_version_sep(fragment: str, canonical_name: str) -> int:
|
|
|
1032
1041
|
raise ValueError(f"{fragment} does not match {canonical_name}")
|
|
1033
1042
|
|
|
1034
1043
|
|
|
1035
|
-
def _extract_version_from_fragment(fragment: str, canonical_name: str) ->
|
|
1044
|
+
def _extract_version_from_fragment(fragment: str, canonical_name: str) -> str | None:
|
|
1036
1045
|
"""Parse the version string from a <package>+<version> filename
|
|
1037
1046
|
"fragment" (stem) or egg fragment.
|
|
1038
1047
|
|
pip/_internal/index/sources.py
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import logging
|
|
2
4
|
import mimetypes
|
|
3
5
|
import os
|
|
4
6
|
from collections import defaultdict
|
|
5
|
-
from
|
|
7
|
+
from collections.abc import Iterable
|
|
8
|
+
from typing import Callable
|
|
6
9
|
|
|
7
10
|
from pip._vendor.packaging.utils import (
|
|
8
11
|
InvalidSdistFilename,
|
|
@@ -27,7 +30,7 @@ PageValidator = Callable[[Link], bool]
|
|
|
27
30
|
|
|
28
31
|
class LinkSource:
|
|
29
32
|
@property
|
|
30
|
-
def link(self) ->
|
|
33
|
+
def link(self) -> Link | None:
|
|
31
34
|
"""Returns the underlying link, if there's one."""
|
|
32
35
|
raise NotImplementedError()
|
|
33
36
|
|
|
@@ -49,8 +52,8 @@ class _FlatDirectoryToUrls:
|
|
|
49
52
|
|
|
50
53
|
def __init__(self, path: str) -> None:
|
|
51
54
|
self._path = path
|
|
52
|
-
self._page_candidates:
|
|
53
|
-
self._project_name_to_urls:
|
|
55
|
+
self._page_candidates: list[str] = []
|
|
56
|
+
self._project_name_to_urls: dict[str, list[str]] = defaultdict(list)
|
|
54
57
|
self._scanned_directory = False
|
|
55
58
|
|
|
56
59
|
def _scan_directory(self) -> None:
|
|
@@ -77,14 +80,14 @@ class _FlatDirectoryToUrls:
|
|
|
77
80
|
self._scanned_directory = True
|
|
78
81
|
|
|
79
82
|
@property
|
|
80
|
-
def page_candidates(self) ->
|
|
83
|
+
def page_candidates(self) -> list[str]:
|
|
81
84
|
if not self._scanned_directory:
|
|
82
85
|
self._scan_directory()
|
|
83
86
|
|
|
84
87
|
return self._page_candidates
|
|
85
88
|
|
|
86
89
|
@property
|
|
87
|
-
def project_name_to_urls(self) ->
|
|
90
|
+
def project_name_to_urls(self) -> dict[str, list[str]]:
|
|
88
91
|
if not self._scanned_directory:
|
|
89
92
|
self._scan_directory()
|
|
90
93
|
|
|
@@ -100,7 +103,7 @@ class _FlatDirectorySource(LinkSource):
|
|
|
100
103
|
* ``file_candidates``: Archives in the directory.
|
|
101
104
|
"""
|
|
102
105
|
|
|
103
|
-
_paths_to_urls:
|
|
106
|
+
_paths_to_urls: dict[str, _FlatDirectoryToUrls] = {}
|
|
104
107
|
|
|
105
108
|
def __init__(
|
|
106
109
|
self,
|
|
@@ -119,7 +122,7 @@ class _FlatDirectorySource(LinkSource):
|
|
|
119
122
|
self._paths_to_urls[path] = self._path_to_urls
|
|
120
123
|
|
|
121
124
|
@property
|
|
122
|
-
def link(self) ->
|
|
125
|
+
def link(self) -> Link | None:
|
|
123
126
|
return None
|
|
124
127
|
|
|
125
128
|
def page_candidates(self) -> FoundCandidates:
|
|
@@ -150,7 +153,7 @@ class _LocalFileSource(LinkSource):
|
|
|
150
153
|
self._link = link
|
|
151
154
|
|
|
152
155
|
@property
|
|
153
|
-
def link(self) ->
|
|
156
|
+
def link(self) -> Link | None:
|
|
154
157
|
return self._link
|
|
155
158
|
|
|
156
159
|
def page_candidates(self) -> FoundCandidates:
|
|
@@ -184,7 +187,7 @@ class _RemoteFileSource(LinkSource):
|
|
|
184
187
|
self._link = link
|
|
185
188
|
|
|
186
189
|
@property
|
|
187
|
-
def link(self) ->
|
|
190
|
+
def link(self) -> Link | None:
|
|
188
191
|
return self._link
|
|
189
192
|
|
|
190
193
|
def page_candidates(self) -> FoundCandidates:
|
|
@@ -212,7 +215,7 @@ class _IndexDirectorySource(LinkSource):
|
|
|
212
215
|
self._link = link
|
|
213
216
|
|
|
214
217
|
@property
|
|
215
|
-
def link(self) ->
|
|
218
|
+
def link(self) -> Link | None:
|
|
216
219
|
return self._link
|
|
217
220
|
|
|
218
221
|
def page_candidates(self) -> FoundCandidates:
|
|
@@ -230,9 +233,9 @@ def build_source(
|
|
|
230
233
|
expand_dir: bool,
|
|
231
234
|
cache_link_parsing: bool,
|
|
232
235
|
project_name: str,
|
|
233
|
-
) ->
|
|
234
|
-
path:
|
|
235
|
-
url:
|
|
236
|
+
) -> tuple[str | None, LinkSource | None]:
|
|
237
|
+
path: str | None = None
|
|
238
|
+
url: str | None = None
|
|
236
239
|
if os.path.exists(location): # Is a local path.
|
|
237
240
|
url = path_to_url(location)
|
|
238
241
|
path = location
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import functools
|
|
2
4
|
import logging
|
|
3
5
|
import os
|
|
4
6
|
import pathlib
|
|
5
7
|
import sys
|
|
6
8
|
import sysconfig
|
|
7
|
-
from typing import Any
|
|
9
|
+
from typing import Any
|
|
8
10
|
|
|
9
11
|
from pip._internal.models.scheme import SCHEME_KEYS, Scheme
|
|
10
12
|
from pip._internal.utils.compat import WINDOWS
|
|
@@ -87,7 +89,7 @@ def _looks_like_bpo_44860() -> bool:
|
|
|
87
89
|
return unix_user_platlib == "$usersite"
|
|
88
90
|
|
|
89
91
|
|
|
90
|
-
def _looks_like_red_hat_patched_platlib_purelib(scheme:
|
|
92
|
+
def _looks_like_red_hat_patched_platlib_purelib(scheme: dict[str, str]) -> bool:
|
|
91
93
|
platlib = scheme["platlib"]
|
|
92
94
|
if "/$platlibdir/" in platlib:
|
|
93
95
|
platlib = platlib.replace("/$platlibdir/", f"/{_PLATLIBDIR}/")
|
|
@@ -97,7 +99,7 @@ def _looks_like_red_hat_patched_platlib_purelib(scheme: Dict[str, str]) -> bool:
|
|
|
97
99
|
return unpatched.replace("$platbase/", "$base/") == scheme["purelib"]
|
|
98
100
|
|
|
99
101
|
|
|
100
|
-
@functools.
|
|
102
|
+
@functools.cache
|
|
101
103
|
def _looks_like_red_hat_lib() -> bool:
|
|
102
104
|
"""Red Hat patches platlib in unix_prefix and unix_home, but not purelib.
|
|
103
105
|
|
|
@@ -112,7 +114,7 @@ def _looks_like_red_hat_lib() -> bool:
|
|
|
112
114
|
)
|
|
113
115
|
|
|
114
116
|
|
|
115
|
-
@functools.
|
|
117
|
+
@functools.cache
|
|
116
118
|
def _looks_like_debian_scheme() -> bool:
|
|
117
119
|
"""Debian adds two additional schemes."""
|
|
118
120
|
from distutils.command.install import INSTALL_SCHEMES
|
|
@@ -120,7 +122,7 @@ def _looks_like_debian_scheme() -> bool:
|
|
|
120
122
|
return "deb_system" in INSTALL_SCHEMES and "unix_local" in INSTALL_SCHEMES
|
|
121
123
|
|
|
122
124
|
|
|
123
|
-
@functools.
|
|
125
|
+
@functools.cache
|
|
124
126
|
def _looks_like_red_hat_scheme() -> bool:
|
|
125
127
|
"""Red Hat patches ``sys.prefix`` and ``sys.exec_prefix``.
|
|
126
128
|
|
|
@@ -140,7 +142,7 @@ def _looks_like_red_hat_scheme() -> bool:
|
|
|
140
142
|
)
|
|
141
143
|
|
|
142
144
|
|
|
143
|
-
@functools.
|
|
145
|
+
@functools.cache
|
|
144
146
|
def _looks_like_slackware_scheme() -> bool:
|
|
145
147
|
"""Slackware patches sysconfig but fails to patch distutils and site.
|
|
146
148
|
|
|
@@ -156,7 +158,7 @@ def _looks_like_slackware_scheme() -> bool:
|
|
|
156
158
|
return "/lib64/" in paths["purelib"] and "/lib64/" not in user_site
|
|
157
159
|
|
|
158
160
|
|
|
159
|
-
@functools.
|
|
161
|
+
@functools.cache
|
|
160
162
|
def _looks_like_msys2_mingw_scheme() -> bool:
|
|
161
163
|
"""MSYS2 patches distutils and sysconfig to use a UNIX-like scheme.
|
|
162
164
|
|
|
@@ -174,7 +176,7 @@ def _looks_like_msys2_mingw_scheme() -> bool:
|
|
|
174
176
|
)
|
|
175
177
|
|
|
176
178
|
|
|
177
|
-
@functools.
|
|
179
|
+
@functools.cache
|
|
178
180
|
def _warn_mismatched(old: pathlib.Path, new: pathlib.Path, *, key: str) -> None:
|
|
179
181
|
issue_url = "https://github.com/pypa/pip/issues/10151"
|
|
180
182
|
message = (
|
|
@@ -192,13 +194,13 @@ def _warn_if_mismatch(old: pathlib.Path, new: pathlib.Path, *, key: str) -> bool
|
|
|
192
194
|
return True
|
|
193
195
|
|
|
194
196
|
|
|
195
|
-
@functools.
|
|
197
|
+
@functools.cache
|
|
196
198
|
def _log_context(
|
|
197
199
|
*,
|
|
198
200
|
user: bool = False,
|
|
199
|
-
home:
|
|
200
|
-
root:
|
|
201
|
-
prefix:
|
|
201
|
+
home: str | None = None,
|
|
202
|
+
root: str | None = None,
|
|
203
|
+
prefix: str | None = None,
|
|
202
204
|
) -> None:
|
|
203
205
|
parts = [
|
|
204
206
|
"Additional context:",
|
|
@@ -214,10 +216,10 @@ def _log_context(
|
|
|
214
216
|
def get_scheme(
|
|
215
217
|
dist_name: str,
|
|
216
218
|
user: bool = False,
|
|
217
|
-
home:
|
|
218
|
-
root:
|
|
219
|
+
home: str | None = None,
|
|
220
|
+
root: str | None = None,
|
|
219
221
|
isolated: bool = False,
|
|
220
|
-
prefix:
|
|
222
|
+
prefix: str | None = None,
|
|
221
223
|
) -> Scheme:
|
|
222
224
|
new = _sysconfig.get_scheme(
|
|
223
225
|
dist_name,
|
|
@@ -281,7 +283,7 @@ def get_scheme(
|
|
|
281
283
|
continue
|
|
282
284
|
|
|
283
285
|
# On Python 3.9+, sysconfig's posix_user scheme sets platlib against
|
|
284
|
-
# sys.platlibdir, but distutils's unix_user incorrectly
|
|
286
|
+
# sys.platlibdir, but distutils's unix_user incorrectly continues
|
|
285
287
|
# using the same $usersite for both platlib and purelib. This creates a
|
|
286
288
|
# mismatch when sys.platlibdir is not "lib".
|
|
287
289
|
skip_bpo_44860 = (
|
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
#
|
|
10
10
|
# See https://github.com/pypa/pip/issues/8761 for the original discussion and
|
|
11
11
|
# rationale for why this is done within pip.
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
12
14
|
try:
|
|
13
15
|
__import__("_distutils_hack").remove_shim()
|
|
14
16
|
except (ImportError, AttributeError):
|
|
@@ -21,7 +23,6 @@ from distutils.cmd import Command as DistutilsCommand
|
|
|
21
23
|
from distutils.command.install import SCHEME_KEYS
|
|
22
24
|
from distutils.command.install import install as distutils_install_command
|
|
23
25
|
from distutils.sysconfig import get_python_lib
|
|
24
|
-
from typing import Dict, List, Optional, Union
|
|
25
26
|
|
|
26
27
|
from pip._internal.models.scheme import Scheme
|
|
27
28
|
from pip._internal.utils.compat import WINDOWS
|
|
@@ -35,19 +36,19 @@ logger = logging.getLogger(__name__)
|
|
|
35
36
|
def distutils_scheme(
|
|
36
37
|
dist_name: str,
|
|
37
38
|
user: bool = False,
|
|
38
|
-
home:
|
|
39
|
-
root:
|
|
39
|
+
home: str | None = None,
|
|
40
|
+
root: str | None = None,
|
|
40
41
|
isolated: bool = False,
|
|
41
|
-
prefix:
|
|
42
|
+
prefix: str | None = None,
|
|
42
43
|
*,
|
|
43
44
|
ignore_config_files: bool = False,
|
|
44
|
-
) ->
|
|
45
|
+
) -> dict[str, str]:
|
|
45
46
|
"""
|
|
46
47
|
Return a distutils install scheme
|
|
47
48
|
"""
|
|
48
49
|
from distutils.dist import Distribution
|
|
49
50
|
|
|
50
|
-
dist_args:
|
|
51
|
+
dist_args: dict[str, str | list[str]] = {"name": dist_name}
|
|
51
52
|
if isolated:
|
|
52
53
|
dist_args["script_args"] = ["--no-user-cfg"]
|
|
53
54
|
|
|
@@ -61,7 +62,7 @@ def distutils_scheme(
|
|
|
61
62
|
"Ignore distutils configs in %s due to encoding errors.",
|
|
62
63
|
", ".join(os.path.basename(p) for p in paths),
|
|
63
64
|
)
|
|
64
|
-
obj:
|
|
65
|
+
obj: DistutilsCommand | None = None
|
|
65
66
|
obj = d.get_command_obj("install", create=True)
|
|
66
67
|
assert obj is not None
|
|
67
68
|
i: distutils_install_command = obj
|
|
@@ -78,7 +79,7 @@ def distutils_scheme(
|
|
|
78
79
|
i.root = root or i.root
|
|
79
80
|
i.finalize_options()
|
|
80
81
|
|
|
81
|
-
scheme:
|
|
82
|
+
scheme: dict[str, str] = {}
|
|
82
83
|
for key in SCHEME_KEYS:
|
|
83
84
|
scheme[key] = getattr(i, "install_" + key)
|
|
84
85
|
|
|
@@ -115,10 +116,10 @@ def distutils_scheme(
|
|
|
115
116
|
def get_scheme(
|
|
116
117
|
dist_name: str,
|
|
117
118
|
user: bool = False,
|
|
118
|
-
home:
|
|
119
|
-
root:
|
|
119
|
+
home: str | None = None,
|
|
120
|
+
root: str | None = None,
|
|
120
121
|
isolated: bool = False,
|
|
121
|
-
prefix:
|
|
122
|
+
prefix: str | None = None,
|
|
122
123
|
) -> Scheme:
|
|
123
124
|
"""
|
|
124
125
|
Get the "scheme" corresponding to the input parameters. The distutils
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import logging
|
|
2
4
|
import os
|
|
3
5
|
import sys
|
|
4
6
|
import sysconfig
|
|
5
|
-
import typing
|
|
6
7
|
|
|
7
8
|
from pip._internal.exceptions import InvalidSchemeCombination, UserInstallationInvalid
|
|
8
9
|
from pip._internal.models.scheme import SCHEME_KEYS, Scheme
|
|
@@ -124,10 +125,10 @@ if sysconfig.get_config_var("userbase") is not None:
|
|
|
124
125
|
def get_scheme(
|
|
125
126
|
dist_name: str,
|
|
126
127
|
user: bool = False,
|
|
127
|
-
home:
|
|
128
|
-
root:
|
|
128
|
+
home: str | None = None,
|
|
129
|
+
root: str | None = None,
|
|
129
130
|
isolated: bool = False,
|
|
130
|
-
prefix:
|
|
131
|
+
prefix: str | None = None,
|
|
131
132
|
) -> Scheme:
|
|
132
133
|
"""
|
|
133
134
|
Get the "scheme" corresponding to the input parameters.
|