diff --git a/importlib_resources/_common.py b/importlib_resources/_common.py index 3e665b9..4e7c913 100644 --- a/importlib_resources/_common.py +++ b/importlib_resources/_common.py @@ -71,6 +71,19 @@ def is_wrapper(frame_info): return next(callers).frame +def _assert_spec(package: types.ModuleType) -> None: + """ + Provide a nicer error message when package is ``__main__`` + and its ``__spec__`` is ``None`` + (https://docs.python.org/3/reference/import.html#main-spec). + """ + if package.__spec__ is None: + raise TypeError( + f"Cannot access resources for '{package.__name__}' " + "as it does not appear to correspond to an importable module (its __spec__ is None)." + ) + + def from_package(package: types.ModuleType): """ Return a Traversable object for the given package. @@ -79,6 +92,7 @@ def from_package(package: types.ModuleType): # deferred for performance (python/cpython#109829) from .future.adapters import wrap_spec + _assert_spec(package) spec = wrap_spec(package) reader = spec.loader.get_resource_reader(spec.name) return reader.files() diff --git a/importlib_resources/tests/test_resource.py b/importlib_resources/tests/test_resource.py index ed9fa19..63a8bfb 100644 --- a/importlib_resources/tests/test_resource.py +++ b/importlib_resources/tests/test_resource.py @@ -1,3 +1,4 @@ +import types import unittest from importlib import import_module @@ -219,5 +220,24 @@ class ResourceFromNamespaceZipTests( MODULE = 'namespacedata01' +class MainModuleTests(unittest.TestCase): + def test_main_module_with_none_spec(self): + """ + __main__ module with no spec should raise TypeError (for clarity). + + See python/cpython#138531 for details. + """ + # construct a __main__ module with no __spec__. + mainmodule = types.ModuleType("__main__") + + assert mainmodule.__spec__ is None + + with self.assertRaises( + TypeError, + msg="Cannot access resources for '__main__' as it does not appear to correspond to an importable module (its __spec__ is None).", + ): + resources.files(mainmodule) + + if __name__ == '__main__': unittest.main() diff --git a/newsfragments/331.feature.rst b/newsfragments/331.feature.rst new file mode 100644 index 0000000..04e9344 --- /dev/null +++ b/newsfragments/331.feature.rst @@ -0,0 +1 @@ +``files()`` now provides a nicer error when __main__.__spec__ is None.