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