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