| from . import util as test_util |
| |
| init = test_util.import_importlib('importlib') |
| util = test_util.import_importlib('importlib.util') |
| machinery = test_util.import_importlib('importlib.machinery') |
| |
| import os.path |
| import sys |
| from test import support |
| import types |
| import unittest |
| import warnings |
| |
| |
| class ImportModuleTests: |
| |
| """Test importlib.import_module.""" |
| |
| def test_module_import(self): |
| # Test importing a top-level module. |
| with test_util.mock_modules('top_level') as mock: |
| with test_util.import_state(meta_path=[mock]): |
| module = self.init.import_module('top_level') |
| self.assertEqual(module.__name__, 'top_level') |
| |
| def test_absolute_package_import(self): |
| # Test importing a module from a package with an absolute name. |
| pkg_name = 'pkg' |
| pkg_long_name = '{0}.__init__'.format(pkg_name) |
| name = '{0}.mod'.format(pkg_name) |
| with test_util.mock_modules(pkg_long_name, name) as mock: |
| with test_util.import_state(meta_path=[mock]): |
| module = self.init.import_module(name) |
| self.assertEqual(module.__name__, name) |
| |
| def test_shallow_relative_package_import(self): |
| # Test importing a module from a package through a relative import. |
| pkg_name = 'pkg' |
| pkg_long_name = '{0}.__init__'.format(pkg_name) |
| module_name = 'mod' |
| absolute_name = '{0}.{1}'.format(pkg_name, module_name) |
| relative_name = '.{0}'.format(module_name) |
| with test_util.mock_modules(pkg_long_name, absolute_name) as mock: |
| with test_util.import_state(meta_path=[mock]): |
| self.init.import_module(pkg_name) |
| module = self.init.import_module(relative_name, pkg_name) |
| self.assertEqual(module.__name__, absolute_name) |
| |
| def test_deep_relative_package_import(self): |
| modules = ['a.__init__', 'a.b.__init__', 'a.c'] |
| with test_util.mock_modules(*modules) as mock: |
| with test_util.import_state(meta_path=[mock]): |
| self.init.import_module('a') |
| self.init.import_module('a.b') |
| module = self.init.import_module('..c', 'a.b') |
| self.assertEqual(module.__name__, 'a.c') |
| |
| def test_absolute_import_with_package(self): |
| # Test importing a module from a package with an absolute name with |
| # the 'package' argument given. |
| pkg_name = 'pkg' |
| pkg_long_name = '{0}.__init__'.format(pkg_name) |
| name = '{0}.mod'.format(pkg_name) |
| with test_util.mock_modules(pkg_long_name, name) as mock: |
| with test_util.import_state(meta_path=[mock]): |
| self.init.import_module(pkg_name) |
| module = self.init.import_module(name, pkg_name) |
| self.assertEqual(module.__name__, name) |
| |
| def test_relative_import_wo_package(self): |
| # Relative imports cannot happen without the 'package' argument being |
| # set. |
| with self.assertRaises(TypeError): |
| self.init.import_module('.support') |
| |
| |
| def test_loaded_once(self): |
| # Issue #13591: Modules should only be loaded once when |
| # initializing the parent package attempts to import the |
| # module currently being imported. |
| b_load_count = 0 |
| def load_a(): |
| self.init.import_module('a.b') |
| def load_b(): |
| nonlocal b_load_count |
| b_load_count += 1 |
| code = {'a': load_a, 'a.b': load_b} |
| modules = ['a.__init__', 'a.b'] |
| with test_util.mock_modules(*modules, module_code=code) as mock: |
| with test_util.import_state(meta_path=[mock]): |
| self.init.import_module('a.b') |
| self.assertEqual(b_load_count, 1) |
| |
| |
| (Frozen_ImportModuleTests, |
| Source_ImportModuleTests |
| ) = test_util.test_both(ImportModuleTests, init=init) |
| |
| |
| class FindLoaderTests: |
| |
| FakeMetaFinder = None |
| |
| def test_sys_modules(self): |
| # If a module with __loader__ is in sys.modules, then return it. |
| name = 'some_mod' |
| with test_util.uncache(name): |
| module = types.ModuleType(name) |
| loader = 'a loader!' |
| module.__loader__ = loader |
| sys.modules[name] = module |
| with warnings.catch_warnings(): |
| warnings.simplefilter('ignore', DeprecationWarning) |
| found = self.init.find_loader(name) |
| self.assertEqual(loader, found) |
| |
| def test_sys_modules_loader_is_None(self): |
| # If sys.modules[name].__loader__ is None, raise ValueError. |
| name = 'some_mod' |
| with test_util.uncache(name): |
| module = types.ModuleType(name) |
| module.__loader__ = None |
| sys.modules[name] = module |
| with self.assertRaises(ValueError): |
| with warnings.catch_warnings(): |
| warnings.simplefilter('ignore', DeprecationWarning) |
| self.init.find_loader(name) |
| |
| def test_sys_modules_loader_is_not_set(self): |
| # Should raise ValueError |
| # Issue #17099 |
| name = 'some_mod' |
| with test_util.uncache(name): |
| module = types.ModuleType(name) |
| try: |
| del module.__loader__ |
| except AttributeError: |
| pass |
| sys.modules[name] = module |
| with self.assertRaises(ValueError): |
| with warnings.catch_warnings(): |
| warnings.simplefilter('ignore', DeprecationWarning) |
| self.init.find_loader(name) |
| |
| def test_success(self): |
| # Return the loader found on sys.meta_path. |
| name = 'some_mod' |
| with test_util.uncache(name): |
| with test_util.import_state(meta_path=[self.FakeMetaFinder]): |
| with warnings.catch_warnings(): |
| warnings.simplefilter('ignore', DeprecationWarning) |
| self.assertEqual((name, None), self.init.find_loader(name)) |
| |
| def test_success_path(self): |
| # Searching on a path should work. |
| name = 'some_mod' |
| path = 'path to some place' |
| with test_util.uncache(name): |
| with test_util.import_state(meta_path=[self.FakeMetaFinder]): |
| with warnings.catch_warnings(): |
| warnings.simplefilter('ignore', DeprecationWarning) |
| self.assertEqual((name, path), |
| self.init.find_loader(name, path)) |
| |
| def test_nothing(self): |
| # None is returned upon failure to find a loader. |
| with warnings.catch_warnings(): |
| warnings.simplefilter('ignore', DeprecationWarning) |
| self.assertIsNone(self.init.find_loader('nevergoingtofindthismodule')) |
| |
| |
| class FindLoaderPEP451Tests(FindLoaderTests): |
| |
| class FakeMetaFinder: |
| @staticmethod |
| def find_spec(name, path=None, target=None): |
| return machinery['Source'].ModuleSpec(name, (name, path)) |
| |
| |
| (Frozen_FindLoaderPEP451Tests, |
| Source_FindLoaderPEP451Tests |
| ) = test_util.test_both(FindLoaderPEP451Tests, init=init) |
| |
| |
| class FindLoaderPEP302Tests(FindLoaderTests): |
| |
| class FakeMetaFinder: |
| @staticmethod |
| def find_module(name, path=None): |
| return name, path |
| |
| |
| (Frozen_FindLoaderPEP302Tests, |
| Source_FindLoaderPEP302Tests |
| ) = test_util.test_both(FindLoaderPEP302Tests, init=init) |
| |
| |
| class ReloadTests: |
| |
| def test_reload_modules(self): |
| for mod in ('tokenize', 'time', 'marshal'): |
| with self.subTest(module=mod): |
| with support.CleanImport(mod): |
| module = self.init.import_module(mod) |
| self.init.reload(module) |
| |
| def test_module_replaced(self): |
| def code(): |
| import sys |
| module = type(sys)('top_level') |
| module.spam = 3 |
| sys.modules['top_level'] = module |
| mock = test_util.mock_modules('top_level', |
| module_code={'top_level': code}) |
| with mock: |
| with test_util.import_state(meta_path=[mock]): |
| module = self.init.import_module('top_level') |
| reloaded = self.init.reload(module) |
| actual = sys.modules['top_level'] |
| self.assertEqual(actual.spam, 3) |
| self.assertEqual(reloaded.spam, 3) |
| |
| def test_reload_missing_loader(self): |
| with support.CleanImport('types'): |
| import types |
| loader = types.__loader__ |
| del types.__loader__ |
| reloaded = self.init.reload(types) |
| |
| self.assertIs(reloaded, types) |
| self.assertIs(sys.modules['types'], types) |
| self.assertEqual(reloaded.__loader__.path, loader.path) |
| |
| def test_reload_loader_replaced(self): |
| with support.CleanImport('types'): |
| import types |
| types.__loader__ = None |
| self.init.invalidate_caches() |
| reloaded = self.init.reload(types) |
| |
| self.assertIsNot(reloaded.__loader__, None) |
| self.assertIs(reloaded, types) |
| self.assertIs(sys.modules['types'], types) |
| |
| def test_reload_location_changed(self): |
| name = 'spam' |
| with support.temp_cwd(None) as cwd: |
| with test_util.uncache('spam'): |
| with support.DirsOnSysPath(cwd): |
| # Start as a plain module. |
| self.init.invalidate_caches() |
| path = os.path.join(cwd, name + '.py') |
| cached = self.util.cache_from_source(path) |
| expected = {'__name__': name, |
| '__package__': '', |
| '__file__': path, |
| '__cached__': cached, |
| '__doc__': None, |
| } |
| support.create_empty_file(path) |
| module = self.init.import_module(name) |
| ns = vars(module).copy() |
| loader = ns.pop('__loader__') |
| spec = ns.pop('__spec__') |
| ns.pop('__builtins__', None) # An implementation detail. |
| self.assertEqual(spec.name, name) |
| self.assertEqual(spec.loader, loader) |
| self.assertEqual(loader.path, path) |
| self.assertEqual(ns, expected) |
| |
| # Change to a package. |
| self.init.invalidate_caches() |
| init_path = os.path.join(cwd, name, '__init__.py') |
| cached = self.util.cache_from_source(init_path) |
| expected = {'__name__': name, |
| '__package__': name, |
| '__file__': init_path, |
| '__cached__': cached, |
| '__path__': [os.path.dirname(init_path)], |
| '__doc__': None, |
| } |
| os.mkdir(name) |
| os.rename(path, init_path) |
| reloaded = self.init.reload(module) |
| ns = vars(reloaded).copy() |
| loader = ns.pop('__loader__') |
| spec = ns.pop('__spec__') |
| ns.pop('__builtins__', None) # An implementation detail. |
| self.assertEqual(spec.name, name) |
| self.assertEqual(spec.loader, loader) |
| self.assertIs(reloaded, module) |
| self.assertEqual(loader.path, init_path) |
| self.maxDiff = None |
| self.assertEqual(ns, expected) |
| |
| def test_reload_namespace_changed(self): |
| name = 'spam' |
| with support.temp_cwd(None) as cwd: |
| with test_util.uncache('spam'): |
| with support.DirsOnSysPath(cwd): |
| # Start as a namespace package. |
| self.init.invalidate_caches() |
| bad_path = os.path.join(cwd, name, '__init.py') |
| cached = self.util.cache_from_source(bad_path) |
| expected = {'__name__': name, |
| '__package__': name, |
| '__doc__': None, |
| '__file__': None, |
| } |
| os.mkdir(name) |
| with open(bad_path, 'w') as init_file: |
| init_file.write('eggs = None') |
| module = self.init.import_module(name) |
| ns = vars(module).copy() |
| loader = ns.pop('__loader__') |
| path = ns.pop('__path__') |
| spec = ns.pop('__spec__') |
| ns.pop('__builtins__', None) # An implementation detail. |
| self.assertEqual(spec.name, name) |
| self.assertIsNotNone(spec.loader) |
| self.assertIsNotNone(loader) |
| self.assertEqual(spec.loader, loader) |
| self.assertEqual(set(path), |
| set([os.path.dirname(bad_path)])) |
| with self.assertRaises(AttributeError): |
| # a NamespaceLoader |
| loader.path |
| self.assertEqual(ns, expected) |
| |
| # Change to a regular package. |
| self.init.invalidate_caches() |
| init_path = os.path.join(cwd, name, '__init__.py') |
| cached = self.util.cache_from_source(init_path) |
| expected = {'__name__': name, |
| '__package__': name, |
| '__file__': init_path, |
| '__cached__': cached, |
| '__path__': [os.path.dirname(init_path)], |
| '__doc__': None, |
| 'eggs': None, |
| } |
| os.rename(bad_path, init_path) |
| reloaded = self.init.reload(module) |
| ns = vars(reloaded).copy() |
| loader = ns.pop('__loader__') |
| spec = ns.pop('__spec__') |
| ns.pop('__builtins__', None) # An implementation detail. |
| self.assertEqual(spec.name, name) |
| self.assertEqual(spec.loader, loader) |
| self.assertIs(reloaded, module) |
| self.assertEqual(loader.path, init_path) |
| self.assertEqual(ns, expected) |
| |
| def test_reload_submodule(self): |
| # See #19851. |
| name = 'spam' |
| subname = 'ham' |
| with test_util.temp_module(name, pkg=True) as pkg_dir: |
| fullname, _ = test_util.submodule(name, subname, pkg_dir) |
| ham = self.init.import_module(fullname) |
| reloaded = self.init.reload(ham) |
| self.assertIs(reloaded, ham) |
| |
| def test_module_missing_spec(self): |
| #Test that reload() throws ModuleNotFounderror when reloading |
| # a module whose missing a spec. (bpo-29851) |
| name = 'spam' |
| with test_util.uncache(name): |
| module = sys.modules[name] = types.ModuleType(name) |
| # Sanity check by attempting an import. |
| module = self.init.import_module(name) |
| self.assertIsNone(module.__spec__) |
| with self.assertRaises(ModuleNotFoundError): |
| self.init.reload(module) |
| |
| |
| (Frozen_ReloadTests, |
| Source_ReloadTests |
| ) = test_util.test_both(ReloadTests, init=init, util=util) |
| |
| |
| class InvalidateCacheTests: |
| |
| def test_method_called(self): |
| # If defined the method should be called. |
| class InvalidatingNullFinder: |
| def __init__(self, *ignored): |
| self.called = False |
| def find_module(self, *args): |
| return None |
| def invalidate_caches(self): |
| self.called = True |
| |
| key = 'gobledeegook' |
| meta_ins = InvalidatingNullFinder() |
| path_ins = InvalidatingNullFinder() |
| sys.meta_path.insert(0, meta_ins) |
| self.addCleanup(lambda: sys.path_importer_cache.__delitem__(key)) |
| sys.path_importer_cache[key] = path_ins |
| self.addCleanup(lambda: sys.meta_path.remove(meta_ins)) |
| self.init.invalidate_caches() |
| self.assertTrue(meta_ins.called) |
| self.assertTrue(path_ins.called) |
| |
| def test_method_lacking(self): |
| # There should be no issues if the method is not defined. |
| key = 'gobbledeegook' |
| sys.path_importer_cache[key] = None |
| self.addCleanup(lambda: sys.path_importer_cache.pop(key, None)) |
| self.init.invalidate_caches() # Shouldn't trigger an exception. |
| |
| |
| (Frozen_InvalidateCacheTests, |
| Source_InvalidateCacheTests |
| ) = test_util.test_both(InvalidateCacheTests, init=init) |
| |
| |
| class FrozenImportlibTests(unittest.TestCase): |
| |
| def test_no_frozen_importlib(self): |
| # Should be able to import w/o _frozen_importlib being defined. |
| # Can't do an isinstance() check since separate copies of importlib |
| # may have been used for import, so just check the name is not for the |
| # frozen loader. |
| source_init = init['Source'] |
| self.assertNotEqual(source_init.__loader__.__class__.__name__, |
| 'FrozenImporter') |
| |
| |
| class StartupTests: |
| |
| def test_everyone_has___loader__(self): |
| # Issue #17098: all modules should have __loader__ defined. |
| for name, module in sys.modules.items(): |
| if isinstance(module, types.ModuleType): |
| with self.subTest(name=name): |
| self.assertTrue(hasattr(module, '__loader__'), |
| '{!r} lacks a __loader__ attribute'.format(name)) |
| if self.machinery.BuiltinImporter.find_module(name): |
| self.assertIsNot(module.__loader__, None) |
| elif self.machinery.FrozenImporter.find_module(name): |
| self.assertIsNot(module.__loader__, None) |
| |
| def test_everyone_has___spec__(self): |
| for name, module in sys.modules.items(): |
| if isinstance(module, types.ModuleType): |
| with self.subTest(name=name): |
| self.assertTrue(hasattr(module, '__spec__')) |
| if self.machinery.BuiltinImporter.find_module(name): |
| self.assertIsNot(module.__spec__, None) |
| elif self.machinery.FrozenImporter.find_module(name): |
| self.assertIsNot(module.__spec__, None) |
| |
| |
| (Frozen_StartupTests, |
| Source_StartupTests |
| ) = test_util.test_both(StartupTests, machinery=machinery) |
| |
| |
| if __name__ == '__main__': |
| unittest.main() |