From cbe460ab1f6c227069f7948619a26cbfde9e34da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Randy=20D=C3=B6ring?= <30527984+radoering@users.noreply.github.com> Date: Sun, 25 Sep 2022 17:51:57 +0200 Subject: [PATCH] canonicalized extras names --- src/poetry_plugin_export/command.py | 9 +++++++-- src/poetry_plugin_export/exporter.py | 5 +++-- src/poetry_plugin_export/walker.py | 12 ++++++++++-- tests/command/test_command_export.py | 2 +- tests/test_exporter.py | 5 +++-- 5 files changed, 24 insertions(+), 9 deletions(-) diff --git a/src/poetry_plugin_export/command.py b/src/poetry_plugin_export/command.py index ee60220..49d8b49 100644 --- a/src/poetry_plugin_export/command.py +++ b/src/poetry_plugin_export/command.py @@ -1,6 +1,7 @@ from __future__ import annotations from cleo.helpers import option +from packaging.utils import canonicalize_name from poetry.console.commands.group_command import GroupCommand from poetry.core.packages.dependency_group import MAIN_GROUP @@ -84,9 +85,13 @@ def handle(self) -> None: # Checking extras extras = { - extra for extra_opt in self.option("extras") for extra in extra_opt.split() + canonicalize_name(extra) + for extra_opt in self.option("extras") + for extra in extra_opt.split() + } + invalid_extras = extras - { + canonicalize_name(extra) for extra in self.poetry.package.extras } - invalid_extras = extras - self.poetry.package.extras.keys() if invalid_extras: raise ValueError( f"Extra [{', '.join(sorted(invalid_extras))}] is not specified." diff --git a/src/poetry_plugin_export/exporter.py b/src/poetry_plugin_export/exporter.py index cacb439..9020293 100644 --- a/src/poetry_plugin_export/exporter.py +++ b/src/poetry_plugin_export/exporter.py @@ -15,6 +15,7 @@ if TYPE_CHECKING: from pathlib import Path + from packaging.utils import NormalizedName from poetry.poetry import Poetry @@ -33,14 +34,14 @@ def __init__(self, poetry: Poetry) -> None: self._with_hashes = True self._with_credentials = False self._with_urls = True - self._extras: bool | list[str] | None = [] + self._extras: bool | list[NormalizedName] | None = [] self._groups: Iterable[str] = [MAIN_GROUP] @classmethod def is_format_supported(cls, fmt: str) -> bool: return fmt in cls.EXPORT_METHODS - def with_extras(self, extras: bool | list[str] | None) -> Exporter: + def with_extras(self, extras: bool | list[NormalizedName] | None) -> Exporter: self._extras = extras return self diff --git a/src/poetry_plugin_export/walker.py b/src/poetry_plugin_export/walker.py index f2ab977..619b806 100644 --- a/src/poetry_plugin_export/walker.py +++ b/src/poetry_plugin_export/walker.py @@ -2,6 +2,7 @@ from typing import TYPE_CHECKING +from packaging.utils import canonicalize_name from poetry.core.semver.util import constraint_regions from poetry.core.version.markers import AnyMarker from poetry.core.version.markers import SingleMarker @@ -14,6 +15,7 @@ from collections.abc import Iterator from collections.abc import Sequence + from packaging.utils import NormalizedName from poetry.core.packages.dependency import Dependency from poetry.core.packages.package import Package from poetry.core.version.markers import BaseMarker @@ -51,7 +53,7 @@ def get_project_dependency_packages( locker: Locker, project_requires: list[Dependency], project_python_marker: BaseMarker | None = None, - extras: bool | Sequence[str] | None = None, + extras: bool | Sequence[NormalizedName] | None = None, ) -> Iterator[DependencyPackage]: # Apply the project python marker to all requirements. if project_python_marker is not None: @@ -68,10 +70,16 @@ def get_project_dependency_packages( extra_package_names: set[str] | None = None if extras is not True: + locked_extras = { + canonicalize_name(extra): [ + canonicalize_name(dependency) for dependency in dependencies + ] + for extra, dependencies in locker.lock_data.get("extras", {}).items() + } extra_package_names = set( get_extra_package_names( repository.packages, - locker.lock_data.get("extras", {}), + locked_extras, # type: ignore[arg-type] extras or (), ) ) diff --git a/tests/command/test_command_export.py b/tests/command/test_command_export.py index cf7fb37..e226b7f 100644 --- a/tests/command/test_command_export.py +++ b/tests/command/test_command_export.py @@ -209,7 +209,7 @@ def test_export_includes_extras_by_flag( def test_export_reports_invalid_extras(tester: CommandTester, do_lock: None) -> None: with pytest.raises(ValueError) as error: tester.execute("--format requirements.txt --extras 'SUS AMONGUS'") - expected = "Extra [AMONGUS, SUS] is not specified." + expected = "Extra [amongus, sus] is not specified." assert str(error.value) == expected diff --git a/tests/test_exporter.py b/tests/test_exporter.py index 85d041f..8dcda3e 100644 --- a/tests/test_exporter.py +++ b/tests/test_exporter.py @@ -37,6 +37,7 @@ if TYPE_CHECKING: + from packaging.utils import NormalizedName from poetry.poetry import Poetry from pytest_mock import MockerFixture @@ -920,7 +921,7 @@ def test_exporter_exports_requirements_txt_without_optional_packages( ], ), ( - ["feature_bar"], + ["feature-bar"], [ f"bar==4.5.6 ; {MARKER_PY}", f"foo==1.2.3 ; {MARKER_PY}", @@ -932,7 +933,7 @@ def test_exporter_exports_requirements_txt_without_optional_packages( def test_exporter_exports_requirements_txt_with_optional_packages( tmp_dir: str, poetry: Poetry, - extras: bool | list[str] | None, + extras: bool | list[NormalizedName] | None, lines: list[str], ) -> None: poetry.locker.mock_lock_data( # type: ignore[attr-defined]