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