1"""Test that sys.modules is used properly by import."""
2from test.test_importlib import util
3import sys
4from types import MethodType
5import unittest
6import warnings
7
8
9class UseCache:
10
11    """When it comes to sys.modules, import prefers it over anything else.
12
13    Once a name has been resolved, sys.modules is checked to see if it contains
14    the module desired. If so, then it is returned [use cache]. If it is not
15    found, then the proper steps are taken to perform the import, but
16    sys.modules is still used to return the imported module (e.g., not what a
17    loader returns) [from cache on return]. This also applies to imports of
18    things contained within a package and thus get assigned as an attribute
19    [from cache to attribute] or pulled in thanks to a fromlist import
20    [from cache for fromlist]. But if sys.modules contains None then
21    ImportError is raised [None in cache].
22
23    """
24
25    def test_using_cache(self):
26        # [use cache]
27        module_to_use = "some module found!"
28        with util.uncache('some_module'):
29            sys.modules['some_module'] = module_to_use
30            module = self.__import__('some_module')
31            self.assertEqual(id(module_to_use), id(module))
32
33    def test_None_in_cache(self):
34        #[None in cache]
35        name = 'using_None'
36        with util.uncache(name):
37            sys.modules[name] = None
38            with self.assertRaises(ImportError) as cm:
39                self.__import__(name)
40            self.assertEqual(cm.exception.name, name)
41
42
43(Frozen_UseCache,
44 Source_UseCache
45 ) = util.test_both(UseCache, __import__=util.__import__)
46
47
48class ImportlibUseCache(UseCache, unittest.TestCase):
49
50    # Pertinent only to PEP 302; exec_module() doesn't return a module.
51
52    __import__ = util.__import__['Source']
53
54    def create_mock(self, *names, return_=None):
55        mock = util.mock_modules(*names)
56        original_load = mock.load_module
57        def load_module(self, fullname):
58            original_load(fullname)
59            return return_
60        mock.load_module = MethodType(load_module, mock)
61        return mock
62
63    # __import__ inconsistent between loaders and built-in import when it comes
64    #   to when to use the module in sys.modules and when not to.
65    def test_using_cache_after_loader(self):
66        # [from cache on return]
67        with warnings.catch_warnings():
68            warnings.simplefilter("ignore", ImportWarning)
69            with self.create_mock('module') as mock:
70                with util.import_state(meta_path=[mock]):
71                    module = self.__import__('module')
72                    self.assertEqual(id(module), id(sys.modules['module']))
73
74    # See test_using_cache_after_loader() for reasoning.
75    def test_using_cache_for_assigning_to_attribute(self):
76        # [from cache to attribute]
77        with warnings.catch_warnings():
78            warnings.simplefilter("ignore", ImportWarning)
79            with self.create_mock('pkg.__init__', 'pkg.module') as importer:
80                with util.import_state(meta_path=[importer]):
81                    module = self.__import__('pkg.module')
82                    self.assertTrue(hasattr(module, 'module'))
83                    self.assertEqual(id(module.module),
84                                    id(sys.modules['pkg.module']))
85
86    # See test_using_cache_after_loader() for reasoning.
87    def test_using_cache_for_fromlist(self):
88        # [from cache for fromlist]
89        with warnings.catch_warnings():
90            warnings.simplefilter("ignore", ImportWarning)
91            with self.create_mock('pkg.__init__', 'pkg.module') as importer:
92                with util.import_state(meta_path=[importer]):
93                    module = self.__import__('pkg', fromlist=['module'])
94                    self.assertTrue(hasattr(module, 'module'))
95                    self.assertEqual(id(module.module),
96                                    id(sys.modules['pkg.module']))
97
98
99if __name__ == '__main__':
100    unittest.main()
101