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