mirror of
https://github.com/python/cpython.git
synced 2025-07-23 19:25:40 +00:00

attributes to None. The long-term goal is for people to be able to rely on these attributes existing and checking for None to see if they have been set. Since import itself sets these attributes when a loader does not the only instances when the attributes are None are from someone overloading __import__() and not using a loader or someone creating a module from scratch. This patch also unifies module initialization. Before you could have different attributes with default values depending on how the module object was created. Now the only way to not get the same default set of attributes is to circumvent initialization by calling ModuleType.__new__() directly.
192 lines
6.4 KiB
Python
192 lines
6.4 KiB
Python
# Test the module type
|
|
import unittest
|
|
from test.support import run_unittest, gc_collect
|
|
|
|
import sys
|
|
ModuleType = type(sys)
|
|
|
|
class FullLoader:
|
|
@classmethod
|
|
def module_repr(cls, m):
|
|
return "<module '{}' (crafted)>".format(m.__name__)
|
|
|
|
class BareLoader:
|
|
pass
|
|
|
|
|
|
class ModuleTests(unittest.TestCase):
|
|
def test_uninitialized(self):
|
|
# An uninitialized module has no __dict__ or __name__,
|
|
# and __doc__ is None
|
|
foo = ModuleType.__new__(ModuleType)
|
|
self.assertTrue(foo.__dict__ is None)
|
|
self.assertRaises(SystemError, dir, foo)
|
|
try:
|
|
s = foo.__name__
|
|
self.fail("__name__ = %s" % repr(s))
|
|
except AttributeError:
|
|
pass
|
|
self.assertEqual(foo.__doc__, ModuleType.__doc__)
|
|
|
|
def test_no_docstring(self):
|
|
# Regularly initialized module, no docstring
|
|
foo = ModuleType("foo")
|
|
self.assertEqual(foo.__name__, "foo")
|
|
self.assertEqual(foo.__doc__, None)
|
|
self.assertIs(foo.__loader__, None)
|
|
self.assertIs(foo.__package__, None)
|
|
self.assertEqual(foo.__dict__, {"__name__": "foo", "__doc__": None,
|
|
"__loader__": None, "__package__": None})
|
|
|
|
def test_ascii_docstring(self):
|
|
# ASCII docstring
|
|
foo = ModuleType("foo", "foodoc")
|
|
self.assertEqual(foo.__name__, "foo")
|
|
self.assertEqual(foo.__doc__, "foodoc")
|
|
self.assertEqual(foo.__dict__,
|
|
{"__name__": "foo", "__doc__": "foodoc",
|
|
"__loader__": None, "__package__": None})
|
|
|
|
def test_unicode_docstring(self):
|
|
# Unicode docstring
|
|
foo = ModuleType("foo", "foodoc\u1234")
|
|
self.assertEqual(foo.__name__, "foo")
|
|
self.assertEqual(foo.__doc__, "foodoc\u1234")
|
|
self.assertEqual(foo.__dict__,
|
|
{"__name__": "foo", "__doc__": "foodoc\u1234",
|
|
"__loader__": None, "__package__": None})
|
|
|
|
def test_reinit(self):
|
|
# Reinitialization should not replace the __dict__
|
|
foo = ModuleType("foo", "foodoc\u1234")
|
|
foo.bar = 42
|
|
d = foo.__dict__
|
|
foo.__init__("foo", "foodoc")
|
|
self.assertEqual(foo.__name__, "foo")
|
|
self.assertEqual(foo.__doc__, "foodoc")
|
|
self.assertEqual(foo.bar, 42)
|
|
self.assertEqual(foo.__dict__,
|
|
{"__name__": "foo", "__doc__": "foodoc", "bar": 42,
|
|
"__loader__": None, "__package__": None})
|
|
self.assertTrue(foo.__dict__ is d)
|
|
|
|
@unittest.expectedFailure
|
|
def test_dont_clear_dict(self):
|
|
# See issue 7140.
|
|
def f():
|
|
foo = ModuleType("foo")
|
|
foo.bar = 4
|
|
return foo
|
|
gc_collect()
|
|
self.assertEqual(f().__dict__["bar"], 4)
|
|
|
|
def test_clear_dict_in_ref_cycle(self):
|
|
destroyed = []
|
|
m = ModuleType("foo")
|
|
m.destroyed = destroyed
|
|
s = """class A:
|
|
def __init__(self, l):
|
|
self.l = l
|
|
def __del__(self):
|
|
self.l.append(1)
|
|
a = A(destroyed)"""
|
|
exec(s, m.__dict__)
|
|
del m
|
|
gc_collect()
|
|
self.assertEqual(destroyed, [1])
|
|
|
|
def test_module_repr_minimal(self):
|
|
# reprs when modules have no __file__, __name__, or __loader__
|
|
m = ModuleType('foo')
|
|
del m.__name__
|
|
self.assertEqual(repr(m), "<module '?'>")
|
|
|
|
def test_module_repr_with_name(self):
|
|
m = ModuleType('foo')
|
|
self.assertEqual(repr(m), "<module 'foo'>")
|
|
|
|
def test_module_repr_with_name_and_filename(self):
|
|
m = ModuleType('foo')
|
|
m.__file__ = '/tmp/foo.py'
|
|
self.assertEqual(repr(m), "<module 'foo' from '/tmp/foo.py'>")
|
|
|
|
def test_module_repr_with_filename_only(self):
|
|
m = ModuleType('foo')
|
|
del m.__name__
|
|
m.__file__ = '/tmp/foo.py'
|
|
self.assertEqual(repr(m), "<module '?' from '/tmp/foo.py'>")
|
|
|
|
def test_module_repr_with_loader_as_None(self):
|
|
m = ModuleType('foo')
|
|
assert m.__loader__ is None
|
|
self.assertEqual(repr(m), "<module 'foo'>")
|
|
|
|
def test_module_repr_with_bare_loader_but_no_name(self):
|
|
m = ModuleType('foo')
|
|
del m.__name__
|
|
# Yes, a class not an instance.
|
|
m.__loader__ = BareLoader
|
|
loader_repr = repr(BareLoader)
|
|
self.assertEqual(
|
|
repr(m), "<module '?' ({})>".format(loader_repr))
|
|
|
|
def test_module_repr_with_full_loader_but_no_name(self):
|
|
# m.__loader__.module_repr() will fail because the module has no
|
|
# m.__name__. This exception will get suppressed and instead the
|
|
# loader's repr will be used.
|
|
m = ModuleType('foo')
|
|
del m.__name__
|
|
# Yes, a class not an instance.
|
|
m.__loader__ = FullLoader
|
|
loader_repr = repr(FullLoader)
|
|
self.assertEqual(
|
|
repr(m), "<module '?' ({})>".format(loader_repr))
|
|
|
|
def test_module_repr_with_bare_loader(self):
|
|
m = ModuleType('foo')
|
|
# Yes, a class not an instance.
|
|
m.__loader__ = BareLoader
|
|
module_repr = repr(BareLoader)
|
|
self.assertEqual(
|
|
repr(m), "<module 'foo' ({})>".format(module_repr))
|
|
|
|
def test_module_repr_with_full_loader(self):
|
|
m = ModuleType('foo')
|
|
# Yes, a class not an instance.
|
|
m.__loader__ = FullLoader
|
|
self.assertEqual(
|
|
repr(m), "<module 'foo' (crafted)>")
|
|
|
|
def test_module_repr_with_bare_loader_and_filename(self):
|
|
# Because the loader has no module_repr(), use the file name.
|
|
m = ModuleType('foo')
|
|
# Yes, a class not an instance.
|
|
m.__loader__ = BareLoader
|
|
m.__file__ = '/tmp/foo.py'
|
|
self.assertEqual(repr(m), "<module 'foo' from '/tmp/foo.py'>")
|
|
|
|
def test_module_repr_with_full_loader_and_filename(self):
|
|
# Even though the module has an __file__, use __loader__.module_repr()
|
|
m = ModuleType('foo')
|
|
# Yes, a class not an instance.
|
|
m.__loader__ = FullLoader
|
|
m.__file__ = '/tmp/foo.py'
|
|
self.assertEqual(repr(m), "<module 'foo' (crafted)>")
|
|
|
|
def test_module_repr_builtin(self):
|
|
self.assertEqual(repr(sys), "<module 'sys' (built-in)>")
|
|
|
|
def test_module_repr_source(self):
|
|
r = repr(unittest)
|
|
self.assertEqual(r[:25], "<module 'unittest' from '")
|
|
self.assertEqual(r[-13:], "__init__.py'>")
|
|
|
|
# frozen and namespace module reprs are tested in importlib.
|
|
|
|
|
|
def test_main():
|
|
run_unittest(ModuleTests)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
test_main()
|