Voice et bot modif

This commit is contained in:
pi 2026-06-16 17:09:34 +00:00
parent 189d56026b
commit 7333a22bcd
10774 changed files with 634644 additions and 933308 deletions

View file

@ -1,47 +1,40 @@
"""Validation of dependencies of packages"""
from __future__ import annotations
"""Validation of dependencies of packages
"""
import logging
from collections.abc import Generator, Iterable
from contextlib import suppress
from email.parser import Parser
from functools import reduce
from typing import (
Callable,
NamedTuple,
)
from typing import Callable, Dict, List, NamedTuple, Optional, Set, Tuple
from pip._vendor.packaging.requirements import Requirement
from pip._vendor.packaging.tags import Tag, parse_tag
from pip._vendor.packaging.specifiers import LegacySpecifier
from pip._vendor.packaging.utils import NormalizedName, canonicalize_name
from pip._vendor.packaging.version import Version
from pip._vendor.packaging.version import LegacyVersion
from pip._internal.distributions import make_distribution_for_install_requirement
from pip._internal.metadata import get_default_environment
from pip._internal.metadata.base import BaseDistribution
from pip._internal.metadata.base import DistributionVersion
from pip._internal.req.req_install import InstallRequirement
from pip._internal.utils.deprecation import deprecated
logger = logging.getLogger(__name__)
class PackageDetails(NamedTuple):
version: Version
dependencies: list[Requirement]
version: DistributionVersion
dependencies: List[Requirement]
# Shorthands
PackageSet = dict[NormalizedName, PackageDetails]
Missing = tuple[NormalizedName, Requirement]
Conflicting = tuple[NormalizedName, Version, Requirement]
PackageSet = Dict[NormalizedName, PackageDetails]
Missing = Tuple[NormalizedName, Requirement]
Conflicting = Tuple[NormalizedName, DistributionVersion, Requirement]
MissingDict = dict[NormalizedName, list[Missing]]
ConflictingDict = dict[NormalizedName, list[Conflicting]]
CheckResult = tuple[MissingDict, ConflictingDict]
ConflictDetails = tuple[PackageSet, CheckResult]
MissingDict = Dict[NormalizedName, List[Missing]]
ConflictingDict = Dict[NormalizedName, List[Conflicting]]
CheckResult = Tuple[MissingDict, ConflictingDict]
ConflictDetails = Tuple[PackageSet, CheckResult]
def create_package_set_from_installed() -> tuple[PackageSet, bool]:
def create_package_set_from_installed() -> Tuple[PackageSet, bool]:
"""Converts a list of distributions into a PackageSet."""
package_set = {}
problems = False
@ -53,13 +46,13 @@ def create_package_set_from_installed() -> tuple[PackageSet, bool]:
package_set[name] = PackageDetails(dist.version, dependencies)
except (OSError, ValueError) as e:
# Don't crash on unreadable or broken metadata.
logger.warning("Error parsing dependencies of %s: %s", name, e)
logger.warning("Error parsing requirements for %s: %s", name, e)
problems = True
return package_set, problems
def check_package_set(
package_set: PackageSet, should_ignore: Callable[[str], bool] | None = None
package_set: PackageSet, should_ignore: Optional[Callable[[str], bool]] = None
) -> CheckResult:
"""Check if a package set is consistent
@ -67,13 +60,15 @@ def check_package_set(
package name and returns a boolean.
"""
warn_legacy_versions_and_specifiers(package_set)
missing = {}
conflicting = {}
for package_name, package_detail in package_set.items():
# Info about dependencies of package_name
missing_deps: set[Missing] = set()
conflicting_deps: set[Conflicting] = set()
missing_deps: Set[Missing] = set()
conflicting_deps: Set[Conflicting] = set()
if should_ignore and should_ignore(package_name):
continue
@ -103,7 +98,7 @@ def check_package_set(
return missing, conflicting
def check_install_conflicts(to_install: list[InstallRequirement]) -> ConflictDetails:
def check_install_conflicts(to_install: List[InstallRequirement]) -> ConflictDetails:
"""For checking if the dependency graph would be consistent after \
installing given requirements
"""
@ -123,25 +118,9 @@ def check_install_conflicts(to_install: list[InstallRequirement]) -> ConflictDet
)
def check_unsupported(
packages: Iterable[BaseDistribution],
supported_tags: Iterable[Tag],
) -> Generator[BaseDistribution, None, None]:
for p in packages:
with suppress(FileNotFoundError):
wheel_file = p.read_text("WHEEL")
wheel_tags: frozenset[Tag] = reduce(
frozenset.union,
map(parse_tag, Parser().parsestr(wheel_file).get_all("Tag", [])),
frozenset(),
)
if wheel_tags.isdisjoint(supported_tags):
yield p
def _simulate_installation_of(
to_install: list[InstallRequirement], package_set: PackageSet
) -> set[NormalizedName]:
to_install: List[InstallRequirement], package_set: PackageSet
) -> Set[NormalizedName]:
"""Computes the version of packages after installing to_install."""
# Keep track of packages that were installed
installed = set()
@ -159,8 +138,8 @@ def _simulate_installation_of(
def _create_whitelist(
would_be_installed: set[NormalizedName], package_set: PackageSet
) -> set[NormalizedName]:
would_be_installed: Set[NormalizedName], package_set: PackageSet
) -> Set[NormalizedName]:
packages_affected = set(would_be_installed)
for package_name in package_set:
@ -173,3 +152,36 @@ def _create_whitelist(
break
return packages_affected
def warn_legacy_versions_and_specifiers(package_set: PackageSet) -> None:
for project_name, package_details in package_set.items():
if isinstance(package_details.version, LegacyVersion):
deprecated(
reason=(
f"{project_name} {package_details.version} "
f"has a non-standard version number."
),
replacement=(
f"to upgrade to a newer version of {project_name} "
f"or contact the author to suggest that they "
f"release a version with a conforming version number"
),
issue=12063,
gone_in="24.1",
)
for dep in package_details.dependencies:
if any(isinstance(spec, LegacySpecifier) for spec in dep.specifier):
deprecated(
reason=(
f"{project_name} {package_details.version} "
f"has a non-standard dependency specifier {dep}."
),
replacement=(
f"to upgrade to a newer version of {project_name} "
f"or contact the author to suggest that they "
f"release a version with a conforming dependency specifiers"
),
issue=12063,
gone_in="24.1",
)