diff --git a/src/poetry/console/commands/check.py b/src/poetry/console/commands/check.py index ae90004d318..a79b7bc2be3 100644 --- a/src/poetry/console/commands/check.py +++ b/src/poetry/console/commands/check.py @@ -5,6 +5,7 @@ from typing import ClassVar from cleo.helpers import option +from poetry.core.utils.helpers import module_name from poetry.console.commands.command import Command @@ -128,6 +129,46 @@ def _validate_dependencies_source(self, config: dict[str, Any]) -> list[str]: for source in sorted(all_referenced_sources - sources) ] + def _validate_project_in_src( + self, toml_data: dict[str, Any], base_path: Path | None + ) -> list[str]: + """ + Checks the validity of projects located under src/ subdirectory. + """ + result: list[str] = [] + + project_name = toml_data.get("project", {}).get("name") or toml_data.get( + "tool", {} + ).get("poetry", {}).get("name") + + if project_name is None or base_path is None: + return result + + project_name = module_name(project_name) + + project_dir = base_path / project_name + src_project_dir = base_path / "src" / project_name + + project_dir_empty = ( + project_dir.exists() + and project_dir.is_dir() + and not any(project_dir.iterdir()) + ) + src_dir_not_empty = ( + src_project_dir.exists() + and src_project_dir.is_dir() + and any(src_project_dir.iterdir()) + ) + + if project_dir_empty and src_dir_not_empty: + result.append( + f"Found empty directory '{project_name}' in project root while the actual package is in " + f"'src/{project_name}'. This may cause issues with package installation. " + "Consider removing the empty directory." + ) + + return result + def handle(self) -> int: from poetry.core.pyproject.toml import PyProjectTOML @@ -149,6 +190,10 @@ def handle(self) -> int: check_result["errors"].extend(errors) check_result["warnings"].extend(warnings) + project_root = poetry_file.parent + warnings = self._validate_project_in_src(toml_data, project_root) + check_result["warnings"].extend(warnings) + # Validate readme (files must exist) # TODO: consider [project.readme] as well if "readme" in poetry_config: diff --git a/tests/console/commands/test_check.py b/tests/console/commands/test_check.py index 6a23a2c093f..f40316d9e28 100644 --- a/tests/console/commands/test_check.py +++ b/tests/console/commands/test_check.py @@ -1,5 +1,7 @@ from __future__ import annotations +import os + from typing import TYPE_CHECKING import pytest @@ -59,6 +61,14 @@ def poetry_with_invalid_pyproject( yield Factory().create_poetry(cwd) +@pytest.fixture +def poetry_with_src_folder( + set_project_context: SetProjectContext, +) -> Iterator[Poetry]: + with set_project_context("project_with_src_folder", in_place=False) as cwd: + yield Factory().create_poetry(cwd) + + @pytest.fixture() def tester( command_tester_factory: CommandTesterFactory, poetry_simple_project: Poetry @@ -309,3 +319,24 @@ def test_check_does_not_error_on_pypi_reference( assert tester.io.fetch_output() == "All set!\n" assert status_code == 0 + + +def test_check_project_with_src_folder( + command_tester_factory: CommandTesterFactory, + poetry_with_src_folder: Poetry, +) -> None: + tester = command_tester_factory("check", poetry=poetry_with_src_folder) + + poetry_file = poetry_with_src_folder.file.path + project_root = poetry_file.parent + project_dir = project_root / "project_with_src_folder" + os.makedirs(project_dir, exist_ok=True) + tester.execute("") + + expected = """\ +Warning: Found empty directory 'project_with_src_folder' in project root while the actual package is in\ + 'src/project_with_src_folder'. This may cause issues with package installation.\ + Consider removing the empty directory. +""" + + assert tester.io.fetch_error() == expected diff --git a/tests/fixtures/project_with_src_folder/pyproject.toml b/tests/fixtures/project_with_src_folder/pyproject.toml new file mode 100644 index 00000000000..e86df64968b --- /dev/null +++ b/tests/fixtures/project_with_src_folder/pyproject.toml @@ -0,0 +1,12 @@ +[project] +name = "project-with-src-folder" +version = "1.2.3" +description = "This is a description" +authors = [] +license = "MIT" + + +[tool.poetry] +packages = [] + +[tool.poetry.group.dev.dependencies] diff --git a/tests/fixtures/project_with_src_folder/src/project_with_src_folder/__init__.py b/tests/fixtures/project_with_src_folder/src/project_with_src_folder/__init__.py new file mode 100644 index 00000000000..e69de29bb2d