Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/usethis/_integrations/project/packages.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ def _get_packages_in_dir(path: Path) -> set[str]:
"""Get the names of packages in the given directory."""
return {
Path(module_name).name
for _, module_name, _ in pkgutil.iter_modules([path.as_posix()])
if not _is_excluded(module_name)
for _, module_name, ispkg in pkgutil.iter_modules([path.as_posix()])
if ispkg and not _is_excluded(module_name)
}


Expand Down
36 changes: 36 additions & 0 deletions tests/usethis/_integrations/project/test_packages.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,39 @@ def test_multiple_namespace_packages(self, tmp_path: Path):

with change_cwd(tmp_path):
assert get_importable_packages() == {"foo", "bar"}

def test_flat_layout_excludes_root_py_files(self, tmp_path: Path):
"""Test that root-level .py files are excluded in a flat layout.

In a flat layout (no src/ directory), standalone .py files like
setup.py or conftest.py should not be detected as importable packages.
Only directories with __init__.py should be included.
"""
(tmp_path / "foo").mkdir()
(tmp_path / "foo" / "__init__.py").touch()
(tmp_path / "foo" / "bar.py").touch()
# Root-level .py files that should be excluded
(tmp_path / "setup.py").touch()
(tmp_path / "conftest.py").touch()

with change_cwd(tmp_path):
# Should only include "foo" package, not "setup" or "conftest" modules
assert get_importable_packages() == {"foo"}

def test_src_layout_excludes_root_py_files(self, tmp_path: Path):
"""Test that root-level .py files are excluded in a src/ layout.

In a src/ layout, standalone .py files in src/ like __init__.py
(without a package directory) should not be detected as importable packages.
"""
(tmp_path / "src").mkdir()
(tmp_path / "src" / "foo").mkdir()
(tmp_path / "src" / "foo" / "__init__.py").touch()
(tmp_path / "src" / "foo" / "bar.py").touch()
# Root-level .py files in src/ that should be excluded
(tmp_path / "src" / "conftest.py").touch()
(tmp_path / "src" / "helper.py").touch()

with change_cwd(tmp_path):
# Should only include "foo" package, not "conftest" or "helper" modules
assert get_importable_packages() == {"foo"}