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