"""Return the repr to use for the module."""
name = '?' if spec.name is None else spec.name
if spec.origin is None:
- if spec.loader is None:
+ loader = spec.loader
+ if loader is None:
return f'<module {name!r}>'
+ elif (
+ _bootstrap_external is not None
+ and isinstance(loader, _bootstrap_external.NamespaceLoader)
+ ):
+ return f'<module {name!r} (namespace) from {list(loader._path)}>'
else:
- return f'<module {name!r} (namespace) from {list(spec.loader._path)}>'
+ return f'<module {name!r} ({loader!r})>'
else:
if spec.has_location:
return f'<module {name!r} from {spec.origin!r}>'
with util.uncache('blah'), util.import_state(meta_path=[loader]):
module = self.__import__('blah')
self.assertEqual(loader, module.__loader__)
+ expected_repr_pattern = (
+ r"<module 'blah' \(<test\.test_importlib\..*SpecLoaderMock object at .+>\)>"
+ )
+ self.assertRegex(repr(module), expected_repr_pattern)
(Frozen_SpecTests,
def test_simple_repr(self):
import foo.one
- assert repr(foo).startswith("<module 'foo' (namespace) from [")
+ self.assertTrue(repr(foo).startswith("<module 'foo' (namespace) from ["))
class DynamicPathNamespacePackage(NamespacePackageTest):
--- /dev/null
+Fix regression in Python 3.12 where calling :func:`repr` on a module that
+had been imported using a custom :term:`loader` could fail with
+:exc:`AttributeError`. Patch by Alex Waygood.