diff --git a/src/griffe/loader.py b/src/griffe/loader.py index dbfc0dd8..8ad59353 100644 --- a/src/griffe/loader.py +++ b/src/griffe/loader.py @@ -200,7 +200,9 @@ def load( try: top_module_path = top_module_object.__path__ - except AttributeError: + if not top_module_path: + raise ValueError(f"Module {top_module_name} has no paths set") # noqa: TRY301 + except (AttributeError, ValueError): # If the top-level module has no `__path__`, we inspect it as-is, # and do not try to recurse into submodules (there shouldn't be any in builtin/compiled modules). logger.debug(f"Module {top_module_name} has no paths set (built-in module?). Inspecting it as-is.") @@ -212,6 +214,7 @@ def load( # We found paths, and use them to build our intermediate Package or NamespacePackage struct. logger.debug(f"Module {top_module_name} has paths set: {top_module_path}") + top_module_path = [Path(path) for path in top_module_path] if len(top_module_path) > 1: package = NamespacePackage(top_module_name, top_module_path) else: diff --git a/tests/test_loader.py b/tests/test_loader.py index a33e6a0c..e153dc73 100644 --- a/tests/test_loader.py +++ b/tests/test_loader.py @@ -464,3 +464,14 @@ def test_forcing_inspection() -> None: for name in static_package["mod"].members: assert name in dynamic_package["mod"].members clear_sys_modules("pkg") + + +def test_relying_on_modules_path_attribute(monkeypatch: pytest.MonkeyPatch) -> None: + """Load a package that relies on the `__path__` attribute of a module.""" + + def raise_module_not_found_error(*args, **kwargs) -> None: # noqa: ARG001,ANN002,ANN003 + raise ModuleNotFoundError + + loader = GriffeLoader() + monkeypatch.setattr(loader.finder, "find_spec", raise_module_not_found_error) + assert loader.load("griffe")