1 # Test the module type 2 import unittest 3 import weakref 4 from test.support import gc_collect, requires_type_collecting 5 from test.support.script_helper import assert_python_ok 6 7 import sys 8 ModuleType = type(sys) 9 10 class FullLoader: 11 @classmethod 12 def module_repr(cls, m): 13 return "<module '{}' (crafted)>".format(m.__name__) 14 15 class BareLoader: 16 pass 17 18 19 class ModuleTests(unittest.TestCase): 20 def test_uninitialized(self): 21 # An uninitialized module has no __dict__ or __name__, 22 # and __doc__ is None 23 foo = ModuleType.__new__(ModuleType) 24 self.assertTrue(foo.__dict__ is None) 25 self.assertRaises(SystemError, dir, foo) 26 try: 27 s = foo.__name__ 28 self.fail("__name__ = %s" % repr(s)) 29 except AttributeError: 30 pass 31 self.assertEqual(foo.__doc__, ModuleType.__doc__) 32 33 def test_uninitialized_missing_getattr(self): 34 # Issue 8297 35 # test the text in the AttributeError of an uninitialized module 36 foo = ModuleType.__new__(ModuleType) 37 self.assertRaisesRegex( 38 AttributeError, "module has no attribute 'not_here'", 39 getattr, foo, "not_here") 40 41 def test_missing_getattr(self): 42 # Issue 8297 43 # test the text in the AttributeError 44 foo = ModuleType("foo") 45 self.assertRaisesRegex( 46 AttributeError, "module 'foo' has no attribute 'not_here'", 47 getattr, foo, "not_here") 48 49 def test_no_docstring(self): 50 # Regularly initialized module, no docstring 51 foo = ModuleType("foo") 52 self.assertEqual(foo.__name__, "foo") 53 self.assertEqual(foo.__doc__, None) 54 self.assertIs(foo.__loader__, None) 55 self.assertIs(foo.__package__, None) 56 self.assertIs(foo.__spec__, None) 57 self.assertEqual(foo.__dict__, {"__name__": "foo", "__doc__": None, 58 "__loader__": None, "__package__": None, 59 "__spec__": None}) 60 61 def test_ascii_docstring(self): 62 # ASCII docstring 63 foo = ModuleType("foo", "foodoc") 64 self.assertEqual(foo.__name__, "foo") 65 self.assertEqual(foo.__doc__, "foodoc") 66 self.assertEqual(foo.__dict__, 67 {"__name__": "foo", "__doc__": "foodoc", 68 "__loader__": None, "__package__": None, 69 "__spec__": None}) 70 71 def test_unicode_docstring(self): 72 # Unicode docstring 73 foo = ModuleType("foo", "foodoc\u1234") 74 self.assertEqual(foo.__name__, "foo") 75 self.assertEqual(foo.__doc__, "foodoc\u1234") 76 self.assertEqual(foo.__dict__, 77 {"__name__": "foo", "__doc__": "foodoc\u1234", 78 "__loader__": None, "__package__": None, 79 "__spec__": None}) 80 81 def test_reinit(self): 82 # Reinitialization should not replace the __dict__ 83 foo = ModuleType("foo", "foodoc\u1234") 84 foo.bar = 42 85 d = foo.__dict__ 86 foo.__init__("foo", "foodoc") 87 self.assertEqual(foo.__name__, "foo") 88 self.assertEqual(foo.__doc__, "foodoc") 89 self.assertEqual(foo.bar, 42) 90 self.assertEqual(foo.__dict__, 91 {"__name__": "foo", "__doc__": "foodoc", "bar": 42, 92 "__loader__": None, "__package__": None, "__spec__": None}) 93 self.assertTrue(foo.__dict__ is d) 94 95 def test_dont_clear_dict(self): 96 # See issue 7140. 97 def f(): 98 foo = ModuleType("foo") 99 foo.bar = 4 100 return foo 101 gc_collect() 102 self.assertEqual(f().__dict__["bar"], 4) 103 104 @requires_type_collecting 105 def test_clear_dict_in_ref_cycle(self): 106 destroyed = [] 107 m = ModuleType("foo") 108 m.destroyed = destroyed 109 s = """class A: 110 def __init__(self, l): 111 self.l = l 112 def __del__(self): 113 self.l.append(1) 114 a = A(destroyed)""" 115 exec(s, m.__dict__) 116 del m 117 gc_collect() 118 self.assertEqual(destroyed, [1]) 119 120 def test_weakref(self): 121 m = ModuleType("foo") 122 wr = weakref.ref(m) 123 self.assertIs(wr(), m) 124 del m 125 gc_collect() 126 self.assertIs(wr(), None) 127 128 def test_module_repr_minimal(self): 129 # reprs when modules have no __file__, __name__, or __loader__ 130 m = ModuleType('foo') 131 del m.__name__ 132 self.assertEqual(repr(m), "<module '?'>") 133 134 def test_module_repr_with_name(self): 135 m = ModuleType('foo') 136 self.assertEqual(repr(m), "<module 'foo'>") 137 138 def test_module_repr_with_name_and_filename(self): 139 m = ModuleType('foo') 140 m.__file__ = '/tmp/foo.py' 141 self.assertEqual(repr(m), "<module 'foo' from '/tmp/foo.py'>") 142 143 def test_module_repr_with_filename_only(self): 144 m = ModuleType('foo') 145 del m.__name__ 146 m.__file__ = '/tmp/foo.py' 147 self.assertEqual(repr(m), "<module '?' from '/tmp/foo.py'>") 148 149 def test_module_repr_with_loader_as_None(self): 150 m = ModuleType('foo') 151 assert m.__loader__ is None 152 self.assertEqual(repr(m), "<module 'foo'>") 153 154 def test_module_repr_with_bare_loader_but_no_name(self): 155 m = ModuleType('foo') 156 del m.__name__ 157 # Yes, a class not an instance. 158 m.__loader__ = BareLoader 159 loader_repr = repr(BareLoader) 160 self.assertEqual( 161 repr(m), "<module '?' ({})>".format(loader_repr)) 162 163 def test_module_repr_with_full_loader_but_no_name(self): 164 # m.__loader__.module_repr() will fail because the module has no 165 # m.__name__. This exception will get suppressed and instead the 166 # loader's repr will be used. 167 m = ModuleType('foo') 168 del m.__name__ 169 # Yes, a class not an instance. 170 m.__loader__ = FullLoader 171 loader_repr = repr(FullLoader) 172 self.assertEqual( 173 repr(m), "<module '?' ({})>".format(loader_repr)) 174 175 def test_module_repr_with_bare_loader(self): 176 m = ModuleType('foo') 177 # Yes, a class not an instance. 178 m.__loader__ = BareLoader 179 module_repr = repr(BareLoader) 180 self.assertEqual( 181 repr(m), "<module 'foo' ({})>".format(module_repr)) 182 183 def test_module_repr_with_full_loader(self): 184 m = ModuleType('foo') 185 # Yes, a class not an instance. 186 m.__loader__ = FullLoader 187 self.assertEqual( 188 repr(m), "<module 'foo' (crafted)>") 189 190 def test_module_repr_with_bare_loader_and_filename(self): 191 # Because the loader has no module_repr(), use the file name. 192 m = ModuleType('foo') 193 # Yes, a class not an instance. 194 m.__loader__ = BareLoader 195 m.__file__ = '/tmp/foo.py' 196 self.assertEqual(repr(m), "<module 'foo' from '/tmp/foo.py'>") 197 198 def test_module_repr_with_full_loader_and_filename(self): 199 # Even though the module has an __file__, use __loader__.module_repr() 200 m = ModuleType('foo') 201 # Yes, a class not an instance. 202 m.__loader__ = FullLoader 203 m.__file__ = '/tmp/foo.py' 204 self.assertEqual(repr(m), "<module 'foo' (crafted)>") 205 206 def test_module_repr_builtin(self): 207 self.assertEqual(repr(sys), "<module 'sys' (built-in)>") 208 209 def test_module_repr_source(self): 210 r = repr(unittest) 211 starts_with = "<module 'unittest' from '" 212 ends_with = "__init__.py'>" 213 self.assertEqual(r[:len(starts_with)], starts_with, 214 '{!r} does not start with {!r}'.format(r, starts_with)) 215 self.assertEqual(r[-len(ends_with):], ends_with, 216 '{!r} does not end with {!r}'.format(r, ends_with)) 217 218 @requires_type_collecting 219 def test_module_finalization_at_shutdown(self): 220 # Module globals and builtins should still be available during shutdown 221 rc, out, err = assert_python_ok("-c", "from test import final_a") 222 self.assertFalse(err) 223 lines = out.splitlines() 224 self.assertEqual(set(lines), { 225 b"x = a", 226 b"x = b", 227 b"final_a.x = a", 228 b"final_b.x = b", 229 b"len = len", 230 b"shutil.rmtree = rmtree"}) 231 232 def test_descriptor_errors_propagate(self): 233 class Descr: 234 def __get__(self, o, t): 235 raise RuntimeError 236 class M(ModuleType): 237 melon = Descr() 238 self.assertRaises(RuntimeError, getattr, M("mymod"), "melon") 239 240 # frozen and namespace module reprs are tested in importlib. 241 242 243 if __name__ == '__main__': 244 unittest.main() 245