test that sys modules is used properly by import from test testimportlib import util import sys from types import methodtype import unittest import warnings class usecache def testusingcacheself use cache moduletouse some module found with util uncache somemodule sys modules somemodule moduletouse module self import somemodule self assertequalidmoduletouse idmodule def testnoneincacheself none in cache name usingnone with util uncachename sys modulesname none with self assertraisesimporterror as cm self importname self assertequalcm exception name name frozenusecache sourceusecache util testbothusecache importutil import class importlibusecacheusecache unittest testcase pertinent only to pep 302 execmodule doesn t return a module import util import source def createmockself names returnnone mock util mockspecnames originalspec mock findspec def findspecself fullname path targetnone return originalspecfullname mock findspec methodtypefindspec mock return mock import inconsistent between loaders and builtin import when it comes to when to use the module in sys modules and when not to def testusingcacheafterloaderself from cache on return with warnings catchwarnings warnings simplefilterignore importwarning with self createmock module as mock with util importstatemetapathmock module self import module self assertequalidmodule idsys modules module see testusingcacheafterloader for reasoning def testusingcacheforassigningtoattributeself from cache to attribute with warnings catchwarnings warnings simplefilterignore importwarning with self createmock pkg init pkg module as importer with util importstatemetapathimporter module self import pkg module self asserttruehasattrmodule module self assertequalidmodule module idsys modules pkg module see testusingcacheafterloader for reasoning def testusingcacheforfromlistself from cache for fromlist with self createmock pkg init pkg module as importer with util importstatemetapathimporter module self import pkg fromlist module self asserttruehasattrmodule module self assertequalidmodule module idsys modules pkg module if name main unittest main when it comes to sys modules import prefers it over anything else once a name has been resolved sys modules is checked to see if it contains the module desired if so then it is returned use cache if it is not found then the proper steps are taken to perform the import but sys modules is still used to return the imported module e g not what a loader returns from cache on return this also applies to imports of things contained within a package and thus get assigned as an attribute from cache to attribute or pulled in thanks to a fromlist import from cache for fromlist but if sys modules contains none then importerror is raised none in cache use cache none in cache pertinent only to pep 302 exec_module doesn t return a module __import__ inconsistent between loaders and built in import when it comes to when to use the module in sys modules and when not to from cache on return see test_using_cache_after_loader for reasoning from cache to attribute see test_using_cache_after_loader for reasoning from cache for fromlist
from test.test_importlib import util
import sys
from types import MethodType
import unittest
import warnings


class UseCache:

    

    def test_using_cache(self):
        
        module_to_use = "some module found!"
        with util.uncache('some_module'):
            sys.modules['some_module'] = module_to_use
            module = self.__import__('some_module')
            self.assertEqual(id(module_to_use), id(module))

    def test_None_in_cache(self):
        
        name = 'using_None'
        with util.uncache(name):
            sys.modules[name] = None
            with self.assertRaises(ImportError) as cm:
                self.__import__(name)
            self.assertEqual(cm.exception.name, name)


(Frozen_UseCache,
 Source_UseCache
 ) = util.test_both(UseCache, __import__=util.__import__)


class ImportlibUseCache(UseCache, unittest.TestCase):

    

    __import__ = util.__import__['Source']

    def create_mock(self, *names, return_=None):
        mock = util.mock_spec(*names)
        original_spec = mock.find_spec
        def find_spec(self, fullname, path, target=None):
            return original_spec(fullname)
        mock.find_spec = MethodType(find_spec, mock)
        return mock

    
    
    def test_using_cache_after_loader(self):
        
        with warnings.catch_warnings():
            warnings.simplefilter("ignore", ImportWarning)
            with self.create_mock('module') as mock:
                with util.import_state(meta_path=[mock]):
                    module = self.__import__('module')
                    self.assertEqual(id(module), id(sys.modules['module']))

    
    def test_using_cache_for_assigning_to_attribute(self):
        
        with warnings.catch_warnings():
            warnings.simplefilter("ignore", ImportWarning)
            with self.create_mock('pkg.__init__', 'pkg.module') as importer:
                with util.import_state(meta_path=[importer]):
                    module = self.__import__('pkg.module')
                    self.assertTrue(hasattr(module, 'module'))
                    self.assertEqual(id(module.module),
                                    id(sys.modules['pkg.module']))

    
    def test_using_cache_for_fromlist(self):
        
        with self.create_mock('pkg.__init__', 'pkg.module') as importer:
            with util.import_state(meta_path=[importer]):
                module = self.__import__('pkg', fromlist=['module'])
                self.assertTrue(hasattr(module, 'module'))
                self.assertEqual(id(module.module),
                                 id(sys.modules['pkg.module']))


if __name__ == '__main__':
    unittest.main()