(root)/
Python-3.12.0/
Lib/
test/
test_importlib/
test_api.py
       1  from test.test_importlib import util as test_util
       2  
       3  init = test_util.import_importlib('importlib')
       4  util = test_util.import_importlib('importlib.util')
       5  machinery = test_util.import_importlib('importlib.machinery')
       6  
       7  import os.path
       8  import sys
       9  from test.support import import_helper
      10  from test.support import os_helper
      11  import types
      12  import unittest
      13  import warnings
      14  
      15  
      16  class ESC[4;38;5;81mImportModuleTests:
      17  
      18      """Test importlib.import_module."""
      19  
      20      def test_module_import(self):
      21          # Test importing a top-level module.
      22          with test_util.mock_spec('top_level') as mock:
      23              with test_util.import_state(meta_path=[mock]):
      24                  module = self.init.import_module('top_level')
      25                  self.assertEqual(module.__name__, 'top_level')
      26  
      27      def test_absolute_package_import(self):
      28          # Test importing a module from a package with an absolute name.
      29          pkg_name = 'pkg'
      30          pkg_long_name = '{0}.__init__'.format(pkg_name)
      31          name = '{0}.mod'.format(pkg_name)
      32          with test_util.mock_spec(pkg_long_name, name) as mock:
      33              with test_util.import_state(meta_path=[mock]):
      34                  module = self.init.import_module(name)
      35                  self.assertEqual(module.__name__, name)
      36  
      37      def test_shallow_relative_package_import(self):
      38          # Test importing a module from a package through a relative import.
      39          pkg_name = 'pkg'
      40          pkg_long_name = '{0}.__init__'.format(pkg_name)
      41          module_name = 'mod'
      42          absolute_name = '{0}.{1}'.format(pkg_name, module_name)
      43          relative_name = '.{0}'.format(module_name)
      44          with test_util.mock_spec(pkg_long_name, absolute_name) as mock:
      45              with test_util.import_state(meta_path=[mock]):
      46                  self.init.import_module(pkg_name)
      47                  module = self.init.import_module(relative_name, pkg_name)
      48                  self.assertEqual(module.__name__, absolute_name)
      49  
      50      def test_deep_relative_package_import(self):
      51          modules = ['a.__init__', 'a.b.__init__', 'a.c']
      52          with test_util.mock_spec(*modules) as mock:
      53              with test_util.import_state(meta_path=[mock]):
      54                  self.init.import_module('a')
      55                  self.init.import_module('a.b')
      56                  module = self.init.import_module('..c', 'a.b')
      57                  self.assertEqual(module.__name__, 'a.c')
      58  
      59      def test_absolute_import_with_package(self):
      60          # Test importing a module from a package with an absolute name with
      61          # the 'package' argument given.
      62          pkg_name = 'pkg'
      63          pkg_long_name = '{0}.__init__'.format(pkg_name)
      64          name = '{0}.mod'.format(pkg_name)
      65          with test_util.mock_spec(pkg_long_name, name) as mock:
      66              with test_util.import_state(meta_path=[mock]):
      67                  self.init.import_module(pkg_name)
      68                  module = self.init.import_module(name, pkg_name)
      69                  self.assertEqual(module.__name__, name)
      70  
      71      def test_relative_import_wo_package(self):
      72          # Relative imports cannot happen without the 'package' argument being
      73          # set.
      74          with self.assertRaises(TypeError):
      75              self.init.import_module('.support')
      76  
      77  
      78      def test_loaded_once(self):
      79          # Issue #13591: Modules should only be loaded once when
      80          # initializing the parent package attempts to import the
      81          # module currently being imported.
      82          b_load_count = 0
      83          def load_a():
      84              self.init.import_module('a.b')
      85          def load_b():
      86              nonlocal b_load_count
      87              b_load_count += 1
      88          code = {'a': load_a, 'a.b': load_b}
      89          modules = ['a.__init__', 'a.b']
      90          with test_util.mock_spec(*modules, module_code=code) as mock:
      91              with test_util.import_state(meta_path=[mock]):
      92                  self.init.import_module('a.b')
      93          self.assertEqual(b_load_count, 1)
      94  
      95  
      96  (Frozen_ImportModuleTests,
      97   Source_ImportModuleTests
      98   ) = test_util.test_both(
      99       ImportModuleTests, init=init, util=util, machinery=machinery)
     100  
     101  
     102  class ESC[4;38;5;81mFindLoaderTests:
     103  
     104      FakeMetaFinder = None
     105  
     106      def test_sys_modules(self):
     107          # If a module with __spec__.loader is in sys.modules, then return it.
     108          name = 'some_mod'
     109          with test_util.uncache(name):
     110              module = types.ModuleType(name)
     111              loader = 'a loader!'
     112              module.__spec__ = self.machinery.ModuleSpec(name, loader)
     113              sys.modules[name] = module
     114              spec = self.util.find_spec(name)
     115              self.assertIsNotNone(spec)
     116              self.assertEqual(spec.loader, loader)
     117  
     118      def test_sys_modules_loader_is_None(self):
     119          # If sys.modules[name].__spec__.loader is None, raise ValueError.
     120          name = 'some_mod'
     121          with test_util.uncache(name):
     122              module = types.ModuleType(name)
     123              module.__loader__ = None
     124              sys.modules[name] = module
     125              with self.assertRaises(ValueError):
     126                  self.util.find_spec(name)
     127  
     128      def test_sys_modules_loader_is_not_set(self):
     129          # Should raise ValueError
     130          # Issue #17099
     131          name = 'some_mod'
     132          with test_util.uncache(name):
     133              module = types.ModuleType(name)
     134              try:
     135                  del module.__spec__.loader
     136              except AttributeError:
     137                  pass
     138              sys.modules[name] = module
     139              with self.assertRaises(ValueError):
     140                  self.util.find_spec(name)
     141  
     142      def test_success(self):
     143          # Return the loader found on sys.meta_path.
     144          name = 'some_mod'
     145          with test_util.uncache(name):
     146              with test_util.import_state(meta_path=[self.FakeMetaFinder]):
     147                  spec = self.util.find_spec(name)
     148                  self.assertEqual((name, (name, None)), (spec.name, spec.loader))
     149  
     150      def test_success_path(self):
     151          # Searching on a path should work.
     152          name = 'some_mod'
     153          path = 'path to some place'
     154          with test_util.uncache(name):
     155              with test_util.import_state(meta_path=[self.FakeMetaFinder]):
     156                  spec = self.util.find_spec(name, path)
     157                  self.assertEqual(name, spec.name)
     158  
     159      def test_nothing(self):
     160          # None is returned upon failure to find a loader.
     161          self.assertIsNone(self.util.find_spec('nevergoingtofindthismodule'))
     162  
     163  
     164  class ESC[4;38;5;81mFindLoaderPEP451Tests(ESC[4;38;5;149mFindLoaderTests):
     165  
     166      class ESC[4;38;5;81mFakeMetaFinder:
     167          @staticmethod
     168          def find_spec(name, path=None, target=None):
     169              return machinery['Source'].ModuleSpec(name, (name, path))
     170  
     171  
     172  (Frozen_FindLoaderPEP451Tests,
     173   Source_FindLoaderPEP451Tests
     174   ) = test_util.test_both(
     175       FindLoaderPEP451Tests, init=init, util=util, machinery=machinery)
     176  
     177  
     178  class ESC[4;38;5;81mReloadTests:
     179  
     180      def test_reload_modules(self):
     181          for mod in ('tokenize', 'time', 'marshal'):
     182              with self.subTest(module=mod):
     183                  with import_helper.CleanImport(mod):
     184                      module = self.init.import_module(mod)
     185                      self.init.reload(module)
     186  
     187      def test_module_replaced(self):
     188          def code():
     189              import sys
     190              module = type(sys)('top_level')
     191              module.spam = 3
     192              sys.modules['top_level'] = module
     193          mock = test_util.mock_spec('top_level',
     194                                     module_code={'top_level': code})
     195          with mock:
     196              with test_util.import_state(meta_path=[mock]):
     197                  module = self.init.import_module('top_level')
     198                  reloaded = self.init.reload(module)
     199                  actual = sys.modules['top_level']
     200                  self.assertEqual(actual.spam, 3)
     201                  self.assertEqual(reloaded.spam, 3)
     202  
     203      def test_reload_missing_loader(self):
     204          with import_helper.CleanImport('types'):
     205              import types
     206              loader = types.__loader__
     207              del types.__loader__
     208              reloaded = self.init.reload(types)
     209  
     210              self.assertIs(reloaded, types)
     211              self.assertIs(sys.modules['types'], types)
     212              self.assertEqual(reloaded.__loader__.path, loader.path)
     213  
     214      def test_reload_loader_replaced(self):
     215          with import_helper.CleanImport('types'):
     216              import types
     217              types.__loader__ = None
     218              self.init.invalidate_caches()
     219              reloaded = self.init.reload(types)
     220  
     221              self.assertIsNot(reloaded.__loader__, None)
     222              self.assertIs(reloaded, types)
     223              self.assertIs(sys.modules['types'], types)
     224  
     225      def test_reload_location_changed(self):
     226          name = 'spam'
     227          with os_helper.temp_cwd(None) as cwd:
     228              with test_util.uncache('spam'):
     229                  with import_helper.DirsOnSysPath(cwd):
     230                      # Start as a plain module.
     231                      self.init.invalidate_caches()
     232                      path = os.path.join(cwd, name + '.py')
     233                      cached = self.util.cache_from_source(path)
     234                      expected = {'__name__': name,
     235                                  '__package__': '',
     236                                  '__file__': path,
     237                                  '__cached__': cached,
     238                                  '__doc__': None,
     239                                  }
     240                      os_helper.create_empty_file(path)
     241                      module = self.init.import_module(name)
     242                      ns = vars(module).copy()
     243                      loader = ns.pop('__loader__')
     244                      spec = ns.pop('__spec__')
     245                      ns.pop('__builtins__', None)  # An implementation detail.
     246                      self.assertEqual(spec.name, name)
     247                      self.assertEqual(spec.loader, loader)
     248                      self.assertEqual(loader.path, path)
     249                      self.assertEqual(ns, expected)
     250  
     251                      # Change to a package.
     252                      self.init.invalidate_caches()
     253                      init_path = os.path.join(cwd, name, '__init__.py')
     254                      cached = self.util.cache_from_source(init_path)
     255                      expected = {'__name__': name,
     256                                  '__package__': name,
     257                                  '__file__': init_path,
     258                                  '__cached__': cached,
     259                                  '__path__': [os.path.dirname(init_path)],
     260                                  '__doc__': None,
     261                                  }
     262                      os.mkdir(name)
     263                      os.rename(path, init_path)
     264                      reloaded = self.init.reload(module)
     265                      ns = vars(reloaded).copy()
     266                      loader = ns.pop('__loader__')
     267                      spec = ns.pop('__spec__')
     268                      ns.pop('__builtins__', None)  # An implementation detail.
     269                      self.assertEqual(spec.name, name)
     270                      self.assertEqual(spec.loader, loader)
     271                      self.assertIs(reloaded, module)
     272                      self.assertEqual(loader.path, init_path)
     273                      self.maxDiff = None
     274                      self.assertEqual(ns, expected)
     275  
     276      def test_reload_namespace_changed(self):
     277          name = 'spam'
     278          with os_helper.temp_cwd(None) as cwd:
     279              with test_util.uncache('spam'):
     280                  with test_util.import_state(path=[cwd]):
     281                      self.init._bootstrap_external._install(self.init._bootstrap)
     282                      # Start as a namespace package.
     283                      self.init.invalidate_caches()
     284                      bad_path = os.path.join(cwd, name, '__init.py')
     285                      cached = self.util.cache_from_source(bad_path)
     286                      expected = {'__name__': name,
     287                                  '__package__': name,
     288                                  '__doc__': None,
     289                                  '__file__': None,
     290                                  }
     291                      os.mkdir(name)
     292                      with open(bad_path, 'w', encoding='utf-8') as init_file:
     293                          init_file.write('eggs = None')
     294                      module = self.init.import_module(name)
     295                      ns = vars(module).copy()
     296                      loader = ns.pop('__loader__')
     297                      path = ns.pop('__path__')
     298                      spec = ns.pop('__spec__')
     299                      ns.pop('__builtins__', None)  # An implementation detail.
     300                      self.assertEqual(spec.name, name)
     301                      self.assertIsNotNone(spec.loader)
     302                      self.assertIsNotNone(loader)
     303                      self.assertEqual(spec.loader, loader)
     304                      self.assertEqual(set(path),
     305                                       set([os.path.dirname(bad_path)]))
     306                      with self.assertRaises(AttributeError):
     307                          # a NamespaceLoader
     308                          loader.path
     309                      self.assertEqual(ns, expected)
     310  
     311                      # Change to a regular package.
     312                      self.init.invalidate_caches()
     313                      init_path = os.path.join(cwd, name, '__init__.py')
     314                      cached = self.util.cache_from_source(init_path)
     315                      expected = {'__name__': name,
     316                                  '__package__': name,
     317                                  '__file__': init_path,
     318                                  '__cached__': cached,
     319                                  '__path__': [os.path.dirname(init_path)],
     320                                  '__doc__': None,
     321                                  'eggs': None,
     322                                  }
     323                      os.rename(bad_path, init_path)
     324                      reloaded = self.init.reload(module)
     325                      ns = vars(reloaded).copy()
     326                      loader = ns.pop('__loader__')
     327                      spec = ns.pop('__spec__')
     328                      ns.pop('__builtins__', None)  # An implementation detail.
     329                      self.assertEqual(spec.name, name)
     330                      self.assertEqual(spec.loader, loader)
     331                      self.assertIs(reloaded, module)
     332                      self.assertEqual(loader.path, init_path)
     333                      self.assertEqual(ns, expected)
     334  
     335      def test_reload_submodule(self):
     336          # See #19851.
     337          name = 'spam'
     338          subname = 'ham'
     339          with test_util.temp_module(name, pkg=True) as pkg_dir:
     340              fullname, _ = test_util.submodule(name, subname, pkg_dir)
     341              ham = self.init.import_module(fullname)
     342              reloaded = self.init.reload(ham)
     343              self.assertIs(reloaded, ham)
     344  
     345      def test_module_missing_spec(self):
     346          #Test that reload() throws ModuleNotFounderror when reloading
     347          # a module whose missing a spec. (bpo-29851)
     348          name = 'spam'
     349          with test_util.uncache(name):
     350              module = sys.modules[name] = types.ModuleType(name)
     351              # Sanity check by attempting an import.
     352              module = self.init.import_module(name)
     353              self.assertIsNone(module.__spec__)
     354              with self.assertRaises(ModuleNotFoundError):
     355                  self.init.reload(module)
     356  
     357  
     358  (Frozen_ReloadTests,
     359   Source_ReloadTests
     360   ) = test_util.test_both(
     361       ReloadTests, init=init, util=util, machinery=machinery)
     362  
     363  
     364  class ESC[4;38;5;81mInvalidateCacheTests:
     365  
     366      def test_method_called(self):
     367          # If defined the method should be called.
     368          class ESC[4;38;5;81mInvalidatingNullFinder:
     369              def __init__(self, *ignored):
     370                  self.called = False
     371              def invalidate_caches(self):
     372                  self.called = True
     373  
     374          key = os.path.abspath('gobledeegook')
     375          meta_ins = InvalidatingNullFinder()
     376          path_ins = InvalidatingNullFinder()
     377          sys.meta_path.insert(0, meta_ins)
     378          self.addCleanup(lambda: sys.path_importer_cache.__delitem__(key))
     379          sys.path_importer_cache[key] = path_ins
     380          self.addCleanup(lambda: sys.meta_path.remove(meta_ins))
     381          self.init.invalidate_caches()
     382          self.assertTrue(meta_ins.called)
     383          self.assertTrue(path_ins.called)
     384  
     385      def test_method_lacking(self):
     386          # There should be no issues if the method is not defined.
     387          key = 'gobbledeegook'
     388          sys.path_importer_cache[key] = None
     389          self.addCleanup(lambda: sys.path_importer_cache.pop(key, None))
     390          self.init.invalidate_caches()  # Shouldn't trigger an exception.
     391  
     392  
     393  (Frozen_InvalidateCacheTests,
     394   Source_InvalidateCacheTests
     395   ) = test_util.test_both(
     396       InvalidateCacheTests, init=init, util=util, machinery=machinery)
     397  
     398  
     399  class ESC[4;38;5;81mFrozenImportlibTests(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
     400  
     401      def test_no_frozen_importlib(self):
     402          # Should be able to import w/o _frozen_importlib being defined.
     403          # Can't do an isinstance() check since separate copies of importlib
     404          # may have been used for import, so just check the name is not for the
     405          # frozen loader.
     406          source_init = init['Source']
     407          self.assertNotEqual(source_init.__loader__.__class__.__name__,
     408                              'FrozenImporter')
     409  
     410  
     411  class ESC[4;38;5;81mStartupTests:
     412  
     413      def test_everyone_has___loader__(self):
     414          # Issue #17098: all modules should have __loader__ defined.
     415          for name, module in sys.modules.items():
     416              if isinstance(module, types.ModuleType):
     417                  with self.subTest(name=name):
     418                      self.assertTrue(hasattr(module, '__loader__'),
     419                                      '{!r} lacks a __loader__ attribute'.format(name))
     420                      if self.machinery.BuiltinImporter.find_spec(name):
     421                          self.assertIsNot(module.__loader__, None)
     422                      elif self.machinery.FrozenImporter.find_spec(name):
     423                          self.assertIsNot(module.__loader__, None)
     424  
     425      def test_everyone_has___spec__(self):
     426          for name, module in sys.modules.items():
     427              if isinstance(module, types.ModuleType):
     428                  with self.subTest(name=name):
     429                      self.assertTrue(hasattr(module, '__spec__'))
     430                      if self.machinery.BuiltinImporter.find_spec(name):
     431                          self.assertIsNot(module.__spec__, None)
     432                      elif self.machinery.FrozenImporter.find_spec(name):
     433                          self.assertIsNot(module.__spec__, None)
     434  
     435  
     436  (Frozen_StartupTests,
     437   Source_StartupTests
     438   ) = test_util.test_both(StartupTests, machinery=machinery)
     439  
     440  
     441  if __name__ == '__main__':
     442      unittest.main()