1import io 2import marshal 3import os 4import sys 5from test import support 6import types 7import unittest 8from unittest import mock 9import warnings 10 11from . import util as test_util 12 13init = test_util.import_importlib('importlib') 14abc = test_util.import_importlib('importlib.abc') 15machinery = test_util.import_importlib('importlib.machinery') 16util = test_util.import_importlib('importlib.util') 17 18 19##### Inheritance ############################################################## 20class InheritanceTests: 21 22 """Test that the specified class is a subclass/superclass of the expected 23 classes.""" 24 25 subclasses = [] 26 superclasses = [] 27 28 def setUp(self): 29 self.superclasses = [getattr(self.abc, class_name) 30 for class_name in self.superclass_names] 31 if hasattr(self, 'subclass_names'): 32 # Because test.support.import_fresh_module() creates a new 33 # importlib._bootstrap per module, inheritance checks fail when 34 # checking across module boundaries (i.e. the _bootstrap in abc is 35 # not the same as the one in machinery). That means stealing one of 36 # the modules from the other to make sure the same instance is used. 37 machinery = self.abc.machinery 38 self.subclasses = [getattr(machinery, class_name) 39 for class_name in self.subclass_names] 40 assert self.subclasses or self.superclasses, self.__class__ 41 self.__test = getattr(self.abc, self._NAME) 42 43 def test_subclasses(self): 44 # Test that the expected subclasses inherit. 45 for subclass in self.subclasses: 46 self.assertTrue(issubclass(subclass, self.__test), 47 "{0} is not a subclass of {1}".format(subclass, self.__test)) 48 49 def test_superclasses(self): 50 # Test that the class inherits from the expected superclasses. 51 for superclass in self.superclasses: 52 self.assertTrue(issubclass(self.__test, superclass), 53 "{0} is not a superclass of {1}".format(superclass, self.__test)) 54 55 56class MetaPathFinder(InheritanceTests): 57 superclass_names = ['Finder'] 58 subclass_names = ['BuiltinImporter', 'FrozenImporter', 'PathFinder', 59 'WindowsRegistryFinder'] 60 61 62(Frozen_MetaPathFinderInheritanceTests, 63 Source_MetaPathFinderInheritanceTests 64 ) = test_util.test_both(MetaPathFinder, abc=abc) 65 66 67class PathEntryFinder(InheritanceTests): 68 superclass_names = ['Finder'] 69 subclass_names = ['FileFinder'] 70 71 72(Frozen_PathEntryFinderInheritanceTests, 73 Source_PathEntryFinderInheritanceTests 74 ) = test_util.test_both(PathEntryFinder, abc=abc) 75 76 77class ResourceLoader(InheritanceTests): 78 superclass_names = ['Loader'] 79 80 81(Frozen_ResourceLoaderInheritanceTests, 82 Source_ResourceLoaderInheritanceTests 83 ) = test_util.test_both(ResourceLoader, abc=abc) 84 85 86class InspectLoader(InheritanceTests): 87 superclass_names = ['Loader'] 88 subclass_names = ['BuiltinImporter', 'FrozenImporter', 'ExtensionFileLoader'] 89 90 91(Frozen_InspectLoaderInheritanceTests, 92 Source_InspectLoaderInheritanceTests 93 ) = test_util.test_both(InspectLoader, abc=abc) 94 95 96class ExecutionLoader(InheritanceTests): 97 superclass_names = ['InspectLoader'] 98 subclass_names = ['ExtensionFileLoader'] 99 100 101(Frozen_ExecutionLoaderInheritanceTests, 102 Source_ExecutionLoaderInheritanceTests 103 ) = test_util.test_both(ExecutionLoader, abc=abc) 104 105 106class FileLoader(InheritanceTests): 107 superclass_names = ['ResourceLoader', 'ExecutionLoader'] 108 subclass_names = ['SourceFileLoader', 'SourcelessFileLoader'] 109 110 111(Frozen_FileLoaderInheritanceTests, 112 Source_FileLoaderInheritanceTests 113 ) = test_util.test_both(FileLoader, abc=abc) 114 115 116class SourceLoader(InheritanceTests): 117 superclass_names = ['ResourceLoader', 'ExecutionLoader'] 118 subclass_names = ['SourceFileLoader'] 119 120 121(Frozen_SourceLoaderInheritanceTests, 122 Source_SourceLoaderInheritanceTests 123 ) = test_util.test_both(SourceLoader, abc=abc) 124 125 126##### Default return values #################################################### 127 128def make_abc_subclasses(base_class, name=None, inst=False, **kwargs): 129 if name is None: 130 name = base_class.__name__ 131 base = {kind: getattr(splitabc, name) 132 for kind, splitabc in abc.items()} 133 return {cls._KIND: cls() if inst else cls 134 for cls in test_util.split_frozen(base_class, base, **kwargs)} 135 136 137class ABCTestHarness: 138 139 @property 140 def ins(self): 141 # Lazily set ins on the class. 142 cls = self.SPLIT[self._KIND] 143 ins = cls() 144 self.__class__.ins = ins 145 return ins 146 147 148class MetaPathFinder: 149 150 def find_module(self, fullname, path): 151 return super().find_module(fullname, path) 152 153 154class MetaPathFinderDefaultsTests(ABCTestHarness): 155 156 SPLIT = make_abc_subclasses(MetaPathFinder) 157 158 def test_find_module(self): 159 # Default should return None. 160 with self.assertWarns(DeprecationWarning): 161 found = self.ins.find_module('something', None) 162 self.assertIsNone(found) 163 164 def test_invalidate_caches(self): 165 # Calling the method is a no-op. 166 self.ins.invalidate_caches() 167 168 169(Frozen_MPFDefaultTests, 170 Source_MPFDefaultTests 171 ) = test_util.test_both(MetaPathFinderDefaultsTests) 172 173 174class PathEntryFinder: 175 176 def find_loader(self, fullname): 177 return super().find_loader(fullname) 178 179 180class PathEntryFinderDefaultsTests(ABCTestHarness): 181 182 SPLIT = make_abc_subclasses(PathEntryFinder) 183 184 def test_find_loader(self): 185 with self.assertWarns(DeprecationWarning): 186 found = self.ins.find_loader('something') 187 self.assertEqual(found, (None, [])) 188 189 def find_module(self): 190 self.assertEqual(None, self.ins.find_module('something')) 191 192 def test_invalidate_caches(self): 193 # Should be a no-op. 194 self.ins.invalidate_caches() 195 196 197(Frozen_PEFDefaultTests, 198 Source_PEFDefaultTests 199 ) = test_util.test_both(PathEntryFinderDefaultsTests) 200 201 202class Loader: 203 204 def load_module(self, fullname): 205 return super().load_module(fullname) 206 207 208class LoaderDefaultsTests(ABCTestHarness): 209 210 SPLIT = make_abc_subclasses(Loader) 211 212 def test_create_module(self): 213 spec = 'a spec' 214 self.assertIsNone(self.ins.create_module(spec)) 215 216 def test_load_module(self): 217 with self.assertRaises(ImportError): 218 self.ins.load_module('something') 219 220 def test_module_repr(self): 221 mod = types.ModuleType('blah') 222 with self.assertRaises(NotImplementedError): 223 self.ins.module_repr(mod) 224 original_repr = repr(mod) 225 mod.__loader__ = self.ins 226 # Should still return a proper repr. 227 self.assertTrue(repr(mod)) 228 229 230(Frozen_LDefaultTests, 231 SourceLDefaultTests 232 ) = test_util.test_both(LoaderDefaultsTests) 233 234 235class ResourceLoader(Loader): 236 237 def get_data(self, path): 238 return super().get_data(path) 239 240 241class ResourceLoaderDefaultsTests(ABCTestHarness): 242 243 SPLIT = make_abc_subclasses(ResourceLoader) 244 245 def test_get_data(self): 246 with self.assertRaises(IOError): 247 self.ins.get_data('/some/path') 248 249 250(Frozen_RLDefaultTests, 251 Source_RLDefaultTests 252 ) = test_util.test_both(ResourceLoaderDefaultsTests) 253 254 255class InspectLoader(Loader): 256 257 def is_package(self, fullname): 258 return super().is_package(fullname) 259 260 def get_source(self, fullname): 261 return super().get_source(fullname) 262 263 264SPLIT_IL = make_abc_subclasses(InspectLoader) 265 266 267class InspectLoaderDefaultsTests(ABCTestHarness): 268 269 SPLIT = SPLIT_IL 270 271 def test_is_package(self): 272 with self.assertRaises(ImportError): 273 self.ins.is_package('blah') 274 275 def test_get_source(self): 276 with self.assertRaises(ImportError): 277 self.ins.get_source('blah') 278 279 280(Frozen_ILDefaultTests, 281 Source_ILDefaultTests 282 ) = test_util.test_both(InspectLoaderDefaultsTests) 283 284 285class ExecutionLoader(InspectLoader): 286 287 def get_filename(self, fullname): 288 return super().get_filename(fullname) 289 290 291SPLIT_EL = make_abc_subclasses(ExecutionLoader) 292 293 294class ExecutionLoaderDefaultsTests(ABCTestHarness): 295 296 SPLIT = SPLIT_EL 297 298 def test_get_filename(self): 299 with self.assertRaises(ImportError): 300 self.ins.get_filename('blah') 301 302 303(Frozen_ELDefaultTests, 304 Source_ELDefaultsTests 305 ) = test_util.test_both(InspectLoaderDefaultsTests) 306 307 308class ResourceReader: 309 310 def open_resource(self, *args, **kwargs): 311 return super().open_resource(*args, **kwargs) 312 313 def resource_path(self, *args, **kwargs): 314 return super().resource_path(*args, **kwargs) 315 316 def is_resource(self, *args, **kwargs): 317 return super().is_resource(*args, **kwargs) 318 319 def contents(self, *args, **kwargs): 320 return super().contents(*args, **kwargs) 321 322 323class ResourceReaderDefaultsTests(ABCTestHarness): 324 325 SPLIT = make_abc_subclasses(ResourceReader) 326 327 def test_open_resource(self): 328 with self.assertRaises(FileNotFoundError): 329 self.ins.open_resource('dummy_file') 330 331 def test_resource_path(self): 332 with self.assertRaises(FileNotFoundError): 333 self.ins.resource_path('dummy_file') 334 335 def test_is_resource(self): 336 with self.assertRaises(FileNotFoundError): 337 self.ins.is_resource('dummy_file') 338 339 def test_contents(self): 340 self.assertEqual([], list(self.ins.contents())) 341 342(Frozen_RRDefaultTests, 343 Source_RRDefaultsTests 344 ) = test_util.test_both(ResourceReaderDefaultsTests) 345 346 347##### MetaPathFinder concrete methods ########################################## 348class MetaPathFinderFindModuleTests: 349 350 @classmethod 351 def finder(cls, spec): 352 class MetaPathSpecFinder(cls.abc.MetaPathFinder): 353 354 def find_spec(self, fullname, path, target=None): 355 self.called_for = fullname, path 356 return spec 357 358 return MetaPathSpecFinder() 359 360 def test_no_spec(self): 361 finder = self.finder(None) 362 path = ['a', 'b', 'c'] 363 name = 'blah' 364 with self.assertWarns(DeprecationWarning): 365 found = finder.find_module(name, path) 366 self.assertIsNone(found) 367 self.assertEqual(name, finder.called_for[0]) 368 self.assertEqual(path, finder.called_for[1]) 369 370 def test_spec(self): 371 loader = object() 372 spec = self.util.spec_from_loader('blah', loader) 373 finder = self.finder(spec) 374 with self.assertWarns(DeprecationWarning): 375 found = finder.find_module('blah', None) 376 self.assertIs(found, spec.loader) 377 378 379(Frozen_MPFFindModuleTests, 380 Source_MPFFindModuleTests 381 ) = test_util.test_both(MetaPathFinderFindModuleTests, abc=abc, util=util) 382 383 384##### PathEntryFinder concrete methods ######################################### 385class PathEntryFinderFindLoaderTests: 386 387 @classmethod 388 def finder(cls, spec): 389 class PathEntrySpecFinder(cls.abc.PathEntryFinder): 390 391 def find_spec(self, fullname, target=None): 392 self.called_for = fullname 393 return spec 394 395 return PathEntrySpecFinder() 396 397 def test_no_spec(self): 398 finder = self.finder(None) 399 name = 'blah' 400 with self.assertWarns(DeprecationWarning): 401 found = finder.find_loader(name) 402 self.assertIsNone(found[0]) 403 self.assertEqual([], found[1]) 404 self.assertEqual(name, finder.called_for) 405 406 def test_spec_with_loader(self): 407 loader = object() 408 spec = self.util.spec_from_loader('blah', loader) 409 finder = self.finder(spec) 410 with self.assertWarns(DeprecationWarning): 411 found = finder.find_loader('blah') 412 self.assertIs(found[0], spec.loader) 413 414 def test_spec_with_portions(self): 415 spec = self.machinery.ModuleSpec('blah', None) 416 paths = ['a', 'b', 'c'] 417 spec.submodule_search_locations = paths 418 finder = self.finder(spec) 419 with self.assertWarns(DeprecationWarning): 420 found = finder.find_loader('blah') 421 self.assertIsNone(found[0]) 422 self.assertEqual(paths, found[1]) 423 424 425(Frozen_PEFFindLoaderTests, 426 Source_PEFFindLoaderTests 427 ) = test_util.test_both(PathEntryFinderFindLoaderTests, abc=abc, util=util, 428 machinery=machinery) 429 430 431##### Loader concrete methods ################################################## 432class LoaderLoadModuleTests: 433 434 def loader(self): 435 class SpecLoader(self.abc.Loader): 436 found = None 437 def exec_module(self, module): 438 self.found = module 439 440 def is_package(self, fullname): 441 """Force some non-default module state to be set.""" 442 return True 443 444 return SpecLoader() 445 446 def test_fresh(self): 447 loader = self.loader() 448 name = 'blah' 449 with test_util.uncache(name): 450 loader.load_module(name) 451 module = loader.found 452 self.assertIs(sys.modules[name], module) 453 self.assertEqual(loader, module.__loader__) 454 self.assertEqual(loader, module.__spec__.loader) 455 self.assertEqual(name, module.__name__) 456 self.assertEqual(name, module.__spec__.name) 457 self.assertIsNotNone(module.__path__) 458 self.assertIsNotNone(module.__path__, 459 module.__spec__.submodule_search_locations) 460 461 def test_reload(self): 462 name = 'blah' 463 loader = self.loader() 464 module = types.ModuleType(name) 465 module.__spec__ = self.util.spec_from_loader(name, loader) 466 module.__loader__ = loader 467 with test_util.uncache(name): 468 sys.modules[name] = module 469 loader.load_module(name) 470 found = loader.found 471 self.assertIs(found, sys.modules[name]) 472 self.assertIs(module, sys.modules[name]) 473 474 475(Frozen_LoaderLoadModuleTests, 476 Source_LoaderLoadModuleTests 477 ) = test_util.test_both(LoaderLoadModuleTests, abc=abc, util=util) 478 479 480##### InspectLoader concrete methods ########################################### 481class InspectLoaderSourceToCodeTests: 482 483 def source_to_module(self, data, path=None): 484 """Help with source_to_code() tests.""" 485 module = types.ModuleType('blah') 486 loader = self.InspectLoaderSubclass() 487 if path is None: 488 code = loader.source_to_code(data) 489 else: 490 code = loader.source_to_code(data, path) 491 exec(code, module.__dict__) 492 return module 493 494 def test_source_to_code_source(self): 495 # Since compile() can handle strings, so should source_to_code(). 496 source = 'attr = 42' 497 module = self.source_to_module(source) 498 self.assertTrue(hasattr(module, 'attr')) 499 self.assertEqual(module.attr, 42) 500 501 def test_source_to_code_bytes(self): 502 # Since compile() can handle bytes, so should source_to_code(). 503 source = b'attr = 42' 504 module = self.source_to_module(source) 505 self.assertTrue(hasattr(module, 'attr')) 506 self.assertEqual(module.attr, 42) 507 508 def test_source_to_code_path(self): 509 # Specifying a path should set it for the code object. 510 path = 'path/to/somewhere' 511 loader = self.InspectLoaderSubclass() 512 code = loader.source_to_code('', path) 513 self.assertEqual(code.co_filename, path) 514 515 def test_source_to_code_no_path(self): 516 # Not setting a path should still work and be set to <string> since that 517 # is a pre-existing practice as a default to compile(). 518 loader = self.InspectLoaderSubclass() 519 code = loader.source_to_code('') 520 self.assertEqual(code.co_filename, '<string>') 521 522 523(Frozen_ILSourceToCodeTests, 524 Source_ILSourceToCodeTests 525 ) = test_util.test_both(InspectLoaderSourceToCodeTests, 526 InspectLoaderSubclass=SPLIT_IL) 527 528 529class InspectLoaderGetCodeTests: 530 531 def test_get_code(self): 532 # Test success. 533 module = types.ModuleType('blah') 534 with mock.patch.object(self.InspectLoaderSubclass, 'get_source') as mocked: 535 mocked.return_value = 'attr = 42' 536 loader = self.InspectLoaderSubclass() 537 code = loader.get_code('blah') 538 exec(code, module.__dict__) 539 self.assertEqual(module.attr, 42) 540 541 def test_get_code_source_is_None(self): 542 # If get_source() is None then this should be None. 543 with mock.patch.object(self.InspectLoaderSubclass, 'get_source') as mocked: 544 mocked.return_value = None 545 loader = self.InspectLoaderSubclass() 546 code = loader.get_code('blah') 547 self.assertIsNone(code) 548 549 def test_get_code_source_not_found(self): 550 # If there is no source then there is no code object. 551 loader = self.InspectLoaderSubclass() 552 with self.assertRaises(ImportError): 553 loader.get_code('blah') 554 555 556(Frozen_ILGetCodeTests, 557 Source_ILGetCodeTests 558 ) = test_util.test_both(InspectLoaderGetCodeTests, 559 InspectLoaderSubclass=SPLIT_IL) 560 561 562class InspectLoaderLoadModuleTests: 563 564 """Test InspectLoader.load_module().""" 565 566 module_name = 'blah' 567 568 def setUp(self): 569 support.unload(self.module_name) 570 self.addCleanup(support.unload, self.module_name) 571 572 def load(self, loader): 573 spec = self.util.spec_from_loader(self.module_name, loader) 574 with warnings.catch_warnings(): 575 warnings.simplefilter('ignore', DeprecationWarning) 576 return self.init._bootstrap._load_unlocked(spec) 577 578 def mock_get_code(self): 579 return mock.patch.object(self.InspectLoaderSubclass, 'get_code') 580 581 def test_get_code_ImportError(self): 582 # If get_code() raises ImportError, it should propagate. 583 with self.mock_get_code() as mocked_get_code: 584 mocked_get_code.side_effect = ImportError 585 with self.assertRaises(ImportError): 586 loader = self.InspectLoaderSubclass() 587 self.load(loader) 588 589 def test_get_code_None(self): 590 # If get_code() returns None, raise ImportError. 591 with self.mock_get_code() as mocked_get_code: 592 mocked_get_code.return_value = None 593 with self.assertRaises(ImportError): 594 loader = self.InspectLoaderSubclass() 595 self.load(loader) 596 597 def test_module_returned(self): 598 # The loaded module should be returned. 599 code = compile('attr = 42', '<string>', 'exec') 600 with self.mock_get_code() as mocked_get_code: 601 mocked_get_code.return_value = code 602 loader = self.InspectLoaderSubclass() 603 module = self.load(loader) 604 self.assertEqual(module, sys.modules[self.module_name]) 605 606 607(Frozen_ILLoadModuleTests, 608 Source_ILLoadModuleTests 609 ) = test_util.test_both(InspectLoaderLoadModuleTests, 610 InspectLoaderSubclass=SPLIT_IL, 611 init=init, 612 util=util) 613 614 615##### ExecutionLoader concrete methods ######################################### 616class ExecutionLoaderGetCodeTests: 617 618 def mock_methods(self, *, get_source=False, get_filename=False): 619 source_mock_context, filename_mock_context = None, None 620 if get_source: 621 source_mock_context = mock.patch.object(self.ExecutionLoaderSubclass, 622 'get_source') 623 if get_filename: 624 filename_mock_context = mock.patch.object(self.ExecutionLoaderSubclass, 625 'get_filename') 626 return source_mock_context, filename_mock_context 627 628 def test_get_code(self): 629 path = 'blah.py' 630 source_mock_context, filename_mock_context = self.mock_methods( 631 get_source=True, get_filename=True) 632 with source_mock_context as source_mock, filename_mock_context as name_mock: 633 source_mock.return_value = 'attr = 42' 634 name_mock.return_value = path 635 loader = self.ExecutionLoaderSubclass() 636 code = loader.get_code('blah') 637 self.assertEqual(code.co_filename, path) 638 module = types.ModuleType('blah') 639 exec(code, module.__dict__) 640 self.assertEqual(module.attr, 42) 641 642 def test_get_code_source_is_None(self): 643 # If get_source() is None then this should be None. 644 source_mock_context, _ = self.mock_methods(get_source=True) 645 with source_mock_context as mocked: 646 mocked.return_value = None 647 loader = self.ExecutionLoaderSubclass() 648 code = loader.get_code('blah') 649 self.assertIsNone(code) 650 651 def test_get_code_source_not_found(self): 652 # If there is no source then there is no code object. 653 loader = self.ExecutionLoaderSubclass() 654 with self.assertRaises(ImportError): 655 loader.get_code('blah') 656 657 def test_get_code_no_path(self): 658 # If get_filename() raises ImportError then simply skip setting the path 659 # on the code object. 660 source_mock_context, filename_mock_context = self.mock_methods( 661 get_source=True, get_filename=True) 662 with source_mock_context as source_mock, filename_mock_context as name_mock: 663 source_mock.return_value = 'attr = 42' 664 name_mock.side_effect = ImportError 665 loader = self.ExecutionLoaderSubclass() 666 code = loader.get_code('blah') 667 self.assertEqual(code.co_filename, '<string>') 668 module = types.ModuleType('blah') 669 exec(code, module.__dict__) 670 self.assertEqual(module.attr, 42) 671 672 673(Frozen_ELGetCodeTests, 674 Source_ELGetCodeTests 675 ) = test_util.test_both(ExecutionLoaderGetCodeTests, 676 ExecutionLoaderSubclass=SPLIT_EL) 677 678 679##### SourceLoader concrete methods ############################################ 680class SourceOnlyLoader: 681 682 # Globals that should be defined for all modules. 683 source = (b"_ = '::'.join([__name__, __file__, __cached__, __package__, " 684 b"repr(__loader__)])") 685 686 def __init__(self, path): 687 self.path = path 688 689 def get_data(self, path): 690 if path != self.path: 691 raise IOError 692 return self.source 693 694 def get_filename(self, fullname): 695 return self.path 696 697 def module_repr(self, module): 698 return '<module>' 699 700 701SPLIT_SOL = make_abc_subclasses(SourceOnlyLoader, 'SourceLoader') 702 703 704class SourceLoader(SourceOnlyLoader): 705 706 source_mtime = 1 707 708 def __init__(self, path, magic=None): 709 super().__init__(path) 710 self.bytecode_path = self.util.cache_from_source(self.path) 711 self.source_size = len(self.source) 712 if magic is None: 713 magic = self.util.MAGIC_NUMBER 714 data = bytearray(magic) 715 data.extend(self.init._w_long(0)) 716 data.extend(self.init._w_long(self.source_mtime)) 717 data.extend(self.init._w_long(self.source_size)) 718 code_object = compile(self.source, self.path, 'exec', 719 dont_inherit=True) 720 data.extend(marshal.dumps(code_object)) 721 self.bytecode = bytes(data) 722 self.written = {} 723 724 def get_data(self, path): 725 if path == self.path: 726 return super().get_data(path) 727 elif path == self.bytecode_path: 728 return self.bytecode 729 else: 730 raise OSError 731 732 def path_stats(self, path): 733 if path != self.path: 734 raise IOError 735 return {'mtime': self.source_mtime, 'size': self.source_size} 736 737 def set_data(self, path, data): 738 self.written[path] = bytes(data) 739 return path == self.bytecode_path 740 741 742SPLIT_SL = make_abc_subclasses(SourceLoader, util=util, init=init) 743 744 745class SourceLoaderTestHarness: 746 747 def setUp(self, *, is_package=True, **kwargs): 748 self.package = 'pkg' 749 if is_package: 750 self.path = os.path.join(self.package, '__init__.py') 751 self.name = self.package 752 else: 753 module_name = 'mod' 754 self.path = os.path.join(self.package, '.'.join(['mod', 'py'])) 755 self.name = '.'.join([self.package, module_name]) 756 self.cached = self.util.cache_from_source(self.path) 757 self.loader = self.loader_mock(self.path, **kwargs) 758 759 def verify_module(self, module): 760 self.assertEqual(module.__name__, self.name) 761 self.assertEqual(module.__file__, self.path) 762 self.assertEqual(module.__cached__, self.cached) 763 self.assertEqual(module.__package__, self.package) 764 self.assertEqual(module.__loader__, self.loader) 765 values = module._.split('::') 766 self.assertEqual(values[0], self.name) 767 self.assertEqual(values[1], self.path) 768 self.assertEqual(values[2], self.cached) 769 self.assertEqual(values[3], self.package) 770 self.assertEqual(values[4], repr(self.loader)) 771 772 def verify_code(self, code_object): 773 module = types.ModuleType(self.name) 774 module.__file__ = self.path 775 module.__cached__ = self.cached 776 module.__package__ = self.package 777 module.__loader__ = self.loader 778 module.__path__ = [] 779 exec(code_object, module.__dict__) 780 self.verify_module(module) 781 782 783class SourceOnlyLoaderTests(SourceLoaderTestHarness): 784 785 """Test importlib.abc.SourceLoader for source-only loading. 786 787 Reload testing is subsumed by the tests for 788 importlib.util.module_for_loader. 789 790 """ 791 792 def test_get_source(self): 793 # Verify the source code is returned as a string. 794 # If an OSError is raised by get_data then raise ImportError. 795 expected_source = self.loader.source.decode('utf-8') 796 self.assertEqual(self.loader.get_source(self.name), expected_source) 797 def raise_OSError(path): 798 raise OSError 799 self.loader.get_data = raise_OSError 800 with self.assertRaises(ImportError) as cm: 801 self.loader.get_source(self.name) 802 self.assertEqual(cm.exception.name, self.name) 803 804 def test_is_package(self): 805 # Properly detect when loading a package. 806 self.setUp(is_package=False) 807 self.assertFalse(self.loader.is_package(self.name)) 808 self.setUp(is_package=True) 809 self.assertTrue(self.loader.is_package(self.name)) 810 self.assertFalse(self.loader.is_package(self.name + '.__init__')) 811 812 def test_get_code(self): 813 # Verify the code object is created. 814 code_object = self.loader.get_code(self.name) 815 self.verify_code(code_object) 816 817 def test_source_to_code(self): 818 # Verify the compiled code object. 819 code = self.loader.source_to_code(self.loader.source, self.path) 820 self.verify_code(code) 821 822 def test_load_module(self): 823 # Loading a module should set __name__, __loader__, __package__, 824 # __path__ (for packages), __file__, and __cached__. 825 # The module should also be put into sys.modules. 826 with test_util.uncache(self.name): 827 with warnings.catch_warnings(): 828 warnings.simplefilter('ignore', DeprecationWarning) 829 module = self.loader.load_module(self.name) 830 self.verify_module(module) 831 self.assertEqual(module.__path__, [os.path.dirname(self.path)]) 832 self.assertIn(self.name, sys.modules) 833 834 def test_package_settings(self): 835 # __package__ needs to be set, while __path__ is set on if the module 836 # is a package. 837 # Testing the values for a package are covered by test_load_module. 838 self.setUp(is_package=False) 839 with test_util.uncache(self.name): 840 with warnings.catch_warnings(): 841 warnings.simplefilter('ignore', DeprecationWarning) 842 module = self.loader.load_module(self.name) 843 self.verify_module(module) 844 self.assertFalse(hasattr(module, '__path__')) 845 846 def test_get_source_encoding(self): 847 # Source is considered encoded in UTF-8 by default unless otherwise 848 # specified by an encoding line. 849 source = "_ = 'ü'" 850 self.loader.source = source.encode('utf-8') 851 returned_source = self.loader.get_source(self.name) 852 self.assertEqual(returned_source, source) 853 source = "# coding: latin-1\n_ = ü" 854 self.loader.source = source.encode('latin-1') 855 returned_source = self.loader.get_source(self.name) 856 self.assertEqual(returned_source, source) 857 858 859(Frozen_SourceOnlyLoaderTests, 860 Source_SourceOnlyLoaderTests 861 ) = test_util.test_both(SourceOnlyLoaderTests, util=util, 862 loader_mock=SPLIT_SOL) 863 864 865@unittest.skipIf(sys.dont_write_bytecode, "sys.dont_write_bytecode is true") 866class SourceLoaderBytecodeTests(SourceLoaderTestHarness): 867 868 """Test importlib.abc.SourceLoader's use of bytecode. 869 870 Source-only testing handled by SourceOnlyLoaderTests. 871 872 """ 873 874 def verify_code(self, code_object, *, bytecode_written=False): 875 super().verify_code(code_object) 876 if bytecode_written: 877 self.assertIn(self.cached, self.loader.written) 878 data = bytearray(self.util.MAGIC_NUMBER) 879 data.extend(self.init._w_long(0)) 880 data.extend(self.init._w_long(self.loader.source_mtime)) 881 data.extend(self.init._w_long(self.loader.source_size)) 882 data.extend(marshal.dumps(code_object)) 883 self.assertEqual(self.loader.written[self.cached], bytes(data)) 884 885 def test_code_with_everything(self): 886 # When everything should work. 887 code_object = self.loader.get_code(self.name) 888 self.verify_code(code_object) 889 890 def test_no_bytecode(self): 891 # If no bytecode exists then move on to the source. 892 self.loader.bytecode_path = "<does not exist>" 893 # Sanity check 894 with self.assertRaises(OSError): 895 bytecode_path = self.util.cache_from_source(self.path) 896 self.loader.get_data(bytecode_path) 897 code_object = self.loader.get_code(self.name) 898 self.verify_code(code_object, bytecode_written=True) 899 900 def test_code_bad_timestamp(self): 901 # Bytecode is only used when the timestamp matches the source EXACTLY. 902 for source_mtime in (0, 2): 903 assert source_mtime != self.loader.source_mtime 904 original = self.loader.source_mtime 905 self.loader.source_mtime = source_mtime 906 # If bytecode is used then EOFError would be raised by marshal. 907 self.loader.bytecode = self.loader.bytecode[8:] 908 code_object = self.loader.get_code(self.name) 909 self.verify_code(code_object, bytecode_written=True) 910 self.loader.source_mtime = original 911 912 def test_code_bad_magic(self): 913 # Skip over bytecode with a bad magic number. 914 self.setUp(magic=b'0000') 915 # If bytecode is used then EOFError would be raised by marshal. 916 self.loader.bytecode = self.loader.bytecode[8:] 917 code_object = self.loader.get_code(self.name) 918 self.verify_code(code_object, bytecode_written=True) 919 920 def test_dont_write_bytecode(self): 921 # Bytecode is not written if sys.dont_write_bytecode is true. 922 # Can assume it is false already thanks to the skipIf class decorator. 923 try: 924 sys.dont_write_bytecode = True 925 self.loader.bytecode_path = "<does not exist>" 926 code_object = self.loader.get_code(self.name) 927 self.assertNotIn(self.cached, self.loader.written) 928 finally: 929 sys.dont_write_bytecode = False 930 931 def test_no_set_data(self): 932 # If set_data is not defined, one can still read bytecode. 933 self.setUp(magic=b'0000') 934 original_set_data = self.loader.__class__.mro()[1].set_data 935 try: 936 del self.loader.__class__.mro()[1].set_data 937 code_object = self.loader.get_code(self.name) 938 self.verify_code(code_object) 939 finally: 940 self.loader.__class__.mro()[1].set_data = original_set_data 941 942 def test_set_data_raises_exceptions(self): 943 # Raising NotImplementedError or OSError is okay for set_data. 944 def raise_exception(exc): 945 def closure(*args, **kwargs): 946 raise exc 947 return closure 948 949 self.setUp(magic=b'0000') 950 self.loader.set_data = raise_exception(NotImplementedError) 951 code_object = self.loader.get_code(self.name) 952 self.verify_code(code_object) 953 954 955(Frozen_SLBytecodeTests, 956 SourceSLBytecodeTests 957 ) = test_util.test_both(SourceLoaderBytecodeTests, init=init, util=util, 958 loader_mock=SPLIT_SL) 959 960 961class SourceLoaderGetSourceTests: 962 963 """Tests for importlib.abc.SourceLoader.get_source().""" 964 965 def test_default_encoding(self): 966 # Should have no problems with UTF-8 text. 967 name = 'mod' 968 mock = self.SourceOnlyLoaderMock('mod.file') 969 source = 'x = "ü"' 970 mock.source = source.encode('utf-8') 971 returned_source = mock.get_source(name) 972 self.assertEqual(returned_source, source) 973 974 def test_decoded_source(self): 975 # Decoding should work. 976 name = 'mod' 977 mock = self.SourceOnlyLoaderMock("mod.file") 978 source = "# coding: Latin-1\nx='ü'" 979 assert source.encode('latin-1') != source.encode('utf-8') 980 mock.source = source.encode('latin-1') 981 returned_source = mock.get_source(name) 982 self.assertEqual(returned_source, source) 983 984 def test_universal_newlines(self): 985 # PEP 302 says universal newlines should be used. 986 name = 'mod' 987 mock = self.SourceOnlyLoaderMock('mod.file') 988 source = "x = 42\r\ny = -13\r\n" 989 mock.source = source.encode('utf-8') 990 expect = io.IncrementalNewlineDecoder(None, True).decode(source) 991 self.assertEqual(mock.get_source(name), expect) 992 993 994(Frozen_SourceOnlyLoaderGetSourceTests, 995 Source_SourceOnlyLoaderGetSourceTests 996 ) = test_util.test_both(SourceLoaderGetSourceTests, 997 SourceOnlyLoaderMock=SPLIT_SOL) 998 999 1000if __name__ == '__main__': 1001 unittest.main() 1002