(root)/
Python-3.11.7/
Lib/
test/
test_importlib/
source/
test_finder.py
       1  from test.test_importlib import abc, util
       2  
       3  machinery = util.import_importlib('importlib.machinery')
       4  
       5  import errno
       6  import os
       7  import py_compile
       8  import stat
       9  import sys
      10  import tempfile
      11  from test.support.import_helper import make_legacy_pyc
      12  import unittest
      13  import warnings
      14  
      15  
      16  class ESC[4;38;5;81mFinderTests(ESC[4;38;5;149mabcESC[4;38;5;149m.ESC[4;38;5;149mFinderTests):
      17  
      18      """For a top-level module, it should just be found directly in the
      19      directory being searched. This is true for a directory with source
      20      [top-level source], bytecode [top-level bc], or both [top-level both].
      21      There is also the possibility that it is a package [top-level package], in
      22      which case there will be a directory with the module name and an
      23      __init__.py file. If there is a directory without an __init__.py an
      24      ImportWarning is returned [empty dir].
      25  
      26      For sub-modules and sub-packages, the same happens as above but only use
      27      the tail end of the name [sub module] [sub package] [sub empty].
      28  
      29      When there is a conflict between a package and module having the same name
      30      in the same directory, the package wins out [package over module]. This is
      31      so that imports of modules within the package can occur rather than trigger
      32      an import error.
      33  
      34      When there is a package and module with the same name, always pick the
      35      package over the module [package over module]. This is so that imports from
      36      the package have the possibility of succeeding.
      37  
      38      """
      39  
      40      def get_finder(self, root):
      41          loader_details = [(self.machinery.SourceFileLoader,
      42                              self.machinery.SOURCE_SUFFIXES),
      43                            (self.machinery.SourcelessFileLoader,
      44                              self.machinery.BYTECODE_SUFFIXES)]
      45          return self.machinery.FileFinder(root, *loader_details)
      46  
      47      def import_(self, root, module):
      48          finder = self.get_finder(root)
      49          return self._find(finder, module, loader_only=True)
      50  
      51      def run_test(self, test, create=None, *, compile_=None, unlink=None):
      52          """Test the finding of 'test' with the creation of modules listed in
      53          'create'.
      54  
      55          Any names listed in 'compile_' are byte-compiled. Modules
      56          listed in 'unlink' have their source files deleted.
      57  
      58          """
      59          if create is None:
      60              create = {test}
      61          with util.create_modules(*create) as mapping:
      62              if compile_:
      63                  for name in compile_:
      64                      py_compile.compile(mapping[name])
      65              if unlink:
      66                  for name in unlink:
      67                      os.unlink(mapping[name])
      68                      try:
      69                          make_legacy_pyc(mapping[name])
      70                      except OSError as error:
      71                          # Some tests do not set compile_=True so the source
      72                          # module will not get compiled and there will be no
      73                          # PEP 3147 pyc file to rename.
      74                          if error.errno != errno.ENOENT:
      75                              raise
      76              loader = self.import_(mapping['.root'], test)
      77              self.assertTrue(hasattr(loader, 'load_module'))
      78              return loader
      79  
      80      def test_module(self):
      81          # [top-level source]
      82          self.run_test('top_level')
      83          # [top-level bc]
      84          self.run_test('top_level', compile_={'top_level'},
      85                        unlink={'top_level'})
      86          # [top-level both]
      87          self.run_test('top_level', compile_={'top_level'})
      88  
      89      # [top-level package]
      90      def test_package(self):
      91          # Source.
      92          self.run_test('pkg', {'pkg.__init__'})
      93          # Bytecode.
      94          self.run_test('pkg', {'pkg.__init__'}, compile_={'pkg.__init__'},
      95                  unlink={'pkg.__init__'})
      96          # Both.
      97          self.run_test('pkg', {'pkg.__init__'}, compile_={'pkg.__init__'})
      98  
      99      # [sub module]
     100      def test_module_in_package(self):
     101          with util.create_modules('pkg.__init__', 'pkg.sub') as mapping:
     102              pkg_dir = os.path.dirname(mapping['pkg.__init__'])
     103              loader = self.import_(pkg_dir, 'pkg.sub')
     104              self.assertTrue(hasattr(loader, 'load_module'))
     105  
     106      # [sub package]
     107      def test_package_in_package(self):
     108          context = util.create_modules('pkg.__init__', 'pkg.sub.__init__')
     109          with context as mapping:
     110              pkg_dir = os.path.dirname(mapping['pkg.__init__'])
     111              loader = self.import_(pkg_dir, 'pkg.sub')
     112              self.assertTrue(hasattr(loader, 'load_module'))
     113  
     114      # [package over modules]
     115      def test_package_over_module(self):
     116          name = '_temp'
     117          loader = self.run_test(name, {'{0}.__init__'.format(name), name})
     118          self.assertIn('__init__', loader.get_filename(name))
     119  
     120      def test_failure(self):
     121          with util.create_modules('blah') as mapping:
     122              nothing = self.import_(mapping['.root'], 'sdfsadsadf')
     123              self.assertIsNone(nothing)
     124  
     125      def test_empty_string_for_dir(self):
     126          # The empty string from sys.path means to search in the cwd.
     127          finder = self.machinery.FileFinder('', (self.machinery.SourceFileLoader,
     128              self.machinery.SOURCE_SUFFIXES))
     129          with open('mod.py', 'w', encoding='utf-8') as file:
     130              file.write("# test file for importlib")
     131          try:
     132              loader = self._find(finder, 'mod', loader_only=True)
     133              self.assertTrue(hasattr(loader, 'load_module'))
     134          finally:
     135              os.unlink('mod.py')
     136  
     137      def test_invalidate_caches(self):
     138          # invalidate_caches() should reset the mtime.
     139          finder = self.machinery.FileFinder('', (self.machinery.SourceFileLoader,
     140              self.machinery.SOURCE_SUFFIXES))
     141          finder._path_mtime = 42
     142          finder.invalidate_caches()
     143          self.assertEqual(finder._path_mtime, -1)
     144  
     145      # Regression test for http://bugs.python.org/issue14846
     146      def test_dir_removal_handling(self):
     147          mod = 'mod'
     148          with util.create_modules(mod) as mapping:
     149              finder = self.get_finder(mapping['.root'])
     150              found = self._find(finder, 'mod', loader_only=True)
     151              self.assertIsNotNone(found)
     152          found = self._find(finder, 'mod', loader_only=True)
     153          self.assertIsNone(found)
     154  
     155      @unittest.skipUnless(sys.platform != 'win32',
     156              'os.chmod() does not support the needed arguments under Windows')
     157      def test_no_read_directory(self):
     158          # Issue #16730
     159          tempdir = tempfile.TemporaryDirectory()
     160          self.enterContext(tempdir)
     161          # Since we muck with the permissions, we want to set them back to
     162          # their original values to make sure the directory can be properly
     163          # cleaned up.
     164          original_mode = os.stat(tempdir.name).st_mode
     165          self.addCleanup(os.chmod, tempdir.name, original_mode)
     166          os.chmod(tempdir.name, stat.S_IWUSR | stat.S_IXUSR)
     167          finder = self.get_finder(tempdir.name)
     168          found = self._find(finder, 'doesnotexist')
     169          self.assertEqual(found, self.NOT_FOUND)
     170  
     171      def test_ignore_file(self):
     172          # If a directory got changed to a file from underneath us, then don't
     173          # worry about looking for submodules.
     174          with tempfile.NamedTemporaryFile() as file_obj:
     175              finder = self.get_finder(file_obj.name)
     176              found = self._find(finder, 'doesnotexist')
     177              self.assertEqual(found, self.NOT_FOUND)
     178  
     179  
     180  class ESC[4;38;5;81mFinderTestsPEP451(ESC[4;38;5;149mFinderTests):
     181  
     182      NOT_FOUND = None
     183  
     184      def _find(self, finder, name, loader_only=False):
     185          spec = finder.find_spec(name)
     186          return spec.loader if spec is not None else spec
     187  
     188  
     189  (Frozen_FinderTestsPEP451,
     190   Source_FinderTestsPEP451
     191   ) = util.test_both(FinderTestsPEP451, machinery=machinery)
     192  
     193  
     194  class ESC[4;38;5;81mFinderTestsPEP420(ESC[4;38;5;149mFinderTests):
     195  
     196      NOT_FOUND = (None, [])
     197  
     198      def _find(self, finder, name, loader_only=False):
     199          with warnings.catch_warnings():
     200              warnings.simplefilter("ignore", DeprecationWarning)
     201              loader_portions = finder.find_loader(name)
     202              return loader_portions[0] if loader_only else loader_portions
     203  
     204  
     205  (Frozen_FinderTestsPEP420,
     206   Source_FinderTestsPEP420
     207   ) = util.test_both(FinderTestsPEP420, machinery=machinery)
     208  
     209  
     210  class ESC[4;38;5;81mFinderTestsPEP302(ESC[4;38;5;149mFinderTests):
     211  
     212      NOT_FOUND = None
     213  
     214      def _find(self, finder, name, loader_only=False):
     215          with warnings.catch_warnings():
     216              warnings.simplefilter("ignore", DeprecationWarning)
     217              return finder.find_module(name)
     218  
     219  
     220  (Frozen_FinderTestsPEP302,
     221   Source_FinderTestsPEP302
     222   ) = util.test_both(FinderTestsPEP302, machinery=machinery)
     223  
     224  
     225  if __name__ == '__main__':
     226      unittest.main()