From 2a9da889c6892c542408e8d1112b13f1c276bfe0 Mon Sep 17 00:00:00 2001 From: Mathieu Kniewallner Date: Fri, 15 Nov 2024 23:06:31 +0100 Subject: [PATCH] fix(dependency_getter): handle strings for `setuptools` dynamic dependencies (#945) --- .../deptry/dependency_getter/pep621/base.py | 13 ++++-- .../pyproject.toml | 3 +- tests/unit/dependency_getter/test_pep_621.py | 40 +++++++++++++++++-- 3 files changed, 48 insertions(+), 8 deletions(-) diff --git a/python/deptry/dependency_getter/pep621/base.py b/python/deptry/dependency_getter/pep621/base.py index 1118adfc..d400ca78 100644 --- a/python/deptry/dependency_getter/pep621/base.py +++ b/python/deptry/dependency_getter/pep621/base.py @@ -64,9 +64,11 @@ def _get_dependencies(self) -> list[Dependency]: if self._project_uses_setuptools(pyproject_data) and "dependencies" in pyproject_data["project"].get( "dynamic", {} ): - return get_dependencies_from_requirements_files( - pyproject_data["tool"]["setuptools"]["dynamic"]["dependencies"]["file"], self.package_module_name_map - ) + dependencies_files = pyproject_data["tool"]["setuptools"]["dynamic"]["dependencies"]["file"] + if isinstance(dependencies_files, str): + dependencies_files = [dependencies_files] + + return get_dependencies_from_requirements_files(dependencies_files, self.package_module_name_map) dependency_strings: list[str] = pyproject_data["project"].get("dependencies", []) return self._extract_pep_508_dependencies(dependency_strings) @@ -79,7 +81,10 @@ def _get_optional_dependencies(self) -> dict[str, list[Dependency]]: "dynamic", {} ): return { - group: get_dependencies_from_requirements_files(specification["file"], self.package_module_name_map) + group: get_dependencies_from_requirements_files( + [specification["file"]] if isinstance(specification["file"], str) else specification["file"], + self.package_module_name_map, + ) for group, specification in pyproject_data["tool"]["setuptools"]["dynamic"] .get("optional-dependencies", {}) .items() diff --git a/tests/fixtures/project_with_setuptools_dynamic_dependencies/pyproject.toml b/tests/fixtures/project_with_setuptools_dynamic_dependencies/pyproject.toml index 5cdd3c7b..dbaa4a3e 100644 --- a/tests/fixtures/project_with_setuptools_dynamic_dependencies/pyproject.toml +++ b/tests/fixtures/project_with_setuptools_dynamic_dependencies/pyproject.toml @@ -12,7 +12,8 @@ dynamic = ["dependencies", "optional-dependencies"] dependencies = { file = ["requirements.txt", "requirements-2.txt"] } [tool.setuptools.dynamic.optional-dependencies] -cli = { file = ["cli-requirements.txt"] } +# Both strings and list of strings are accepted. +cli = { file = "cli-requirements.txt" } dev = { file = ["dev-requirements.txt"] } [tool.deptry] diff --git a/tests/unit/dependency_getter/test_pep_621.py b/tests/unit/dependency_getter/test_pep_621.py index 62ff3f0a..1bb50086 100644 --- a/tests/unit/dependency_getter/test_pep_621.py +++ b/tests/unit/dependency_getter/test_pep_621.py @@ -203,7 +203,8 @@ def test_dependency_getter_with_setuptools_dynamic_dependencies(tmp_path: Path) dependencies = { file = ["requirements.txt", "requirements-2.txt"] } [tool.setuptools.dynamic.optional-dependencies] -cli = { file = ["cli-requirements.txt"] } +# Both strings and list of strings are accepted. +cli = { file = "cli-requirements.txt" } dev = { file = ["dev-requirements.txt"] } """ @@ -245,7 +246,8 @@ def test_dependency_getter_with_setuptools_dynamic_dependencies_without_build_ba dependencies = { file = ["requirements.txt", "requirements-2.txt"] } [tool.setuptools.dynamic.optional-dependencies] -cli = { file = ["cli-requirements.txt"] } +# Both strings and list of strings are accepted. +cli = { file = "cli-requirements.txt" } dev = { file = ["dev-requirements.txt"] } """ @@ -286,7 +288,8 @@ def test_dependency_getter_with_setuptools_dynamic_dependencies_with_another_bui dependencies = { file = ["requirements.txt", "requirements-2.txt"] } [tool.setuptools.dynamic.optional-dependencies] -cli = { file = ["cli-requirements.txt"] } +# Both strings and list of strings are accepted. +cli = { file = "cli-requirements.txt" } dev = { file = ["dev-requirements.txt"] } """ @@ -344,3 +347,34 @@ def test_dependency_getter_with_setuptools_dynamic_dependencies_only_optional(tm assert dependencies[0].name == "foo" assert dev_dependencies[0].name == "dev-dep" + + +def test_dependency_getter_with_setuptools_dynamic_dependencies_only_dependencies(tmp_path: Path) -> None: + fake_pyproject_toml = """[build-system] +requires = ["setuptools"] +build-backend = "setuptools.build_meta" + +[project] +name = "foo" +dependencies = ["foo==1.2.3"] +dynamic = ["dependencies"] + +[tool.setuptools.dynamic] +dependencies = { file = "requirements.txt" } +""" + + with run_within_dir(tmp_path): + with Path("pyproject.toml").open("w") as f: + f.write(fake_pyproject_toml) + + with Path("requirements.txt").open("w") as f: + f.write("foo==1.2.3") + + extract = PEP621DependencyGetter(config=Path("pyproject.toml"), pep621_dev_dependency_groups=("dev",)).get() + dependencies = extract.dependencies + dev_dependencies = extract.dev_dependencies + + assert len(dependencies) == 1 + assert len(dev_dependencies) == 0 + + assert dependencies[0].name == "foo"