From 47b3f09366f5abc8ef3d8c51a9573ac48d866d00 Mon Sep 17 00:00:00 2001 From: "Yuichiro Tachibana (Tsuchiya)" Date: Wed, 22 Oct 2025 23:06:18 +0900 Subject: [PATCH] A better error message from importlib.resources.files() when module spec is None from https://github.com/python/cpython/pull/138531 --- importlib_resources/_adapters.py | 4 ++-- importlib_resources/_common.py | 8 +++++++- importlib_resources/tests/test_resource.py | 13 +++++++++++++ 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/importlib_resources/_adapters.py b/importlib_resources/_adapters.py index 50688fbb..222888b4 100644 --- a/importlib_resources/_adapters.py +++ b/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/importlib_resources/_common.py b/importlib_resources/_common.py index 5f41c265..de6d84f5 100644 --- a/importlib_resources/_common.py +++ b/importlib_resources/_common.py @@ -113,7 +113,13 @@ def from_package(package: types.ModuleType): # deferred for performance (python/cpython#109829) from .future.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/importlib_resources/tests/test_resource.py b/importlib_resources/tests/test_resource.py index c80afdc7..c02f0b0b 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 @@ -234,5 +235,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()