1from .. import util
2
3from importlib import machinery
4import sys
5import types
6import unittest
7
8PKG_NAME = 'fine'
9SUBMOD_NAME = 'fine.bogus'
10
11
12class BadSpecFinderLoader:
13    @classmethod
14    def find_spec(cls, fullname, path=None, target=None):
15        if fullname == SUBMOD_NAME:
16            spec = machinery.ModuleSpec(fullname, cls)
17            return spec
18
19    @staticmethod
20    def create_module(spec):
21        return None
22
23    @staticmethod
24    def exec_module(module):
25        if module.__name__ == SUBMOD_NAME:
26            raise ImportError('I cannot be loaded!')
27
28
29class BadLoaderFinder:
30    @classmethod
31    def find_module(cls, fullname, path):
32        if fullname == SUBMOD_NAME:
33            return cls
34
35    @classmethod
36    def load_module(cls, fullname):
37        if fullname == SUBMOD_NAME:
38            raise ImportError('I cannot be loaded!')
39
40
41class APITest:
42
43    """Test API-specific details for __import__ (e.g. raising the right
44    exception when passing in an int for the module name)."""
45
46    def test_raises_ModuleNotFoundError(self):
47        with self.assertRaises(ModuleNotFoundError):
48            util.import_importlib('some module that does not exist')
49
50    def test_name_requires_rparition(self):
51        # Raise TypeError if a non-string is passed in for the module name.
52        with self.assertRaises(TypeError):
53            self.__import__(42)
54
55    def test_negative_level(self):
56        # Raise ValueError when a negative level is specified.
57        # PEP 328 did away with sys.module None entries and the ambiguity of
58        # absolute/relative imports.
59        with self.assertRaises(ValueError):
60            self.__import__('os', globals(), level=-1)
61
62    def test_nonexistent_fromlist_entry(self):
63        # If something in fromlist doesn't exist, that's okay.
64        # issue15715
65        mod = types.ModuleType(PKG_NAME)
66        mod.__path__ = ['XXX']
67        with util.import_state(meta_path=[self.bad_finder_loader]):
68            with util.uncache(PKG_NAME):
69                sys.modules[PKG_NAME] = mod
70                self.__import__(PKG_NAME, fromlist=['not here'])
71
72    def test_fromlist_load_error_propagates(self):
73        # If something in fromlist triggers an exception not related to not
74        # existing, let that exception propagate.
75        # issue15316
76        mod = types.ModuleType(PKG_NAME)
77        mod.__path__ = ['XXX']
78        with util.import_state(meta_path=[self.bad_finder_loader]):
79            with util.uncache(PKG_NAME):
80                sys.modules[PKG_NAME] = mod
81                with self.assertRaises(ImportError):
82                    self.__import__(PKG_NAME,
83                                    fromlist=[SUBMOD_NAME.rpartition('.')[-1]])
84
85    def test_blocked_fromlist(self):
86        # If fromlist entry is None, let a ModuleNotFoundError propagate.
87        # issue31642
88        mod = types.ModuleType(PKG_NAME)
89        mod.__path__ = []
90        with util.import_state(meta_path=[self.bad_finder_loader]):
91            with util.uncache(PKG_NAME, SUBMOD_NAME):
92                sys.modules[PKG_NAME] = mod
93                sys.modules[SUBMOD_NAME] = None
94                with self.assertRaises(ModuleNotFoundError) as cm:
95                    self.__import__(PKG_NAME,
96                                    fromlist=[SUBMOD_NAME.rpartition('.')[-1]])
97                self.assertEqual(cm.exception.name, SUBMOD_NAME)
98
99
100class OldAPITests(APITest):
101    bad_finder_loader = BadLoaderFinder
102
103
104(Frozen_OldAPITests,
105 Source_OldAPITests
106 ) = util.test_both(OldAPITests, __import__=util.__import__)
107
108
109class SpecAPITests(APITest):
110    bad_finder_loader = BadSpecFinderLoader
111
112
113(Frozen_SpecAPITests,
114 Source_SpecAPITests
115 ) = util.test_both(SpecAPITests, __import__=util.__import__)
116
117
118if __name__ == '__main__':
119    unittest.main()
120