1from . import util as test_util 2 3init = test_util.import_importlib('importlib') 4util = test_util.import_importlib('importlib.util') 5machinery = test_util.import_importlib('importlib.machinery') 6 7import os.path 8import sys 9from test import support 10from test.support import import_helper 11from test.support import os_helper 12import types 13import unittest 14import warnings 15 16 17class ImportModuleTests: 18 19 """Test importlib.import_module.""" 20 21 def test_module_import(self): 22 # Test importing a top-level module. 23 with test_util.mock_spec('top_level') as mock: 24 with test_util.import_state(meta_path=[mock]): 25 module = self.init.import_module('top_level') 26 self.assertEqual(module.__name__, 'top_level') 27 28 def test_absolute_package_import(self): 29 # Test importing a module from a package with an absolute name. 30 pkg_name = 'pkg' 31 pkg_long_name = '{0}.__init__'.format(pkg_name) 32 name = '{0}.mod'.format(pkg_name) 33 with test_util.mock_spec(pkg_long_name, name) as mock: 34 with test_util.import_state(meta_path=[mock]): 35 module = self.init.import_module(name) 36 self.assertEqual(module.__name__, name) 37 38 def test_shallow_relative_package_import(self): 39 # Test importing a module from a package through a relative import. 40 pkg_name = 'pkg' 41 pkg_long_name = '{0}.__init__'.format(pkg_name) 42 module_name = 'mod' 43 absolute_name = '{0}.{1}'.format(pkg_name, module_name) 44 relative_name = '.{0}'.format(module_name) 45 with test_util.mock_spec(pkg_long_name, absolute_name) as mock: 46 with test_util.import_state(meta_path=[mock]): 47 self.init.import_module(pkg_name) 48 module = self.init.import_module(relative_name, pkg_name) 49 self.assertEqual(module.__name__, absolute_name) 50 51 def test_deep_relative_package_import(self): 52 modules = ['a.__init__', 'a.b.__init__', 'a.c'] 53 with test_util.mock_spec(*modules) as mock: 54 with test_util.import_state(meta_path=[mock]): 55 self.init.import_module('a') 56 self.init.import_module('a.b') 57 module = self.init.import_module('..c', 'a.b') 58 self.assertEqual(module.__name__, 'a.c') 59 60 def test_absolute_import_with_package(self): 61 # Test importing a module from a package with an absolute name with 62 # the 'package' argument given. 63 pkg_name = 'pkg' 64 pkg_long_name = '{0}.__init__'.format(pkg_name) 65 name = '{0}.mod'.format(pkg_name) 66 with test_util.mock_spec(pkg_long_name, name) as mock: 67 with test_util.import_state(meta_path=[mock]): 68 self.init.import_module(pkg_name) 69 module = self.init.import_module(name, pkg_name) 70 self.assertEqual(module.__name__, name) 71 72 def test_relative_import_wo_package(self): 73 # Relative imports cannot happen without the 'package' argument being 74 # set. 75 with self.assertRaises(TypeError): 76 self.init.import_module('.support') 77 78 79 def test_loaded_once(self): 80 # Issue #13591: Modules should only be loaded once when 81 # initializing the parent package attempts to import the 82 # module currently being imported. 83 b_load_count = 0 84 def load_a(): 85 self.init.import_module('a.b') 86 def load_b(): 87 nonlocal b_load_count 88 b_load_count += 1 89 code = {'a': load_a, 'a.b': load_b} 90 modules = ['a.__init__', 'a.b'] 91 with test_util.mock_spec(*modules, module_code=code) as mock: 92 with test_util.import_state(meta_path=[mock]): 93 self.init.import_module('a.b') 94 self.assertEqual(b_load_count, 1) 95 96 97(Frozen_ImportModuleTests, 98 Source_ImportModuleTests 99 ) = test_util.test_both(ImportModuleTests, init=init) 100 101 102class FindLoaderTests: 103 104 FakeMetaFinder = None 105 106 def test_sys_modules(self): 107 # If a module with __loader__ is in sys.modules, then return it. 108 name = 'some_mod' 109 with test_util.uncache(name): 110 module = types.ModuleType(name) 111 loader = 'a loader!' 112 module.__loader__ = loader 113 sys.modules[name] = module 114 with warnings.catch_warnings(): 115 warnings.simplefilter('ignore', DeprecationWarning) 116 found = self.init.find_loader(name) 117 self.assertEqual(loader, found) 118 119 def test_sys_modules_loader_is_None(self): 120 # If sys.modules[name].__loader__ is None, raise ValueError. 121 name = 'some_mod' 122 with test_util.uncache(name): 123 module = types.ModuleType(name) 124 module.__loader__ = None 125 sys.modules[name] = module 126 with self.assertRaises(ValueError): 127 with warnings.catch_warnings(): 128 warnings.simplefilter('ignore', DeprecationWarning) 129 self.init.find_loader(name) 130 131 def test_sys_modules_loader_is_not_set(self): 132 # Should raise ValueError 133 # Issue #17099 134 name = 'some_mod' 135 with test_util.uncache(name): 136 module = types.ModuleType(name) 137 try: 138 del module.__loader__ 139 except AttributeError: 140 pass 141 sys.modules[name] = module 142 with self.assertRaises(ValueError): 143 with warnings.catch_warnings(): 144 warnings.simplefilter('ignore', DeprecationWarning) 145 self.init.find_loader(name) 146 147 def test_success(self): 148 # Return the loader found on sys.meta_path. 149 name = 'some_mod' 150 with test_util.uncache(name): 151 with test_util.import_state(meta_path=[self.FakeMetaFinder]): 152 with warnings.catch_warnings(): 153 warnings.simplefilter('ignore', DeprecationWarning) 154 warnings.simplefilter('ignore', ImportWarning) 155 self.assertEqual((name, None), self.init.find_loader(name)) 156 157 def test_success_path(self): 158 # Searching on a path should work. 159 name = 'some_mod' 160 path = 'path to some place' 161 with test_util.uncache(name): 162 with test_util.import_state(meta_path=[self.FakeMetaFinder]): 163 with warnings.catch_warnings(): 164 warnings.simplefilter('ignore', DeprecationWarning) 165 warnings.simplefilter('ignore', ImportWarning) 166 self.assertEqual((name, path), 167 self.init.find_loader(name, path)) 168 169 def test_nothing(self): 170 # None is returned upon failure to find a loader. 171 with warnings.catch_warnings(): 172 warnings.simplefilter('ignore', DeprecationWarning) 173 self.assertIsNone(self.init.find_loader('nevergoingtofindthismodule')) 174 175 176class FindLoaderPEP451Tests(FindLoaderTests): 177 178 class FakeMetaFinder: 179 @staticmethod 180 def find_spec(name, path=None, target=None): 181 return machinery['Source'].ModuleSpec(name, (name, path)) 182 183 184(Frozen_FindLoaderPEP451Tests, 185 Source_FindLoaderPEP451Tests 186 ) = test_util.test_both(FindLoaderPEP451Tests, init=init) 187 188 189class FindLoaderPEP302Tests(FindLoaderTests): 190 191 class FakeMetaFinder: 192 @staticmethod 193 def find_module(name, path=None): 194 return name, path 195 196 197(Frozen_FindLoaderPEP302Tests, 198 Source_FindLoaderPEP302Tests 199 ) = test_util.test_both(FindLoaderPEP302Tests, init=init) 200 201 202class ReloadTests: 203 204 def test_reload_modules(self): 205 for mod in ('tokenize', 'time', 'marshal'): 206 with self.subTest(module=mod): 207 with import_helper.CleanImport(mod): 208 module = self.init.import_module(mod) 209 self.init.reload(module) 210 211 def test_module_replaced(self): 212 def code(): 213 import sys 214 module = type(sys)('top_level') 215 module.spam = 3 216 sys.modules['top_level'] = module 217 mock = test_util.mock_spec('top_level', 218 module_code={'top_level': code}) 219 with mock: 220 with test_util.import_state(meta_path=[mock]): 221 module = self.init.import_module('top_level') 222 reloaded = self.init.reload(module) 223 actual = sys.modules['top_level'] 224 self.assertEqual(actual.spam, 3) 225 self.assertEqual(reloaded.spam, 3) 226 227 def test_reload_missing_loader(self): 228 with import_helper.CleanImport('types'): 229 import types 230 loader = types.__loader__ 231 del types.__loader__ 232 reloaded = self.init.reload(types) 233 234 self.assertIs(reloaded, types) 235 self.assertIs(sys.modules['types'], types) 236 self.assertEqual(reloaded.__loader__.path, loader.path) 237 238 def test_reload_loader_replaced(self): 239 with import_helper.CleanImport('types'): 240 import types 241 types.__loader__ = None 242 self.init.invalidate_caches() 243 reloaded = self.init.reload(types) 244 245 self.assertIsNot(reloaded.__loader__, None) 246 self.assertIs(reloaded, types) 247 self.assertIs(sys.modules['types'], types) 248 249 def test_reload_location_changed(self): 250 name = 'spam' 251 with os_helper.temp_cwd(None) as cwd: 252 with test_util.uncache('spam'): 253 with import_helper.DirsOnSysPath(cwd): 254 # Start as a plain module. 255 self.init.invalidate_caches() 256 path = os.path.join(cwd, name + '.py') 257 cached = self.util.cache_from_source(path) 258 expected = {'__name__': name, 259 '__package__': '', 260 '__file__': path, 261 '__cached__': cached, 262 '__doc__': None, 263 } 264 os_helper.create_empty_file(path) 265 module = self.init.import_module(name) 266 ns = vars(module).copy() 267 loader = ns.pop('__loader__') 268 spec = ns.pop('__spec__') 269 ns.pop('__builtins__', None) # An implementation detail. 270 self.assertEqual(spec.name, name) 271 self.assertEqual(spec.loader, loader) 272 self.assertEqual(loader.path, path) 273 self.assertEqual(ns, expected) 274 275 # Change to a package. 276 self.init.invalidate_caches() 277 init_path = os.path.join(cwd, name, '__init__.py') 278 cached = self.util.cache_from_source(init_path) 279 expected = {'__name__': name, 280 '__package__': name, 281 '__file__': init_path, 282 '__cached__': cached, 283 '__path__': [os.path.dirname(init_path)], 284 '__doc__': None, 285 } 286 os.mkdir(name) 287 os.rename(path, init_path) 288 reloaded = self.init.reload(module) 289 ns = vars(reloaded).copy() 290 loader = ns.pop('__loader__') 291 spec = ns.pop('__spec__') 292 ns.pop('__builtins__', None) # An implementation detail. 293 self.assertEqual(spec.name, name) 294 self.assertEqual(spec.loader, loader) 295 self.assertIs(reloaded, module) 296 self.assertEqual(loader.path, init_path) 297 self.maxDiff = None 298 self.assertEqual(ns, expected) 299 300 def test_reload_namespace_changed(self): 301 name = 'spam' 302 with os_helper.temp_cwd(None) as cwd: 303 with test_util.uncache('spam'): 304 with import_helper.DirsOnSysPath(cwd): 305 # Start as a namespace package. 306 self.init.invalidate_caches() 307 bad_path = os.path.join(cwd, name, '__init.py') 308 cached = self.util.cache_from_source(bad_path) 309 expected = {'__name__': name, 310 '__package__': name, 311 '__doc__': None, 312 '__file__': None, 313 } 314 os.mkdir(name) 315 with open(bad_path, 'w', encoding='utf-8') as init_file: 316 init_file.write('eggs = None') 317 module = self.init.import_module(name) 318 ns = vars(module).copy() 319 loader = ns.pop('__loader__') 320 path = ns.pop('__path__') 321 spec = ns.pop('__spec__') 322 ns.pop('__builtins__', None) # An implementation detail. 323 self.assertEqual(spec.name, name) 324 self.assertIsNotNone(spec.loader) 325 self.assertIsNotNone(loader) 326 self.assertEqual(spec.loader, loader) 327 self.assertEqual(set(path), 328 set([os.path.dirname(bad_path)])) 329 with self.assertRaises(AttributeError): 330 # a NamespaceLoader 331 loader.path 332 self.assertEqual(ns, expected) 333 334 # Change to a regular package. 335 self.init.invalidate_caches() 336 init_path = os.path.join(cwd, name, '__init__.py') 337 cached = self.util.cache_from_source(init_path) 338 expected = {'__name__': name, 339 '__package__': name, 340 '__file__': init_path, 341 '__cached__': cached, 342 '__path__': [os.path.dirname(init_path)], 343 '__doc__': None, 344 'eggs': None, 345 } 346 os.rename(bad_path, init_path) 347 reloaded = self.init.reload(module) 348 ns = vars(reloaded).copy() 349 loader = ns.pop('__loader__') 350 spec = ns.pop('__spec__') 351 ns.pop('__builtins__', None) # An implementation detail. 352 self.assertEqual(spec.name, name) 353 self.assertEqual(spec.loader, loader) 354 self.assertIs(reloaded, module) 355 self.assertEqual(loader.path, init_path) 356 self.assertEqual(ns, expected) 357 358 def test_reload_submodule(self): 359 # See #19851. 360 name = 'spam' 361 subname = 'ham' 362 with test_util.temp_module(name, pkg=True) as pkg_dir: 363 fullname, _ = test_util.submodule(name, subname, pkg_dir) 364 ham = self.init.import_module(fullname) 365 reloaded = self.init.reload(ham) 366 self.assertIs(reloaded, ham) 367 368 def test_module_missing_spec(self): 369 #Test that reload() throws ModuleNotFounderror when reloading 370 # a module whose missing a spec. (bpo-29851) 371 name = 'spam' 372 with test_util.uncache(name): 373 module = sys.modules[name] = types.ModuleType(name) 374 # Sanity check by attempting an import. 375 module = self.init.import_module(name) 376 self.assertIsNone(module.__spec__) 377 with self.assertRaises(ModuleNotFoundError): 378 self.init.reload(module) 379 380 381(Frozen_ReloadTests, 382 Source_ReloadTests 383 ) = test_util.test_both(ReloadTests, init=init, util=util) 384 385 386class InvalidateCacheTests: 387 388 def test_method_called(self): 389 # If defined the method should be called. 390 class InvalidatingNullFinder: 391 def __init__(self, *ignored): 392 self.called = False 393 def find_module(self, *args): 394 return None 395 def invalidate_caches(self): 396 self.called = True 397 398 key = 'gobledeegook' 399 meta_ins = InvalidatingNullFinder() 400 path_ins = InvalidatingNullFinder() 401 sys.meta_path.insert(0, meta_ins) 402 self.addCleanup(lambda: sys.path_importer_cache.__delitem__(key)) 403 sys.path_importer_cache[key] = path_ins 404 self.addCleanup(lambda: sys.meta_path.remove(meta_ins)) 405 self.init.invalidate_caches() 406 self.assertTrue(meta_ins.called) 407 self.assertTrue(path_ins.called) 408 409 def test_method_lacking(self): 410 # There should be no issues if the method is not defined. 411 key = 'gobbledeegook' 412 sys.path_importer_cache[key] = None 413 self.addCleanup(lambda: sys.path_importer_cache.pop(key, None)) 414 self.init.invalidate_caches() # Shouldn't trigger an exception. 415 416 417(Frozen_InvalidateCacheTests, 418 Source_InvalidateCacheTests 419 ) = test_util.test_both(InvalidateCacheTests, init=init) 420 421 422class FrozenImportlibTests(unittest.TestCase): 423 424 def test_no_frozen_importlib(self): 425 # Should be able to import w/o _frozen_importlib being defined. 426 # Can't do an isinstance() check since separate copies of importlib 427 # may have been used for import, so just check the name is not for the 428 # frozen loader. 429 source_init = init['Source'] 430 self.assertNotEqual(source_init.__loader__.__class__.__name__, 431 'FrozenImporter') 432 433 434class StartupTests: 435 436 def test_everyone_has___loader__(self): 437 # Issue #17098: all modules should have __loader__ defined. 438 for name, module in sys.modules.items(): 439 if isinstance(module, types.ModuleType): 440 with self.subTest(name=name): 441 self.assertTrue(hasattr(module, '__loader__'), 442 '{!r} lacks a __loader__ attribute'.format(name)) 443 if self.machinery.BuiltinImporter.find_spec(name): 444 self.assertIsNot(module.__loader__, None) 445 elif self.machinery.FrozenImporter.find_spec(name): 446 self.assertIsNot(module.__loader__, None) 447 448 def test_everyone_has___spec__(self): 449 for name, module in sys.modules.items(): 450 if isinstance(module, types.ModuleType): 451 with self.subTest(name=name): 452 self.assertTrue(hasattr(module, '__spec__')) 453 if self.machinery.BuiltinImporter.find_spec(name): 454 self.assertIsNot(module.__spec__, None) 455 elif self.machinery.FrozenImporter.find_spec(name): 456 self.assertIsNot(module.__spec__, None) 457 458 459(Frozen_StartupTests, 460 Source_StartupTests 461 ) = test_util.test_both(StartupTests, machinery=machinery) 462 463 464if __name__ == '__main__': 465 unittest.main() 466