test_module.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  1. # Test the module type
  2. import unittest
  3. import weakref
  4. from test.support import gc_collect
  5. from test.support import import_helper
  6. from test.support.script_helper import assert_python_ok
  7. import sys
  8. ModuleType = type(sys)
  9. class FullLoader:
  10. @classmethod
  11. def module_repr(cls, m):
  12. return "<module '{}' (crafted)>".format(m.__name__)
  13. class BareLoader:
  14. pass
  15. class ModuleTests(unittest.TestCase):
  16. def test_uninitialized(self):
  17. # An uninitialized module has no __dict__ or __name__,
  18. # and __doc__ is None
  19. foo = ModuleType.__new__(ModuleType)
  20. self.assertTrue(isinstance(foo.__dict__, dict))
  21. self.assertEqual(dir(foo), [])
  22. try:
  23. s = foo.__name__
  24. self.fail("__name__ = %s" % repr(s))
  25. except AttributeError:
  26. pass
  27. self.assertEqual(foo.__doc__, ModuleType.__doc__)
  28. def test_uninitialized_missing_getattr(self):
  29. # Issue 8297
  30. # test the text in the AttributeError of an uninitialized module
  31. foo = ModuleType.__new__(ModuleType)
  32. self.assertRaisesRegex(
  33. AttributeError, "module has no attribute 'not_here'",
  34. getattr, foo, "not_here")
  35. def test_missing_getattr(self):
  36. # Issue 8297
  37. # test the text in the AttributeError
  38. foo = ModuleType("foo")
  39. self.assertRaisesRegex(
  40. AttributeError, "module 'foo' has no attribute 'not_here'",
  41. getattr, foo, "not_here")
  42. def test_no_docstring(self):
  43. # Regularly initialized module, no docstring
  44. foo = ModuleType("foo")
  45. self.assertEqual(foo.__name__, "foo")
  46. self.assertEqual(foo.__doc__, None)
  47. self.assertIs(foo.__loader__, None)
  48. self.assertIs(foo.__package__, None)
  49. self.assertIs(foo.__spec__, None)
  50. self.assertEqual(foo.__dict__, {"__name__": "foo", "__doc__": None,
  51. "__loader__": None, "__package__": None,
  52. "__spec__": None})
  53. def test_ascii_docstring(self):
  54. # ASCII docstring
  55. foo = ModuleType("foo", "foodoc")
  56. self.assertEqual(foo.__name__, "foo")
  57. self.assertEqual(foo.__doc__, "foodoc")
  58. self.assertEqual(foo.__dict__,
  59. {"__name__": "foo", "__doc__": "foodoc",
  60. "__loader__": None, "__package__": None,
  61. "__spec__": None})
  62. def test_unicode_docstring(self):
  63. # Unicode docstring
  64. foo = ModuleType("foo", "foodoc\u1234")
  65. self.assertEqual(foo.__name__, "foo")
  66. self.assertEqual(foo.__doc__, "foodoc\u1234")
  67. self.assertEqual(foo.__dict__,
  68. {"__name__": "foo", "__doc__": "foodoc\u1234",
  69. "__loader__": None, "__package__": None,
  70. "__spec__": None})
  71. def test_reinit(self):
  72. # Reinitialization should not replace the __dict__
  73. foo = ModuleType("foo", "foodoc\u1234")
  74. foo.bar = 42
  75. d = foo.__dict__
  76. foo.__init__("foo", "foodoc")
  77. self.assertEqual(foo.__name__, "foo")
  78. self.assertEqual(foo.__doc__, "foodoc")
  79. self.assertEqual(foo.bar, 42)
  80. self.assertEqual(foo.__dict__,
  81. {"__name__": "foo", "__doc__": "foodoc", "bar": 42,
  82. "__loader__": None, "__package__": None, "__spec__": None})
  83. self.assertTrue(foo.__dict__ is d)
  84. def test_dont_clear_dict(self):
  85. # See issue 7140.
  86. def f():
  87. foo = ModuleType("foo")
  88. foo.bar = 4
  89. return foo
  90. gc_collect()
  91. self.assertEqual(f().__dict__["bar"], 4)
  92. def test_clear_dict_in_ref_cycle(self):
  93. destroyed = []
  94. m = ModuleType("foo")
  95. m.destroyed = destroyed
  96. s = """class A:
  97. def __init__(self, l):
  98. self.l = l
  99. def __del__(self):
  100. self.l.append(1)
  101. a = A(destroyed)"""
  102. exec(s, m.__dict__)
  103. del m
  104. gc_collect()
  105. self.assertEqual(destroyed, [1])
  106. def test_weakref(self):
  107. m = ModuleType("foo")
  108. wr = weakref.ref(m)
  109. self.assertIs(wr(), m)
  110. del m
  111. gc_collect()
  112. self.assertIs(wr(), None)
  113. def test_module_getattr(self):
  114. import test.good_getattr as gga
  115. from test.good_getattr import test
  116. self.assertEqual(test, "There is test")
  117. self.assertEqual(gga.x, 1)
  118. self.assertEqual(gga.y, 2)
  119. with self.assertRaisesRegex(AttributeError,
  120. "Deprecated, use whatever instead"):
  121. gga.yolo
  122. self.assertEqual(gga.whatever, "There is whatever")
  123. del sys.modules['test.good_getattr']
  124. def test_module_getattr_errors(self):
  125. import test.bad_getattr as bga
  126. from test import bad_getattr2
  127. self.assertEqual(bga.x, 1)
  128. self.assertEqual(bad_getattr2.x, 1)
  129. with self.assertRaises(TypeError):
  130. bga.nope
  131. with self.assertRaises(TypeError):
  132. bad_getattr2.nope
  133. del sys.modules['test.bad_getattr']
  134. if 'test.bad_getattr2' in sys.modules:
  135. del sys.modules['test.bad_getattr2']
  136. def test_module_dir(self):
  137. import test.good_getattr as gga
  138. self.assertEqual(dir(gga), ['a', 'b', 'c'])
  139. del sys.modules['test.good_getattr']
  140. def test_module_dir_errors(self):
  141. import test.bad_getattr as bga
  142. from test import bad_getattr2
  143. with self.assertRaises(TypeError):
  144. dir(bga)
  145. with self.assertRaises(TypeError):
  146. dir(bad_getattr2)
  147. del sys.modules['test.bad_getattr']
  148. if 'test.bad_getattr2' in sys.modules:
  149. del sys.modules['test.bad_getattr2']
  150. def test_module_getattr_tricky(self):
  151. from test import bad_getattr3
  152. # these lookups should not crash
  153. with self.assertRaises(AttributeError):
  154. bad_getattr3.one
  155. with self.assertRaises(AttributeError):
  156. bad_getattr3.delgetattr
  157. if 'test.bad_getattr3' in sys.modules:
  158. del sys.modules['test.bad_getattr3']
  159. def test_module_repr_minimal(self):
  160. # reprs when modules have no __file__, __name__, or __loader__
  161. m = ModuleType('foo')
  162. del m.__name__
  163. self.assertEqual(repr(m), "<module '?'>")
  164. def test_module_repr_with_name(self):
  165. m = ModuleType('foo')
  166. self.assertEqual(repr(m), "<module 'foo'>")
  167. def test_module_repr_with_name_and_filename(self):
  168. m = ModuleType('foo')
  169. m.__file__ = '/tmp/foo.py'
  170. self.assertEqual(repr(m), "<module 'foo' from '/tmp/foo.py'>")
  171. def test_module_repr_with_filename_only(self):
  172. m = ModuleType('foo')
  173. del m.__name__
  174. m.__file__ = '/tmp/foo.py'
  175. self.assertEqual(repr(m), "<module '?' from '/tmp/foo.py'>")
  176. def test_module_repr_with_loader_as_None(self):
  177. m = ModuleType('foo')
  178. assert m.__loader__ is None
  179. self.assertEqual(repr(m), "<module 'foo'>")
  180. def test_module_repr_with_bare_loader_but_no_name(self):
  181. m = ModuleType('foo')
  182. del m.__name__
  183. # Yes, a class not an instance.
  184. m.__loader__ = BareLoader
  185. loader_repr = repr(BareLoader)
  186. self.assertEqual(
  187. repr(m), "<module '?' ({})>".format(loader_repr))
  188. def test_module_repr_with_full_loader_but_no_name(self):
  189. # m.__loader__.module_repr() will fail because the module has no
  190. # m.__name__. This exception will get suppressed and instead the
  191. # loader's repr will be used.
  192. m = ModuleType('foo')
  193. del m.__name__
  194. # Yes, a class not an instance.
  195. m.__loader__ = FullLoader
  196. loader_repr = repr(FullLoader)
  197. self.assertEqual(
  198. repr(m), "<module '?' ({})>".format(loader_repr))
  199. def test_module_repr_with_bare_loader(self):
  200. m = ModuleType('foo')
  201. # Yes, a class not an instance.
  202. m.__loader__ = BareLoader
  203. module_repr = repr(BareLoader)
  204. self.assertEqual(
  205. repr(m), "<module 'foo' ({})>".format(module_repr))
  206. def test_module_repr_with_full_loader(self):
  207. m = ModuleType('foo')
  208. # Yes, a class not an instance.
  209. m.__loader__ = FullLoader
  210. self.assertEqual(
  211. repr(m), "<module 'foo' (crafted)>")
  212. def test_module_repr_with_bare_loader_and_filename(self):
  213. # Because the loader has no module_repr(), use the file name.
  214. m = ModuleType('foo')
  215. # Yes, a class not an instance.
  216. m.__loader__ = BareLoader
  217. m.__file__ = '/tmp/foo.py'
  218. self.assertEqual(repr(m), "<module 'foo' from '/tmp/foo.py'>")
  219. def test_module_repr_with_full_loader_and_filename(self):
  220. # Even though the module has an __file__, use __loader__.module_repr()
  221. m = ModuleType('foo')
  222. # Yes, a class not an instance.
  223. m.__loader__ = FullLoader
  224. m.__file__ = '/tmp/foo.py'
  225. self.assertEqual(repr(m), "<module 'foo' (crafted)>")
  226. def test_module_repr_builtin(self):
  227. self.assertEqual(repr(sys), "<module 'sys' (built-in)>")
  228. def test_module_repr_source(self):
  229. r = repr(unittest)
  230. starts_with = "<module 'unittest' from '"
  231. ends_with = "__init__.py'>"
  232. self.assertEqual(r[:len(starts_with)], starts_with,
  233. '{!r} does not start with {!r}'.format(r, starts_with))
  234. self.assertEqual(r[-len(ends_with):], ends_with,
  235. '{!r} does not end with {!r}'.format(r, ends_with))
  236. def test_module_finalization_at_shutdown(self):
  237. # Module globals and builtins should still be available during shutdown
  238. rc, out, err = assert_python_ok("-c", "from test import final_a")
  239. self.assertFalse(err)
  240. lines = out.splitlines()
  241. self.assertEqual(set(lines), {
  242. b"x = a",
  243. b"x = b",
  244. b"final_a.x = a",
  245. b"final_b.x = b",
  246. b"len = len",
  247. b"shutil.rmtree = rmtree"})
  248. def test_descriptor_errors_propagate(self):
  249. class Descr:
  250. def __get__(self, o, t):
  251. raise RuntimeError
  252. class M(ModuleType):
  253. melon = Descr()
  254. self.assertRaises(RuntimeError, getattr, M("mymod"), "melon")
  255. def test_lazy_create_annotations(self):
  256. # module objects lazy create their __annotations__ dict on demand.
  257. # the annotations dict is stored in module.__dict__.
  258. # a freshly created module shouldn't have an annotations dict yet.
  259. foo = ModuleType("foo")
  260. for i in range(4):
  261. self.assertFalse("__annotations__" in foo.__dict__)
  262. d = foo.__annotations__
  263. self.assertTrue("__annotations__" in foo.__dict__)
  264. self.assertEqual(foo.__annotations__, d)
  265. self.assertEqual(foo.__dict__['__annotations__'], d)
  266. if i % 2:
  267. del foo.__annotations__
  268. else:
  269. del foo.__dict__['__annotations__']
  270. def test_setting_annotations(self):
  271. foo = ModuleType("foo")
  272. for i in range(4):
  273. self.assertFalse("__annotations__" in foo.__dict__)
  274. d = {'a': int}
  275. foo.__annotations__ = d
  276. self.assertTrue("__annotations__" in foo.__dict__)
  277. self.assertEqual(foo.__annotations__, d)
  278. self.assertEqual(foo.__dict__['__annotations__'], d)
  279. if i % 2:
  280. del foo.__annotations__
  281. else:
  282. del foo.__dict__['__annotations__']
  283. def test_annotations_getset_raises(self):
  284. # double delete
  285. foo = ModuleType("foo")
  286. foo.__annotations__ = {}
  287. del foo.__annotations__
  288. with self.assertRaises(AttributeError):
  289. del foo.__annotations__
  290. def test_annotations_are_created_correctly(self):
  291. ann_module4 = import_helper.import_fresh_module('test.ann_module4')
  292. self.assertTrue("__annotations__" in ann_module4.__dict__)
  293. del ann_module4.__annotations__
  294. self.assertFalse("__annotations__" in ann_module4.__dict__)
  295. def test_repeated_attribute_pops(self):
  296. # Repeated accesses to module attribute will be specialized
  297. # Check that popping the attribute doesn't break it
  298. m = ModuleType("test")
  299. d = m.__dict__
  300. count = 0
  301. for _ in range(100):
  302. m.attr = 1
  303. count += m.attr # Might be specialized
  304. d.pop("attr")
  305. self.assertEqual(count, 100)
  306. # frozen and namespace module reprs are tested in importlib.
  307. def test_subclass_with_slots(self):
  308. # In 3.11alpha this crashed, as the slots weren't NULLed.
  309. class ModuleWithSlots(ModuleType):
  310. __slots__ = ("a", "b")
  311. def __init__(self, name):
  312. super().__init__(name)
  313. m = ModuleWithSlots("name")
  314. with self.assertRaises(AttributeError):
  315. m.a
  316. with self.assertRaises(AttributeError):
  317. m.b
  318. m.a, m.b = 1, 2
  319. self.assertEqual(m.a, 1)
  320. self.assertEqual(m.b, 2)
  321. if __name__ == '__main__':
  322. unittest.main()