diff --git a/Lib/importlib/resources/_adapters.py b/Lib/importlib/resources/_adapters.py index 50688fbb666658..222888b4b3b02a 100644 --- a/Lib/importlib/resources/_adapters.py +++ b/Lib/importlib/resources/_adapters.py @@ -160,9 +160,9 @@ def files(self): return CompatibilityFiles.SpecPath(self.spec, self._reader) -def wrap_spec(package): +def wrap_spec(spec): """ Construct a package spec with traversable compatibility on the spec/loader/reader. """ - return SpecLoaderAdapter(package.__spec__, TraversableResourcesLoader) + return SpecLoaderAdapter(spec, TraversableResourcesLoader) diff --git a/Lib/importlib/resources/_common.py b/Lib/importlib/resources/_common.py index 4e9014c45a056e..22fd32568be3e9 100644 --- a/Lib/importlib/resources/_common.py +++ b/Lib/importlib/resources/_common.py @@ -113,7 +113,13 @@ def from_package(package: types.ModuleType): # deferred for performance (python/cpython#109829) from ._adapters import wrap_spec - spec = wrap_spec(package) + if package.__spec__ is None: + raise TypeError( + f"Cannot access resources for '{package.__name__ or package!r}' " + "as it does not appear to correspond to an importable module (its __spec__ is None)." + ) + + spec = wrap_spec(package.__spec__) reader = spec.loader.get_resource_reader(spec.name) return reader.files() diff --git a/Lib/test/test_importlib/resources/test_resource.py b/Lib/test/test_importlib/resources/test_resource.py index fcede14b891a84..cdc1e38118a381 100644 --- a/Lib/test/test_importlib/resources/test_resource.py +++ b/Lib/test/test_importlib/resources/test_resource.py @@ -1,4 +1,5 @@ import unittest +import types from . import util from importlib import resources, import_module @@ -232,5 +233,17 @@ class ResourceFromNamespaceZipTests( MODULE = 'namespacedata01' +class ResourceFromMainModuleWithNoneSpecTests(unittest.TestCase): + # `__main__.__spec__` can be `None` depending on how it is populated. + # https://docs.python.org/3/reference/import.html#main-spec + def test_main_module_with_none_spec(self): + mainmodule = types.ModuleType("__main__") + + self.assertIsNone(mainmodule.__spec__) + + 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/Misc/NEWS.d/next/Library/2025-09-05-08-26-11.gh-issue-121190.nBBcWu.rst b/Misc/NEWS.d/next/Library/2025-09-05-08-26-11.gh-issue-121190.nBBcWu.rst new file mode 100644 index 00000000000000..c252d16b1d02ca --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-09-05-08-26-11.gh-issue-121190.nBBcWu.rst @@ -0,0 +1 @@ +``importlib.resources.files(package)`` raises an error with a clearer message when ``package.__spec__`` is ``None``