1  from test.test_importlib import util
       2  
       3  importlib = util.import_importlib('importlib')
       4  machinery = util.import_importlib('importlib.machinery')
       5  
       6  import os
       7  import sys
       8  import tempfile
       9  from types import ModuleType
      10  import unittest
      11  import warnings
      12  import zipimport
      13  
      14  
      15  class ESC[4;38;5;81mFinderTests:
      16  
      17      """Tests for PathFinder."""
      18  
      19      find = None
      20      check_found = None
      21  
      22      def test_failure(self):
      23          # Test None returned upon not finding a suitable loader.
      24          module = '<test module>'
      25          with util.import_state():
      26              self.assertIsNone(self.find(module))
      27  
      28      def test_sys_path(self):
      29          # Test that sys.path is used when 'path' is None.
      30          # Implicitly tests that sys.path_importer_cache is used.
      31          module = '<test module>'
      32          path = '<test path>'
      33          importer = util.mock_spec(module)
      34          with util.import_state(path_importer_cache={path: importer},
      35                                 path=[path]):
      36              found = self.find(module)
      37              self.check_found(found, importer)
      38  
      39      def test_path(self):
      40          # Test that 'path' is used when set.
      41          # Implicitly tests that sys.path_importer_cache is used.
      42          module = '<test module>'
      43          path = '<test path>'
      44          importer = util.mock_spec(module)
      45          with util.import_state(path_importer_cache={path: importer}):
      46              found = self.find(module, [path])
      47              self.check_found(found, importer)
      48  
      49      def test_empty_list(self):
      50          # An empty list should not count as asking for sys.path.
      51          module = 'module'
      52          path = '<test path>'
      53          importer = util.mock_spec(module)
      54          with util.import_state(path_importer_cache={path: importer},
      55                                 path=[path]):
      56              self.assertIsNone(self.find('module', []))
      57  
      58      def test_path_hooks(self):
      59          # Test that sys.path_hooks is used.
      60          # Test that sys.path_importer_cache is set.
      61          module = '<test module>'
      62          path = '<test path>'
      63          importer = util.mock_spec(module)
      64          hook = util.mock_path_hook(path, importer=importer)
      65          with util.import_state(path_hooks=[hook]):
      66              found = self.find(module, [path])
      67              self.check_found(found, importer)
      68              self.assertIn(path, sys.path_importer_cache)
      69              self.assertIs(sys.path_importer_cache[path], importer)
      70  
      71      def test_empty_path_hooks(self):
      72          # Test that if sys.path_hooks is empty a warning is raised,
      73          # sys.path_importer_cache gets None set, and PathFinder returns None.
      74          path_entry = 'bogus_path'
      75          with util.import_state(path_importer_cache={}, path_hooks=[],
      76                                 path=[path_entry]):
      77              with warnings.catch_warnings(record=True) as w:
      78                  warnings.simplefilter('always', ImportWarning)
      79                  warnings.simplefilter('ignore', DeprecationWarning)
      80                  self.assertIsNone(self.find('os'))
      81                  self.assertIsNone(sys.path_importer_cache[path_entry])
      82                  self.assertEqual(len(w), 1)
      83                  self.assertTrue(issubclass(w[-1].category, ImportWarning))
      84  
      85      def test_path_importer_cache_empty_string(self):
      86          # The empty string should create a finder using the cwd.
      87          path = ''
      88          module = '<test module>'
      89          importer = util.mock_spec(module)
      90          hook = util.mock_path_hook(os.getcwd(), importer=importer)
      91          with util.import_state(path=[path], path_hooks=[hook]):
      92              found = self.find(module)
      93              self.check_found(found, importer)
      94              self.assertIn(os.getcwd(), sys.path_importer_cache)
      95  
      96      def test_None_on_sys_path(self):
      97          # Putting None in sys.path[0] caused an import regression from Python
      98          # 3.2: http://bugs.python.org/issue16514
      99          new_path = sys.path[:]
     100          new_path.insert(0, None)
     101          new_path_importer_cache = sys.path_importer_cache.copy()
     102          new_path_importer_cache.pop(None, None)
     103          new_path_hooks = [zipimport.zipimporter,
     104                            self.machinery.FileFinder.path_hook(
     105                                *self.importlib._bootstrap_external._get_supported_file_loaders())]
     106          missing = object()
     107          email = sys.modules.pop('email', missing)
     108          try:
     109              with util.import_state(meta_path=sys.meta_path[:],
     110                                     path=new_path,
     111                                     path_importer_cache=new_path_importer_cache,
     112                                     path_hooks=new_path_hooks):
     113                  module = self.importlib.import_module('email')
     114                  self.assertIsInstance(module, ModuleType)
     115          finally:
     116              if email is not missing:
     117                  sys.modules['email'] = email
     118  
     119      def test_finder_with_find_spec(self):
     120          class ESC[4;38;5;81mTestFinder:
     121              spec = None
     122              def find_spec(self, fullname, target=None):
     123                  return self.spec
     124          path = 'testing path'
     125          with util.import_state(path_importer_cache={path: TestFinder()}):
     126              self.assertIsNone(
     127                      self.machinery.PathFinder.find_spec('whatever', [path]))
     128          success_finder = TestFinder()
     129          success_finder.spec = self.machinery.ModuleSpec('whatever', __loader__)
     130          with util.import_state(path_importer_cache={path: success_finder}):
     131              got = self.machinery.PathFinder.find_spec('whatever', [path])
     132          self.assertEqual(got, success_finder.spec)
     133  
     134      def test_deleted_cwd(self):
     135          # Issue #22834
     136          old_dir = os.getcwd()
     137          self.addCleanup(os.chdir, old_dir)
     138          new_dir = tempfile.mkdtemp()
     139          try:
     140              os.chdir(new_dir)
     141              try:
     142                  os.rmdir(new_dir)
     143              except OSError:
     144                  # EINVAL on Solaris, EBUSY on AIX, ENOTEMPTY on Windows
     145                  self.skipTest("platform does not allow "
     146                                "the deletion of the cwd")
     147          except:
     148              os.chdir(old_dir)
     149              os.rmdir(new_dir)
     150              raise
     151  
     152          with util.import_state(path=['']):
     153              # Do not want FileNotFoundError raised.
     154              self.assertIsNone(self.machinery.PathFinder.find_spec('whatever'))
     155  
     156      def test_invalidate_caches_finders(self):
     157          # Finders with an invalidate_caches() method have it called.
     158          class ESC[4;38;5;81mFakeFinder:
     159              def __init__(self):
     160                  self.called = False
     161  
     162              def invalidate_caches(self):
     163                  self.called = True
     164  
     165          key = os.path.abspath('finder_to_invalidate')
     166          cache = {'leave_alone': object(), key: FakeFinder()}
     167          with util.import_state(path_importer_cache=cache):
     168              self.machinery.PathFinder.invalidate_caches()
     169          self.assertTrue(cache[key].called)
     170  
     171      def test_invalidate_caches_clear_out_None(self):
     172          # Clear out None in sys.path_importer_cache() when invalidating caches.
     173          cache = {'clear_out': None}
     174          with util.import_state(path_importer_cache=cache):
     175              self.machinery.PathFinder.invalidate_caches()
     176          self.assertEqual(len(cache), 0)
     177  
     178      def test_invalidate_caches_clear_out_relative_path(self):
     179          class ESC[4;38;5;81mFakeFinder:
     180              def invalidate_caches(self):
     181                  pass
     182  
     183          cache = {'relative_path': FakeFinder()}
     184          with util.import_state(path_importer_cache=cache):
     185              self.machinery.PathFinder.invalidate_caches()
     186          self.assertEqual(cache, {})
     187  
     188  
     189  class ESC[4;38;5;81mFindModuleTests(ESC[4;38;5;149mFinderTests):
     190      def find(self, *args, **kwargs):
     191          spec = self.machinery.PathFinder.find_spec(*args, **kwargs)
     192          return None if spec is None else spec.loader
     193  
     194      def check_found(self, found, importer):
     195          self.assertIs(found, importer)
     196  
     197  
     198  (Frozen_FindModuleTests,
     199   Source_FindModuleTests
     200  ) = util.test_both(FindModuleTests, importlib=importlib, machinery=machinery)
     201  
     202  
     203  class ESC[4;38;5;81mFindSpecTests(ESC[4;38;5;149mFinderTests):
     204      def find(self, *args, **kwargs):
     205          return self.machinery.PathFinder.find_spec(*args, **kwargs)
     206      def check_found(self, found, importer):
     207          self.assertIs(found.loader, importer)
     208  
     209  
     210  (Frozen_FindSpecTests,
     211   Source_FindSpecTests
     212   ) = util.test_both(FindSpecTests, importlib=importlib, machinery=machinery)
     213  
     214  
     215  class ESC[4;38;5;81mPathEntryFinderTests:
     216  
     217      def test_finder_with_failing_find_spec(self):
     218          class ESC[4;38;5;81mFinder:
     219              path_location = 'test_finder_with_find_spec'
     220              def __init__(self, path):
     221                  if path != self.path_location:
     222                      raise ImportError
     223  
     224              @staticmethod
     225              def find_spec(fullname, target=None):
     226                  return None
     227  
     228  
     229          with util.import_state(path=[Finder.path_location]+sys.path[:],
     230                                 path_hooks=[Finder]):
     231              with warnings.catch_warnings():
     232                  warnings.simplefilter("ignore", ImportWarning)
     233                  self.machinery.PathFinder.find_spec('importlib')
     234  
     235  
     236  (Frozen_PEFTests,
     237   Source_PEFTests
     238   ) = util.test_both(PathEntryFinderTests, machinery=machinery)
     239  
     240  
     241  if __name__ == '__main__':
     242      unittest.main()