1from .. import util 2 3importlib = util.import_importlib('importlib') 4machinery = util.import_importlib('importlib.machinery') 5 6import os 7import sys 8import tempfile 9from types import ModuleType 10import unittest 11import warnings 12import zipimport 13 14 15class FinderTests: 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_module(self): 120 class TestFinder: 121 def find_module(self, fullname): 122 return self.to_return 123 failing_finder = TestFinder() 124 failing_finder.to_return = None 125 path = 'testing path' 126 with util.import_state(path_importer_cache={path: failing_finder}): 127 with warnings.catch_warnings(): 128 warnings.simplefilter("ignore", ImportWarning) 129 self.assertIsNone( 130 self.machinery.PathFinder.find_spec('whatever', [path])) 131 success_finder = TestFinder() 132 success_finder.to_return = __loader__ 133 with util.import_state(path_importer_cache={path: success_finder}): 134 with warnings.catch_warnings(): 135 warnings.simplefilter("ignore", ImportWarning) 136 spec = self.machinery.PathFinder.find_spec('whatever', [path]) 137 self.assertEqual(spec.loader, __loader__) 138 139 def test_finder_with_find_loader(self): 140 class TestFinder: 141 loader = None 142 portions = [] 143 def find_loader(self, fullname): 144 return self.loader, self.portions 145 path = 'testing path' 146 with util.import_state(path_importer_cache={path: TestFinder()}): 147 with warnings.catch_warnings(): 148 warnings.simplefilter("ignore", ImportWarning) 149 self.assertIsNone( 150 self.machinery.PathFinder.find_spec('whatever', [path])) 151 success_finder = TestFinder() 152 success_finder.loader = __loader__ 153 with util.import_state(path_importer_cache={path: success_finder}): 154 with warnings.catch_warnings(): 155 warnings.simplefilter("ignore", ImportWarning) 156 spec = self.machinery.PathFinder.find_spec('whatever', [path]) 157 self.assertEqual(spec.loader, __loader__) 158 159 def test_finder_with_find_spec(self): 160 class TestFinder: 161 spec = None 162 def find_spec(self, fullname, target=None): 163 return self.spec 164 path = 'testing path' 165 with util.import_state(path_importer_cache={path: TestFinder()}): 166 self.assertIsNone( 167 self.machinery.PathFinder.find_spec('whatever', [path])) 168 success_finder = TestFinder() 169 success_finder.spec = self.machinery.ModuleSpec('whatever', __loader__) 170 with util.import_state(path_importer_cache={path: success_finder}): 171 got = self.machinery.PathFinder.find_spec('whatever', [path]) 172 self.assertEqual(got, success_finder.spec) 173 174 def test_deleted_cwd(self): 175 # Issue #22834 176 old_dir = os.getcwd() 177 self.addCleanup(os.chdir, old_dir) 178 new_dir = tempfile.mkdtemp() 179 try: 180 os.chdir(new_dir) 181 try: 182 os.rmdir(new_dir) 183 except OSError: 184 # EINVAL on Solaris, EBUSY on AIX, ENOTEMPTY on Windows 185 self.skipTest("platform does not allow " 186 "the deletion of the cwd") 187 except: 188 os.chdir(old_dir) 189 os.rmdir(new_dir) 190 raise 191 192 with util.import_state(path=['']): 193 # Do not want FileNotFoundError raised. 194 self.assertIsNone(self.machinery.PathFinder.find_spec('whatever')) 195 196 def test_invalidate_caches_finders(self): 197 # Finders with an invalidate_caches() method have it called. 198 class FakeFinder: 199 def __init__(self): 200 self.called = False 201 202 def invalidate_caches(self): 203 self.called = True 204 205 cache = {'leave_alone': object(), 'finder_to_invalidate': FakeFinder()} 206 with util.import_state(path_importer_cache=cache): 207 self.machinery.PathFinder.invalidate_caches() 208 self.assertTrue(cache['finder_to_invalidate'].called) 209 210 def test_invalidate_caches_clear_out_None(self): 211 # Clear out None in sys.path_importer_cache() when invalidating caches. 212 cache = {'clear_out': None} 213 with util.import_state(path_importer_cache=cache): 214 self.machinery.PathFinder.invalidate_caches() 215 self.assertEqual(len(cache), 0) 216 217 218class FindModuleTests(FinderTests): 219 def find(self, *args, **kwargs): 220 with warnings.catch_warnings(): 221 warnings.simplefilter("ignore", DeprecationWarning) 222 return self.machinery.PathFinder.find_module(*args, **kwargs) 223 def check_found(self, found, importer): 224 self.assertIs(found, importer) 225 226 227(Frozen_FindModuleTests, 228 Source_FindModuleTests 229) = util.test_both(FindModuleTests, importlib=importlib, machinery=machinery) 230 231 232class FindSpecTests(FinderTests): 233 def find(self, *args, **kwargs): 234 return self.machinery.PathFinder.find_spec(*args, **kwargs) 235 def check_found(self, found, importer): 236 self.assertIs(found.loader, importer) 237 238 239(Frozen_FindSpecTests, 240 Source_FindSpecTests 241 ) = util.test_both(FindSpecTests, importlib=importlib, machinery=machinery) 242 243 244class PathEntryFinderTests: 245 246 def test_finder_with_failing_find_spec(self): 247 # PathEntryFinder with find_module() defined should work. 248 # Issue #20763. 249 class Finder: 250 path_location = 'test_finder_with_find_module' 251 def __init__(self, path): 252 if path != self.path_location: 253 raise ImportError 254 255 @staticmethod 256 def find_module(fullname): 257 return None 258 259 260 with util.import_state(path=[Finder.path_location]+sys.path[:], 261 path_hooks=[Finder]): 262 with warnings.catch_warnings(): 263 warnings.simplefilter("ignore", ImportWarning) 264 self.machinery.PathFinder.find_spec('importlib') 265 266 def test_finder_with_failing_find_module(self): 267 # PathEntryFinder with find_module() defined should work. 268 # Issue #20763. 269 class Finder: 270 path_location = 'test_finder_with_find_module' 271 def __init__(self, path): 272 if path != self.path_location: 273 raise ImportError 274 275 @staticmethod 276 def find_module(fullname): 277 return None 278 279 280 with util.import_state(path=[Finder.path_location]+sys.path[:], 281 path_hooks=[Finder]): 282 with warnings.catch_warnings(): 283 warnings.simplefilter("ignore", ImportWarning) 284 warnings.simplefilter("ignore", DeprecationWarning) 285 self.machinery.PathFinder.find_module('importlib') 286 287 288(Frozen_PEFTests, 289 Source_PEFTests 290 ) = util.test_both(PathEntryFinderTests, machinery=machinery) 291 292 293if __name__ == '__main__': 294 unittest.main() 295