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_find_module(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 368 def test_find_spec_with_explicit_target(self): 369 loader = object() 370 spec = self.util.spec_from_loader('blah', loader) 371 finder = self.finder(spec) 372 found = finder.find_spec('blah', 'blah', None) 373 self.assertEqual(found, spec) 374 375 def test_no_spec(self): 376 finder = self.finder(None) 377 path = ['a', 'b', 'c'] 378 name = 'blah' 379 found = finder.find_spec(name, path, None) 380 self.assertIsNone(found) 381 self.assertEqual(name, finder.called_for[0]) 382 self.assertEqual(path, finder.called_for[1]) 383 384 def test_spec(self): 385 loader = object() 386 spec = self.util.spec_from_loader('blah', loader) 387 finder = self.finder(spec) 388 found = finder.find_spec('blah', None) 389 self.assertIs(found, spec) 390 391 392(Frozen_MPFFindModuleTests, 393 Source_MPFFindModuleTests 394 ) = test_util.test_both(MetaPathFinderFindModuleTests, abc=abc, util=util) 395 396 397##### PathEntryFinder concrete methods ######################################### 398class PathEntryFinderFindLoaderTests: 399 400 @classmethod 401 def finder(cls, spec): 402 class PathEntrySpecFinder(cls.abc.PathEntryFinder): 403 404 def find_spec(self, fullname, target=None): 405 self.called_for = fullname 406 return spec 407 408 return PathEntrySpecFinder() 409 410 def test_no_spec(self): 411 finder = self.finder(None) 412 name = 'blah' 413 with self.assertWarns(DeprecationWarning): 414 found = finder.find_loader(name) 415 self.assertIsNone(found[0]) 416 self.assertEqual([], found[1]) 417 self.assertEqual(name, finder.called_for) 418 419 def test_spec_with_loader(self): 420 loader = object() 421 spec = self.util.spec_from_loader('blah', loader) 422 finder = self.finder(spec) 423 with self.assertWarns(DeprecationWarning): 424 found = finder.find_loader('blah') 425 self.assertIs(found[0], spec.loader) 426 427 def test_spec_with_portions(self): 428 spec = self.machinery.ModuleSpec('blah', None) 429 paths = ['a', 'b', 'c'] 430 spec.submodule_search_locations = paths 431 finder = self.finder(spec) 432 with self.assertWarns(DeprecationWarning): 433 found = finder.find_loader('blah') 434 self.assertIsNone(found[0]) 435 self.assertEqual(paths, found[1]) 436 437 438(Frozen_PEFFindLoaderTests, 439 Source_PEFFindLoaderTests 440 ) = test_util.test_both(PathEntryFinderFindLoaderTests, abc=abc, util=util, 441 machinery=machinery) 442 443 444##### Loader concrete methods ################################################## 445class LoaderLoadModuleTests: 446 447 def loader(self): 448 class SpecLoader(self.abc.Loader): 449 found = None 450 def exec_module(self, module): 451 self.found = module 452 453 def is_package(self, fullname): 454 """Force some non-default module state to be set.""" 455 return True 456 457 return SpecLoader() 458 459 def test_fresh(self): 460 loader = self.loader() 461 name = 'blah' 462 with test_util.uncache(name): 463 loader.load_module(name) 464 module = loader.found 465 self.assertIs(sys.modules[name], module) 466 self.assertEqual(loader, module.__loader__) 467 self.assertEqual(loader, module.__spec__.loader) 468 self.assertEqual(name, module.__name__) 469 self.assertEqual(name, module.__spec__.name) 470 self.assertIsNotNone(module.__path__) 471 self.assertIsNotNone(module.__path__, 472 module.__spec__.submodule_search_locations) 473 474 def test_reload(self): 475 name = 'blah' 476 loader = self.loader() 477 module = types.ModuleType(name) 478 module.__spec__ = self.util.spec_from_loader(name, loader) 479 module.__loader__ = loader 480 with test_util.uncache(name): 481 sys.modules[name] = module 482 loader.load_module(name) 483 found = loader.found 484 self.assertIs(found, sys.modules[name]) 485 self.assertIs(module, sys.modules[name]) 486 487 488(Frozen_LoaderLoadModuleTests, 489 Source_LoaderLoadModuleTests 490 ) = test_util.test_both(LoaderLoadModuleTests, abc=abc, util=util) 491 492 493##### InspectLoader concrete methods ########################################### 494class InspectLoaderSourceToCodeTests: 495 496 def source_to_module(self, data, path=None): 497 """Help with source_to_code() tests.""" 498 module = types.ModuleType('blah') 499 loader = self.InspectLoaderSubclass() 500 if path is None: 501 code = loader.source_to_code(data) 502 else: 503 code = loader.source_to_code(data, path) 504 exec(code, module.__dict__) 505 return module 506 507 def test_source_to_code_source(self): 508 # Since compile() can handle strings, so should source_to_code(). 509 source = 'attr = 42' 510 module = self.source_to_module(source) 511 self.assertTrue(hasattr(module, 'attr')) 512 self.assertEqual(module.attr, 42) 513 514 def test_source_to_code_bytes(self): 515 # Since compile() can handle bytes, so should source_to_code(). 516 source = b'attr = 42' 517 module = self.source_to_module(source) 518 self.assertTrue(hasattr(module, 'attr')) 519 self.assertEqual(module.attr, 42) 520 521 def test_source_to_code_path(self): 522 # Specifying a path should set it for the code object. 523 path = 'path/to/somewhere' 524 loader = self.InspectLoaderSubclass() 525 code = loader.source_to_code('', path) 526 self.assertEqual(code.co_filename, path) 527 528 def test_source_to_code_no_path(self): 529 # Not setting a path should still work and be set to <string> since that 530 # is a pre-existing practice as a default to compile(). 531 loader = self.InspectLoaderSubclass() 532 code = loader.source_to_code('') 533 self.assertEqual(code.co_filename, '<string>') 534 535 536(Frozen_ILSourceToCodeTests, 537 Source_ILSourceToCodeTests 538 ) = test_util.test_both(InspectLoaderSourceToCodeTests, 539 InspectLoaderSubclass=SPLIT_IL) 540 541 542class InspectLoaderGetCodeTests: 543 544 def test_get_code(self): 545 # Test success. 546 module = types.ModuleType('blah') 547 with mock.patch.object(self.InspectLoaderSubclass, 'get_source') as mocked: 548 mocked.return_value = 'attr = 42' 549 loader = self.InspectLoaderSubclass() 550 code = loader.get_code('blah') 551 exec(code, module.__dict__) 552 self.assertEqual(module.attr, 42) 553 554 def test_get_code_source_is_None(self): 555 # If get_source() is None then this should be None. 556 with mock.patch.object(self.InspectLoaderSubclass, 'get_source') as mocked: 557 mocked.return_value = None 558 loader = self.InspectLoaderSubclass() 559 code = loader.get_code('blah') 560 self.assertIsNone(code) 561 562 def test_get_code_source_not_found(self): 563 # If there is no source then there is no code object. 564 loader = self.InspectLoaderSubclass() 565 with self.assertRaises(ImportError): 566 loader.get_code('blah') 567 568 569(Frozen_ILGetCodeTests, 570 Source_ILGetCodeTests 571 ) = test_util.test_both(InspectLoaderGetCodeTests, 572 InspectLoaderSubclass=SPLIT_IL) 573 574 575class InspectLoaderLoadModuleTests: 576 577 """Test InspectLoader.load_module().""" 578 579 module_name = 'blah' 580 581 def setUp(self): 582 support.unload(self.module_name) 583 self.addCleanup(support.unload, self.module_name) 584 585 def load(self, loader): 586 spec = self.util.spec_from_loader(self.module_name, loader) 587 with warnings.catch_warnings(): 588 warnings.simplefilter('ignore', DeprecationWarning) 589 return self.init._bootstrap._load_unlocked(spec) 590 591 def mock_get_code(self): 592 return mock.patch.object(self.InspectLoaderSubclass, 'get_code') 593 594 def test_get_code_ImportError(self): 595 # If get_code() raises ImportError, it should propagate. 596 with self.mock_get_code() as mocked_get_code: 597 mocked_get_code.side_effect = ImportError 598 with self.assertRaises(ImportError): 599 loader = self.InspectLoaderSubclass() 600 self.load(loader) 601 602 def test_get_code_None(self): 603 # If get_code() returns None, raise ImportError. 604 with self.mock_get_code() as mocked_get_code: 605 mocked_get_code.return_value = None 606 with self.assertRaises(ImportError): 607 loader = self.InspectLoaderSubclass() 608 self.load(loader) 609 610 def test_module_returned(self): 611 # The loaded module should be returned. 612 code = compile('attr = 42', '<string>', 'exec') 613 with self.mock_get_code() as mocked_get_code: 614 mocked_get_code.return_value = code 615 loader = self.InspectLoaderSubclass() 616 module = self.load(loader) 617 self.assertEqual(module, sys.modules[self.module_name]) 618 619 620(Frozen_ILLoadModuleTests, 621 Source_ILLoadModuleTests 622 ) = test_util.test_both(InspectLoaderLoadModuleTests, 623 InspectLoaderSubclass=SPLIT_IL, 624 init=init, 625 util=util) 626 627 628##### ExecutionLoader concrete methods ######################################### 629class ExecutionLoaderGetCodeTests: 630 631 def mock_methods(self, *, get_source=False, get_filename=False): 632 source_mock_context, filename_mock_context = None, None 633 if get_source: 634 source_mock_context = mock.patch.object(self.ExecutionLoaderSubclass, 635 'get_source') 636 if get_filename: 637 filename_mock_context = mock.patch.object(self.ExecutionLoaderSubclass, 638 'get_filename') 639 return source_mock_context, filename_mock_context 640 641 def test_get_code(self): 642 path = 'blah.py' 643 source_mock_context, filename_mock_context = self.mock_methods( 644 get_source=True, get_filename=True) 645 with source_mock_context as source_mock, filename_mock_context as name_mock: 646 source_mock.return_value = 'attr = 42' 647 name_mock.return_value = path 648 loader = self.ExecutionLoaderSubclass() 649 code = loader.get_code('blah') 650 self.assertEqual(code.co_filename, path) 651 module = types.ModuleType('blah') 652 exec(code, module.__dict__) 653 self.assertEqual(module.attr, 42) 654 655 def test_get_code_source_is_None(self): 656 # If get_source() is None then this should be None. 657 source_mock_context, _ = self.mock_methods(get_source=True) 658 with source_mock_context as mocked: 659 mocked.return_value = None 660 loader = self.ExecutionLoaderSubclass() 661 code = loader.get_code('blah') 662 self.assertIsNone(code) 663 664 def test_get_code_source_not_found(self): 665 # If there is no source then there is no code object. 666 loader = self.ExecutionLoaderSubclass() 667 with self.assertRaises(ImportError): 668 loader.get_code('blah') 669 670 def test_get_code_no_path(self): 671 # If get_filename() raises ImportError then simply skip setting the path 672 # on the code object. 673 source_mock_context, filename_mock_context = self.mock_methods( 674 get_source=True, get_filename=True) 675 with source_mock_context as source_mock, filename_mock_context as name_mock: 676 source_mock.return_value = 'attr = 42' 677 name_mock.side_effect = ImportError 678 loader = self.ExecutionLoaderSubclass() 679 code = loader.get_code('blah') 680 self.assertEqual(code.co_filename, '<string>') 681 module = types.ModuleType('blah') 682 exec(code, module.__dict__) 683 self.assertEqual(module.attr, 42) 684 685 686(Frozen_ELGetCodeTests, 687 Source_ELGetCodeTests 688 ) = test_util.test_both(ExecutionLoaderGetCodeTests, 689 ExecutionLoaderSubclass=SPLIT_EL) 690 691 692##### SourceLoader concrete methods ############################################ 693class SourceOnlyLoader: 694 695 # Globals that should be defined for all modules. 696 source = (b"_ = '::'.join([__name__, __file__, __cached__, __package__, " 697 b"repr(__loader__)])") 698 699 def __init__(self, path): 700 self.path = path 701 702 def get_data(self, path): 703 if path != self.path: 704 raise IOError 705 return self.source 706 707 def get_filename(self, fullname): 708 return self.path 709 710 def module_repr(self, module): 711 return '<module>' 712 713 714SPLIT_SOL = make_abc_subclasses(SourceOnlyLoader, 'SourceLoader') 715 716 717class SourceLoader(SourceOnlyLoader): 718 719 source_mtime = 1 720 721 def __init__(self, path, magic=None): 722 super().__init__(path) 723 self.bytecode_path = self.util.cache_from_source(self.path) 724 self.source_size = len(self.source) 725 if magic is None: 726 magic = self.util.MAGIC_NUMBER 727 data = bytearray(magic) 728 data.extend(self.init._pack_uint32(0)) 729 data.extend(self.init._pack_uint32(self.source_mtime)) 730 data.extend(self.init._pack_uint32(self.source_size)) 731 code_object = compile(self.source, self.path, 'exec', 732 dont_inherit=True) 733 data.extend(marshal.dumps(code_object)) 734 self.bytecode = bytes(data) 735 self.written = {} 736 737 def get_data(self, path): 738 if path == self.path: 739 return super().get_data(path) 740 elif path == self.bytecode_path: 741 return self.bytecode 742 else: 743 raise OSError 744 745 def path_stats(self, path): 746 if path != self.path: 747 raise IOError 748 return {'mtime': self.source_mtime, 'size': self.source_size} 749 750 def set_data(self, path, data): 751 self.written[path] = bytes(data) 752 return path == self.bytecode_path 753 754 755SPLIT_SL = make_abc_subclasses(SourceLoader, util=util, init=init) 756 757 758class SourceLoaderTestHarness: 759 760 def setUp(self, *, is_package=True, **kwargs): 761 self.package = 'pkg' 762 if is_package: 763 self.path = os.path.join(self.package, '__init__.py') 764 self.name = self.package 765 else: 766 module_name = 'mod' 767 self.path = os.path.join(self.package, '.'.join(['mod', 'py'])) 768 self.name = '.'.join([self.package, module_name]) 769 self.cached = self.util.cache_from_source(self.path) 770 self.loader = self.loader_mock(self.path, **kwargs) 771 772 def verify_module(self, module): 773 self.assertEqual(module.__name__, self.name) 774 self.assertEqual(module.__file__, self.path) 775 self.assertEqual(module.__cached__, self.cached) 776 self.assertEqual(module.__package__, self.package) 777 self.assertEqual(module.__loader__, self.loader) 778 values = module._.split('::') 779 self.assertEqual(values[0], self.name) 780 self.assertEqual(values[1], self.path) 781 self.assertEqual(values[2], self.cached) 782 self.assertEqual(values[3], self.package) 783 self.assertEqual(values[4], repr(self.loader)) 784 785 def verify_code(self, code_object): 786 module = types.ModuleType(self.name) 787 module.__file__ = self.path 788 module.__cached__ = self.cached 789 module.__package__ = self.package 790 module.__loader__ = self.loader 791 module.__path__ = [] 792 exec(code_object, module.__dict__) 793 self.verify_module(module) 794 795 796class SourceOnlyLoaderTests(SourceLoaderTestHarness): 797 798 """Test importlib.abc.SourceLoader for source-only loading. 799 800 Reload testing is subsumed by the tests for 801 importlib.util.module_for_loader. 802 803 """ 804 805 def test_get_source(self): 806 # Verify the source code is returned as a string. 807 # If an OSError is raised by get_data then raise ImportError. 808 expected_source = self.loader.source.decode('utf-8') 809 self.assertEqual(self.loader.get_source(self.name), expected_source) 810 def raise_OSError(path): 811 raise OSError 812 self.loader.get_data = raise_OSError 813 with self.assertRaises(ImportError) as cm: 814 self.loader.get_source(self.name) 815 self.assertEqual(cm.exception.name, self.name) 816 817 def test_is_package(self): 818 # Properly detect when loading a package. 819 self.setUp(is_package=False) 820 self.assertFalse(self.loader.is_package(self.name)) 821 self.setUp(is_package=True) 822 self.assertTrue(self.loader.is_package(self.name)) 823 self.assertFalse(self.loader.is_package(self.name + '.__init__')) 824 825 def test_get_code(self): 826 # Verify the code object is created. 827 code_object = self.loader.get_code(self.name) 828 self.verify_code(code_object) 829 830 def test_source_to_code(self): 831 # Verify the compiled code object. 832 code = self.loader.source_to_code(self.loader.source, self.path) 833 self.verify_code(code) 834 835 def test_load_module(self): 836 # Loading a module should set __name__, __loader__, __package__, 837 # __path__ (for packages), __file__, and __cached__. 838 # The module should also be put into sys.modules. 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.assertEqual(module.__path__, [os.path.dirname(self.path)]) 845 self.assertIn(self.name, sys.modules) 846 847 def test_package_settings(self): 848 # __package__ needs to be set, while __path__ is set on if the module 849 # is a package. 850 # Testing the values for a package are covered by test_load_module. 851 self.setUp(is_package=False) 852 with test_util.uncache(self.name): 853 with warnings.catch_warnings(): 854 warnings.simplefilter('ignore', DeprecationWarning) 855 module = self.loader.load_module(self.name) 856 self.verify_module(module) 857 self.assertFalse(hasattr(module, '__path__')) 858 859 def test_get_source_encoding(self): 860 # Source is considered encoded in UTF-8 by default unless otherwise 861 # specified by an encoding line. 862 source = "_ = 'ü'" 863 self.loader.source = source.encode('utf-8') 864 returned_source = self.loader.get_source(self.name) 865 self.assertEqual(returned_source, source) 866 source = "# coding: latin-1\n_ = ü" 867 self.loader.source = source.encode('latin-1') 868 returned_source = self.loader.get_source(self.name) 869 self.assertEqual(returned_source, source) 870 871 872(Frozen_SourceOnlyLoaderTests, 873 Source_SourceOnlyLoaderTests 874 ) = test_util.test_both(SourceOnlyLoaderTests, util=util, 875 loader_mock=SPLIT_SOL) 876 877 878@unittest.skipIf(sys.dont_write_bytecode, "sys.dont_write_bytecode is true") 879class SourceLoaderBytecodeTests(SourceLoaderTestHarness): 880 881 """Test importlib.abc.SourceLoader's use of bytecode. 882 883 Source-only testing handled by SourceOnlyLoaderTests. 884 885 """ 886 887 def verify_code(self, code_object, *, bytecode_written=False): 888 super().verify_code(code_object) 889 if bytecode_written: 890 self.assertIn(self.cached, self.loader.written) 891 data = bytearray(self.util.MAGIC_NUMBER) 892 data.extend(self.init._pack_uint32(0)) 893 data.extend(self.init._pack_uint32(self.loader.source_mtime)) 894 data.extend(self.init._pack_uint32(self.loader.source_size)) 895 data.extend(marshal.dumps(code_object)) 896 self.assertEqual(self.loader.written[self.cached], bytes(data)) 897 898 def test_code_with_everything(self): 899 # When everything should work. 900 code_object = self.loader.get_code(self.name) 901 self.verify_code(code_object) 902 903 def test_no_bytecode(self): 904 # If no bytecode exists then move on to the source. 905 self.loader.bytecode_path = "<does not exist>" 906 # Sanity check 907 with self.assertRaises(OSError): 908 bytecode_path = self.util.cache_from_source(self.path) 909 self.loader.get_data(bytecode_path) 910 code_object = self.loader.get_code(self.name) 911 self.verify_code(code_object, bytecode_written=True) 912 913 def test_code_bad_timestamp(self): 914 # Bytecode is only used when the timestamp matches the source EXACTLY. 915 for source_mtime in (0, 2): 916 assert source_mtime != self.loader.source_mtime 917 original = self.loader.source_mtime 918 self.loader.source_mtime = source_mtime 919 # If bytecode is used then EOFError would be raised by marshal. 920 self.loader.bytecode = self.loader.bytecode[8:] 921 code_object = self.loader.get_code(self.name) 922 self.verify_code(code_object, bytecode_written=True) 923 self.loader.source_mtime = original 924 925 def test_code_bad_magic(self): 926 # Skip over bytecode with a bad magic number. 927 self.setUp(magic=b'0000') 928 # If bytecode is used then EOFError would be raised by marshal. 929 self.loader.bytecode = self.loader.bytecode[8:] 930 code_object = self.loader.get_code(self.name) 931 self.verify_code(code_object, bytecode_written=True) 932 933 def test_dont_write_bytecode(self): 934 # Bytecode is not written if sys.dont_write_bytecode is true. 935 # Can assume it is false already thanks to the skipIf class decorator. 936 try: 937 sys.dont_write_bytecode = True 938 self.loader.bytecode_path = "<does not exist>" 939 code_object = self.loader.get_code(self.name) 940 self.assertNotIn(self.cached, self.loader.written) 941 finally: 942 sys.dont_write_bytecode = False 943 944 def test_no_set_data(self): 945 # If set_data is not defined, one can still read bytecode. 946 self.setUp(magic=b'0000') 947 original_set_data = self.loader.__class__.mro()[1].set_data 948 try: 949 del self.loader.__class__.mro()[1].set_data 950 code_object = self.loader.get_code(self.name) 951 self.verify_code(code_object) 952 finally: 953 self.loader.__class__.mro()[1].set_data = original_set_data 954 955 def test_set_data_raises_exceptions(self): 956 # Raising NotImplementedError or OSError is okay for set_data. 957 def raise_exception(exc): 958 def closure(*args, **kwargs): 959 raise exc 960 return closure 961 962 self.setUp(magic=b'0000') 963 self.loader.set_data = raise_exception(NotImplementedError) 964 code_object = self.loader.get_code(self.name) 965 self.verify_code(code_object) 966 967 968(Frozen_SLBytecodeTests, 969 SourceSLBytecodeTests 970 ) = test_util.test_both(SourceLoaderBytecodeTests, init=init, util=util, 971 loader_mock=SPLIT_SL) 972 973 974class SourceLoaderGetSourceTests: 975 976 """Tests for importlib.abc.SourceLoader.get_source().""" 977 978 def test_default_encoding(self): 979 # Should have no problems with UTF-8 text. 980 name = 'mod' 981 mock = self.SourceOnlyLoaderMock('mod.file') 982 source = 'x = "ü"' 983 mock.source = source.encode('utf-8') 984 returned_source = mock.get_source(name) 985 self.assertEqual(returned_source, source) 986 987 def test_decoded_source(self): 988 # Decoding should work. 989 name = 'mod' 990 mock = self.SourceOnlyLoaderMock("mod.file") 991 source = "# coding: Latin-1\nx='ü'" 992 assert source.encode('latin-1') != source.encode('utf-8') 993 mock.source = source.encode('latin-1') 994 returned_source = mock.get_source(name) 995 self.assertEqual(returned_source, source) 996 997 def test_universal_newlines(self): 998 # PEP 302 says universal newlines should be used. 999 name = 'mod' 1000 mock = self.SourceOnlyLoaderMock('mod.file') 1001 source = "x = 42\r\ny = -13\r\n" 1002 mock.source = source.encode('utf-8') 1003 expect = io.IncrementalNewlineDecoder(None, True).decode(source) 1004 self.assertEqual(mock.get_source(name), expect) 1005 1006 1007(Frozen_SourceOnlyLoaderGetSourceTests, 1008 Source_SourceOnlyLoaderGetSourceTests 1009 ) = test_util.test_both(SourceLoaderGetSourceTests, 1010 SourceOnlyLoaderMock=SPLIT_SOL) 1011 1012 1013if __name__ == '__main__': 1014 unittest.main() 1015