1 """Test that sys.modules is used properly by import.""" 2 from .. import util 3 import sys 4 from types import MethodType 5 import unittest 6 7 8 class 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 47 class 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 92 if __name__ == '__main__': 93 unittest.main() 94