• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Test the module type
2import unittest
3import weakref
4from test.support import gc_collect
5from test.support.script_helper import assert_python_ok
6
7import sys
8ModuleType = type(sys)
9
10class FullLoader:
11    @classmethod
12    def module_repr(cls, m):
13        return "<module '{}' (crafted)>".format(m.__name__)
14
15class BareLoader:
16    pass
17
18
19class 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    def test_clear_dict_in_ref_cycle(self):
105        destroyed = []
106        m = ModuleType("foo")
107        m.destroyed = destroyed
108        s = """class A:
109    def __init__(self, l):
110        self.l = l
111    def __del__(self):
112        self.l.append(1)
113a = A(destroyed)"""
114        exec(s, m.__dict__)
115        del m
116        gc_collect()
117        self.assertEqual(destroyed, [1])
118
119    def test_weakref(self):
120        m = ModuleType("foo")
121        wr = weakref.ref(m)
122        self.assertIs(wr(), m)
123        del m
124        gc_collect()
125        self.assertIs(wr(), None)
126
127    def test_module_getattr(self):
128        import test.good_getattr as gga
129        from test.good_getattr import test
130        self.assertEqual(test, "There is test")
131        self.assertEqual(gga.x, 1)
132        self.assertEqual(gga.y, 2)
133        with self.assertRaisesRegex(AttributeError,
134                                    "Deprecated, use whatever instead"):
135            gga.yolo
136        self.assertEqual(gga.whatever, "There is whatever")
137        del sys.modules['test.good_getattr']
138
139    def test_module_getattr_errors(self):
140        import test.bad_getattr as bga
141        from test import bad_getattr2
142        self.assertEqual(bga.x, 1)
143        self.assertEqual(bad_getattr2.x, 1)
144        with self.assertRaises(TypeError):
145            bga.nope
146        with self.assertRaises(TypeError):
147            bad_getattr2.nope
148        del sys.modules['test.bad_getattr']
149        if 'test.bad_getattr2' in sys.modules:
150            del sys.modules['test.bad_getattr2']
151
152    def test_module_dir(self):
153        import test.good_getattr as gga
154        self.assertEqual(dir(gga), ['a', 'b', 'c'])
155        del sys.modules['test.good_getattr']
156
157    def test_module_dir_errors(self):
158        import test.bad_getattr as bga
159        from test import bad_getattr2
160        with self.assertRaises(TypeError):
161            dir(bga)
162        with self.assertRaises(TypeError):
163            dir(bad_getattr2)
164        del sys.modules['test.bad_getattr']
165        if 'test.bad_getattr2' in sys.modules:
166            del sys.modules['test.bad_getattr2']
167
168    def test_module_getattr_tricky(self):
169        from test import bad_getattr3
170        # these lookups should not crash
171        with self.assertRaises(AttributeError):
172            bad_getattr3.one
173        with self.assertRaises(AttributeError):
174            bad_getattr3.delgetattr
175        if 'test.bad_getattr3' in sys.modules:
176            del sys.modules['test.bad_getattr3']
177
178    def test_module_repr_minimal(self):
179        # reprs when modules have no __file__, __name__, or __loader__
180        m = ModuleType('foo')
181        del m.__name__
182        self.assertEqual(repr(m), "<module '?'>")
183
184    def test_module_repr_with_name(self):
185        m = ModuleType('foo')
186        self.assertEqual(repr(m), "<module 'foo'>")
187
188    def test_module_repr_with_name_and_filename(self):
189        m = ModuleType('foo')
190        m.__file__ = '/tmp/foo.py'
191        self.assertEqual(repr(m), "<module 'foo' from '/tmp/foo.py'>")
192
193    def test_module_repr_with_filename_only(self):
194        m = ModuleType('foo')
195        del m.__name__
196        m.__file__ = '/tmp/foo.py'
197        self.assertEqual(repr(m), "<module '?' from '/tmp/foo.py'>")
198
199    def test_module_repr_with_loader_as_None(self):
200        m = ModuleType('foo')
201        assert m.__loader__ is None
202        self.assertEqual(repr(m), "<module 'foo'>")
203
204    def test_module_repr_with_bare_loader_but_no_name(self):
205        m = ModuleType('foo')
206        del m.__name__
207        # Yes, a class not an instance.
208        m.__loader__ = BareLoader
209        loader_repr = repr(BareLoader)
210        self.assertEqual(
211            repr(m), "<module '?' ({})>".format(loader_repr))
212
213    def test_module_repr_with_full_loader_but_no_name(self):
214        # m.__loader__.module_repr() will fail because the module has no
215        # m.__name__.  This exception will get suppressed and instead the
216        # loader's repr will be used.
217        m = ModuleType('foo')
218        del m.__name__
219        # Yes, a class not an instance.
220        m.__loader__ = FullLoader
221        loader_repr = repr(FullLoader)
222        self.assertEqual(
223            repr(m), "<module '?' ({})>".format(loader_repr))
224
225    def test_module_repr_with_bare_loader(self):
226        m = ModuleType('foo')
227        # Yes, a class not an instance.
228        m.__loader__ = BareLoader
229        module_repr = repr(BareLoader)
230        self.assertEqual(
231            repr(m), "<module 'foo' ({})>".format(module_repr))
232
233    def test_module_repr_with_full_loader(self):
234        m = ModuleType('foo')
235        # Yes, a class not an instance.
236        m.__loader__ = FullLoader
237        self.assertEqual(
238            repr(m), "<module 'foo' (crafted)>")
239
240    def test_module_repr_with_bare_loader_and_filename(self):
241        # Because the loader has no module_repr(), use the file name.
242        m = ModuleType('foo')
243        # Yes, a class not an instance.
244        m.__loader__ = BareLoader
245        m.__file__ = '/tmp/foo.py'
246        self.assertEqual(repr(m), "<module 'foo' from '/tmp/foo.py'>")
247
248    def test_module_repr_with_full_loader_and_filename(self):
249        # Even though the module has an __file__, use __loader__.module_repr()
250        m = ModuleType('foo')
251        # Yes, a class not an instance.
252        m.__loader__ = FullLoader
253        m.__file__ = '/tmp/foo.py'
254        self.assertEqual(repr(m), "<module 'foo' (crafted)>")
255
256    def test_module_repr_builtin(self):
257        self.assertEqual(repr(sys), "<module 'sys' (built-in)>")
258
259    def test_module_repr_source(self):
260        r = repr(unittest)
261        starts_with = "<module 'unittest' from '"
262        ends_with = "__init__.py'>"
263        self.assertEqual(r[:len(starts_with)], starts_with,
264                         '{!r} does not start with {!r}'.format(r, starts_with))
265        self.assertEqual(r[-len(ends_with):], ends_with,
266                         '{!r} does not end with {!r}'.format(r, ends_with))
267
268    def test_module_finalization_at_shutdown(self):
269        # Module globals and builtins should still be available during shutdown
270        rc, out, err = assert_python_ok("-c", "from test import final_a")
271        self.assertFalse(err)
272        lines = out.splitlines()
273        self.assertEqual(set(lines), {
274            b"x = a",
275            b"x = b",
276            b"final_a.x = a",
277            b"final_b.x = b",
278            b"len = len",
279            b"shutil.rmtree = rmtree"})
280
281    def test_descriptor_errors_propagate(self):
282        class Descr:
283            def __get__(self, o, t):
284                raise RuntimeError
285        class M(ModuleType):
286            melon = Descr()
287        self.assertRaises(RuntimeError, getattr, M("mymod"), "melon")
288
289    # frozen and namespace module reprs are tested in importlib.
290
291
292if __name__ == '__main__':
293    unittest.main()
294