python (3.12.0)

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