extras.py (poetry-1.1.15) | : | extras.py (poetry-1.2.0) | ||
---|---|---|---|---|
from typing import Iterator | from __future__ import annotations | |||
from typing import List | ||||
from typing import Mapping | ||||
from typing import Sequence | ||||
from poetry.core.packages import Package | from typing import TYPE_CHECKING | |||
from poetry.utils.helpers import canonicalize_name | ||||
if TYPE_CHECKING: | ||||
from collections.abc import Iterable | ||||
from collections.abc import Iterator | ||||
from collections.abc import Sequence | ||||
from typing import Mapping | ||||
from packaging.utils import NormalizedName | ||||
from poetry.core.packages.package import Package | ||||
def get_extra_package_names( | def get_extra_package_names( | |||
packages, # type: Sequence[Package] | packages: Sequence[Package], | |||
extras, # type: Mapping[str, List[str]] | extras: Mapping[str, list[str]], | |||
extra_names, # type: Sequence[str] | extra_names: Sequence[str], | |||
): # type: (...) -> Iterator[str] | ) -> Iterable[str]: | |||
""" | """ | |||
Returns all package names required by the given extras. | Returns all package names required by the given extras. | |||
:param packages: A collection of packages, such as from Repository.packages | :param packages: A collection of packages, such as from Repository.packages | |||
:param extras: A mapping of `extras` names to lists of package names, as def ined | :param extras: A mapping of `extras` names to lists of package names, as def ined | |||
in the `extras` section of `poetry.lock`. | in the `extras` section of `poetry.lock`. | |||
:param extra_names: A list of strings specifying names of extra groups to re solve. | :param extra_names: A list of strings specifying names of extra groups to re solve. | |||
""" | """ | |||
from packaging.utils import canonicalize_name | ||||
if not extra_names: | if not extra_names: | |||
return [] | return [] | |||
# lookup for packages by name, faster than looping over packages repeatedly | # lookup for packages by name, faster than looping over packages repeatedly | |||
packages_by_name = {package.name: package for package in packages} | packages_by_name = {package.name: package for package in packages} | |||
# get and flatten names of packages we've opted into as extras | # get and flatten names of packages we've opted into as extras | |||
extra_package_names = [ | extra_package_names = [ | |||
canonicalize_name(extra_package_name) | canonicalize_name(extra_package_name) | |||
for extra_name in extra_names | for extra_name in extra_names | |||
for extra_package_name in extras.get(extra_name, ()) | for extra_package_name in extras.get(extra_name, ()) | |||
] | ] | |||
# keep record of packages seen during recursion in order to avoid recursion error | # keep record of packages seen during recursion in order to avoid recursion error | |||
seen_package_names = set() | seen_package_names = set() | |||
def _extra_packages(package_names): | def _extra_packages( | |||
package_names: Iterable[NormalizedName], | ||||
) -> Iterator[NormalizedName]: | ||||
"""Recursively find dependencies for packages names""" | """Recursively find dependencies for packages names""" | |||
# for each extra pacakge name | # for each extra package name | |||
for package_name in package_names: | for package_name in package_names: | |||
# Find the actual Package object. A missing key indicates an implici t | # Find the actual Package object. A missing key indicates an implici t | |||
# dependency (like setuptools), which should be ignored | # dependency (like setuptools), which should be ignored | |||
package = packages_by_name.get(canonicalize_name(package_name)) | package = packages_by_name.get(package_name) | |||
if package: | if package: | |||
if package.name not in seen_package_names: | if package.name not in seen_package_names: | |||
seen_package_names.add(package.name) | seen_package_names.add(package.name) | |||
yield package.name | yield package.name | |||
# Recurse for dependencies | # Recurse for dependencies | |||
for dependency_package_name in _extra_packages( | for dependency_package_name in _extra_packages( | |||
dependency.name | dependency.name | |||
for dependency in package.requires | for dependency in package.requires | |||
if dependency.name not in seen_package_names | if dependency.name not in seen_package_names | |||
): | ): | |||
End of changes. 7 change blocks. | ||||
13 lines changed or deleted | 22 lines changed or added |