diff --git a/src/pydocstyle/parser.py b/src/pydocstyle/parser.py index a5470484..0b97a14d 100644 --- a/src/pydocstyle/parser.py +++ b/src/pydocstyle/parser.py @@ -119,7 +119,16 @@ def is_public(self): This helps determine if it requires a docstring. """ module_name = Path(self.name).name - return not module_name.startswith('_') or module_name.startswith('__') + return ( + not self._is_inside_private_package() and + (not module_name.startswith('_') or module_name.startswith('__')) + ) + + def _is_inside_private_package(self): + """Return True if the module is inside a private package.""" + path = Path(self.name) + package_names = path.parts[:-1] + return any([package.startswith('_') for package in package_names]) def __str__(self): return 'at module level' diff --git a/src/tests/parser_test.py b/src/tests/parser_test.py index dd4b75cf..0de5a252 100644 --- a/src/tests/parser_test.py +++ b/src/tests/parser_test.py @@ -575,6 +575,13 @@ def test_module_publicity(parent_path): module = parser.parse(code, str(parent_path / "filepath")) assert module.is_public + module = parser.parse(code, str(parent_path / "_private_pkg" / "filepath")) + assert not module.is_public + + module = parser.parse(code, str( + parent_path / "_private_pkg" / "some_pkg" / "filepath")) + assert not module.is_public + module = parser.parse(code, str(parent_path / "_filepath")) assert not module.is_public