1"""Test that the semantics relating to the 'fromlist' argument are correct."""
2from test.test_importlib import util
3import warnings
4import unittest
5
6
7class ReturnValue:
8
9    """The use of fromlist influences what import returns.
10
11    If direct ``import ...`` statement is used, the root module or package is
12    returned [import return]. But if fromlist is set, then the specified module
13    is actually returned (whether it is a relative import or not)
14    [from return].
15
16    """
17
18    def test_return_from_import(self):
19        # [import return]
20        with util.mock_spec('pkg.__init__', 'pkg.module') as importer:
21            with util.import_state(meta_path=[importer]):
22                module = self.__import__('pkg.module')
23                self.assertEqual(module.__name__, 'pkg')
24
25    def test_return_from_from_import(self):
26        # [from return]
27        with util.mock_spec('pkg.__init__', 'pkg.module')as importer:
28            with util.import_state(meta_path=[importer]):
29                module = self.__import__('pkg.module', fromlist=['attr'])
30                self.assertEqual(module.__name__, 'pkg.module')
31
32
33(Frozen_ReturnValue,
34 Source_ReturnValue
35 ) = util.test_both(ReturnValue, __import__=util.__import__)
36
37
38class HandlingFromlist:
39
40    """Using fromlist triggers different actions based on what is being asked
41    of it.
42
43    If fromlist specifies an object on a module, nothing special happens
44    [object case]. This is even true if the object does not exist [bad object].
45
46    If a package is being imported, then what is listed in fromlist may be
47    treated as a module to be imported [module]. And this extends to what is
48    contained in __all__ when '*' is imported [using *]. And '*' does not need
49    to be the only name in the fromlist [using * with others].
50
51    """
52
53    def test_object(self):
54        # [object case]
55        with util.mock_spec('module') as importer:
56            with util.import_state(meta_path=[importer]):
57                module = self.__import__('module', fromlist=['attr'])
58                self.assertEqual(module.__name__, 'module')
59
60    def test_nonexistent_object(self):
61        # [bad object]
62        with util.mock_spec('module') as importer:
63            with util.import_state(meta_path=[importer]):
64                module = self.__import__('module', fromlist=['non_existent'])
65                self.assertEqual(module.__name__, 'module')
66                self.assertFalse(hasattr(module, 'non_existent'))
67
68    def test_module_from_package(self):
69        # [module]
70        with util.mock_spec('pkg.__init__', 'pkg.module') as importer:
71            with util.import_state(meta_path=[importer]):
72                module = self.__import__('pkg', fromlist=['module'])
73                self.assertEqual(module.__name__, 'pkg')
74                self.assertTrue(hasattr(module, 'module'))
75                self.assertEqual(module.module.__name__, 'pkg.module')
76
77    def test_nonexistent_from_package(self):
78        with util.mock_spec('pkg.__init__') as importer:
79            with util.import_state(meta_path=[importer]):
80                module = self.__import__('pkg', fromlist=['non_existent'])
81                self.assertEqual(module.__name__, 'pkg')
82                self.assertFalse(hasattr(module, 'non_existent'))
83
84    def test_module_from_package_triggers_ModuleNotFoundError(self):
85        # If a submodule causes an ModuleNotFoundError because it tries
86        # to import a module which doesn't exist, that should let the
87        # ModuleNotFoundError propagate.
88        def module_code():
89            import i_do_not_exist
90        with util.mock_spec('pkg.__init__', 'pkg.mod',
91                               module_code={'pkg.mod': module_code}) as importer:
92            with util.import_state(meta_path=[importer]):
93                with self.assertRaises(ModuleNotFoundError) as exc:
94                    self.__import__('pkg', fromlist=['mod'])
95                self.assertEqual('i_do_not_exist', exc.exception.name)
96
97    def test_empty_string(self):
98        with util.mock_spec('pkg.__init__', 'pkg.mod') as importer:
99            with util.import_state(meta_path=[importer]):
100                module = self.__import__('pkg.mod', fromlist=[''])
101                self.assertEqual(module.__name__, 'pkg.mod')
102
103    def basic_star_test(self, fromlist=['*']):
104        # [using *]
105        with util.mock_spec('pkg.__init__', 'pkg.module') as mock:
106            with util.import_state(meta_path=[mock]):
107                mock['pkg'].__all__ = ['module']
108                module = self.__import__('pkg', fromlist=fromlist)
109                self.assertEqual(module.__name__, 'pkg')
110                self.assertTrue(hasattr(module, 'module'))
111                self.assertEqual(module.module.__name__, 'pkg.module')
112
113    def test_using_star(self):
114        # [using *]
115        self.basic_star_test()
116
117    def test_fromlist_as_tuple(self):
118        self.basic_star_test(('*',))
119
120    def test_star_with_others(self):
121        # [using * with others]
122        context = util.mock_spec('pkg.__init__', 'pkg.module1', 'pkg.module2')
123        with context as mock:
124            with util.import_state(meta_path=[mock]):
125                mock['pkg'].__all__ = ['module1']
126                module = self.__import__('pkg', fromlist=['module2', '*'])
127                self.assertEqual(module.__name__, 'pkg')
128                self.assertTrue(hasattr(module, 'module1'))
129                self.assertTrue(hasattr(module, 'module2'))
130                self.assertEqual(module.module1.__name__, 'pkg.module1')
131                self.assertEqual(module.module2.__name__, 'pkg.module2')
132
133    def test_nonexistent_in_all(self):
134        with util.mock_spec('pkg.__init__') as importer:
135            with util.import_state(meta_path=[importer]):
136                importer['pkg'].__all__ = ['non_existent']
137                module = self.__import__('pkg', fromlist=['*'])
138                self.assertEqual(module.__name__, 'pkg')
139                self.assertFalse(hasattr(module, 'non_existent'))
140
141    def test_star_in_all(self):
142        with util.mock_spec('pkg.__init__') as importer:
143            with util.import_state(meta_path=[importer]):
144                importer['pkg'].__all__ = ['*']
145                module = self.__import__('pkg', fromlist=['*'])
146                self.assertEqual(module.__name__, 'pkg')
147                self.assertFalse(hasattr(module, '*'))
148
149    def test_invalid_type(self):
150        with util.mock_spec('pkg.__init__') as importer:
151            with util.import_state(meta_path=[importer]), \
152                 warnings.catch_warnings():
153                warnings.simplefilter('error', BytesWarning)
154                with self.assertRaisesRegex(TypeError, r'\bfrom\b'):
155                    self.__import__('pkg', fromlist=[b'attr'])
156                with self.assertRaisesRegex(TypeError, r'\bfrom\b'):
157                    self.__import__('pkg', fromlist=iter([b'attr']))
158
159    def test_invalid_type_in_all(self):
160        with util.mock_spec('pkg.__init__') as importer:
161            with util.import_state(meta_path=[importer]), \
162                 warnings.catch_warnings():
163                warnings.simplefilter('error', BytesWarning)
164                importer['pkg'].__all__ = [b'attr']
165                with self.assertRaisesRegex(TypeError, r'\bpkg\.__all__\b'):
166                    self.__import__('pkg', fromlist=['*'])
167
168
169(Frozen_FromList,
170 Source_FromList
171 ) = util.test_both(HandlingFromlist, __import__=util.__import__)
172
173
174if __name__ == '__main__':
175    unittest.main()
176