diff --git a/doc/changes/unreleased.md b/doc/changes/unreleased.md index 94fdd7479..ba7fefbda 100644 --- a/doc/changes/unreleased.md +++ b/doc/changes/unreleased.md @@ -5,3 +5,7 @@ ## ✨ Features * #426: Allowed configuring the python version used for coverage + +## Bugfixes + +* #463: Fixed dependency:licenses to correctly parse exceptional names \ No newline at end of file diff --git a/exasol/toolbox/util/dependencies/poetry_dependencies.py b/exasol/toolbox/util/dependencies/poetry_dependencies.py index de6bb5acc..9fb9f0156 100644 --- a/exasol/toolbox/util/dependencies/poetry_dependencies.py +++ b/exasol/toolbox/util/dependencies/poetry_dependencies.py @@ -2,13 +2,13 @@ import re import subprocess +import sys from pathlib import Path from typing import Optional import tomlkit from pydantic import ( BaseModel, - model_validator, ) from tomlkit import TOMLDocument @@ -84,19 +84,33 @@ class PoetryDependencies(BaseModel): working_directory: Path @staticmethod - def _extract_from_line(line: str) -> Package: - pattern = r"\s+(\d+(?:\.\d+)*)\s+" - match = re.split(pattern, line) - return Package(name=match[0], version=match[1]) # + def _extract_from_line(line: str) -> Optional[Package]: + # remove (!) from line as indicates not installed in environment, + # which could occur for optional dependencies + split_line = line.replace("(!)", "").strip().split(maxsplit=2) + if len(split_line) < 2: + print(f"Unable to parse dependency={line}") + return None + return Package(name=split_line[0], version=split_line[1]) def _extract_from_poetry_show(self, output_text: str) -> list[Package]: - return [self._extract_from_line(line) for line in output_text.splitlines()] + return [ + package + for line in output_text.splitlines() + if (package := self._extract_from_line(line)) + ] @property def direct_dependencies(self) -> dict[str, list[Package]]: dependencies = {} for group in self.groups: - command = ("poetry", "show", "--top-level", f"--only={group.name}") + command = ( + "poetry", + "show", + "--top-level", + f"--only={group.name}", + "--no-truncate", + ) output = subprocess.run( command, capture_output=True, @@ -110,7 +124,7 @@ def direct_dependencies(self) -> dict[str, list[Package]]: @property def all_dependencies(self) -> dict[str, list[Package]]: - command = ("poetry", "show") + command = ("poetry", "show", "--no-truncate") output = subprocess.run( command, capture_output=True, @@ -128,7 +142,7 @@ def all_dependencies(self) -> dict[str, list[Package]]: } for line in output.stdout.splitlines(): dep = self._extract_from_line(line=line) - if dep.name not in names_direct_dependencies: + if dep and dep.name not in names_direct_dependencies: transitive_dependencies.append(dep) return direct_dependencies | {TRANSITIVE_GROUP.name: transitive_dependencies} diff --git a/test/unit/util/dependencies/poetry_dependencies_test.py b/test/unit/util/dependencies/poetry_dependencies_test.py index 0edf86092..e5b8212bf 100644 --- a/test/unit/util/dependencies/poetry_dependencies_test.py +++ b/test/unit/util/dependencies/poetry_dependencies_test.py @@ -95,6 +95,14 @@ class TestPoetryDependencies: "import-linter 2.3 Enforces rules for the imports within and between Python packages.", Package(name="import-linter", version="2.3"), ), + ( + "python-dateutil 2.9.0.post0 Extensions to the standard Python datetime module", + Package(name="python-dateutil", version="2.9.0.post0"), + ), + ( + "types-requests 2.32.0.20250602", + Package(name="types-requests", version="2.32.0.20250602"), + ), ], ) def test_extract_from_line(line, expected):