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') 79 self.assertIsNone(self.find('os')) 80 self.assertIsNone(sys.path_importer_cache[path_entry]) 81 self.assertEqual(len(w), 1) 82 self.assertTrue(issubclass(w[-1].category, ImportWarning)) 83 84 def test_path_importer_cache_empty_string(self): 85 # The empty string should create a finder using the cwd. 86 path = '' 87 module = '<test module>' 88 importer = util.mock_spec(module) 89 hook = util.mock_path_hook(os.getcwd(), importer=importer) 90 with util.import_state(path=[path], path_hooks=[hook]): 91 found = self.find(module) 92 self.check_found(found, importer) 93 self.assertIn(os.getcwd(), sys.path_importer_cache) 94 95 def test_None_on_sys_path(self): 96 # Putting None in sys.path[0] caused an import regression from Python 97 # 3.2: http://bugs.python.org/issue16514 98 new_path = sys.path[:] 99 new_path.insert(0, None) 100 new_path_importer_cache = sys.path_importer_cache.copy() 101 new_path_importer_cache.pop(None, None) 102 new_path_hooks = [zipimport.zipimporter, 103 self.machinery.FileFinder.path_hook( 104 *self.importlib._bootstrap_external._get_supported_file_loaders())] 105 missing = object() 106 email = sys.modules.pop('email', missing) 107 try: 108 with util.import_state(meta_path=sys.meta_path[:], 109 path=new_path, 110 path_importer_cache=new_path_importer_cache, 111 path_hooks=new_path_hooks): 112 module = self.importlib.import_module('email') 113 self.assertIsInstance(module, ModuleType) 114 finally: 115 if email is not missing: 116 sys.modules['email'] = email 117 118 def test_finder_with_find_module(self): 119 class TestFinder: 120 def find_module(self, fullname): 121 return self.to_return 122 failing_finder = TestFinder() 123 failing_finder.to_return = None 124 path = 'testing path' 125 with util.import_state(path_importer_cache={path: failing_finder}): 126 self.assertIsNone( 127 self.machinery.PathFinder.find_spec('whatever', [path])) 128 success_finder = TestFinder() 129 success_finder.to_return = __loader__ 130 with util.import_state(path_importer_cache={path: success_finder}): 131 spec = self.machinery.PathFinder.find_spec('whatever', [path]) 132 self.assertEqual(spec.loader, __loader__) 133 134 def test_finder_with_find_loader(self): 135 class TestFinder: 136 loader = None 137 portions = [] 138 def find_loader(self, fullname): 139 return self.loader, self.portions 140 path = 'testing path' 141 with util.import_state(path_importer_cache={path: TestFinder()}): 142 self.assertIsNone( 143 self.machinery.PathFinder.find_spec('whatever', [path])) 144 success_finder = TestFinder() 145 success_finder.loader = __loader__ 146 with util.import_state(path_importer_cache={path: success_finder}): 147 spec = self.machinery.PathFinder.find_spec('whatever', [path]) 148 self.assertEqual(spec.loader, __loader__) 149 150 def test_finder_with_find_spec(self): 151 class TestFinder: 152 spec = None 153 def find_spec(self, fullname, target=None): 154 return self.spec 155 path = 'testing path' 156 with util.import_state(path_importer_cache={path: TestFinder()}): 157 self.assertIsNone( 158 self.machinery.PathFinder.find_spec('whatever', [path])) 159 success_finder = TestFinder() 160 success_finder.spec = self.machinery.ModuleSpec('whatever', __loader__) 161 with util.import_state(path_importer_cache={path: success_finder}): 162 got = self.machinery.PathFinder.find_spec('whatever', [path]) 163 self.assertEqual(got, success_finder.spec) 164 165 def test_deleted_cwd(self): 166 # Issue #22834 167 old_dir = os.getcwd() 168 self.addCleanup(os.chdir, old_dir) 169 new_dir = tempfile.mkdtemp() 170 try: 171 os.chdir(new_dir) 172 try: 173 os.rmdir(new_dir) 174 except OSError: 175 # EINVAL on Solaris, EBUSY on AIX, ENOTEMPTY on Windows 176 self.skipTest("platform does not allow " 177 "the deletion of the cwd") 178 except: 179 os.chdir(old_dir) 180 os.rmdir(new_dir) 181 raise 182 183 with util.import_state(path=['']): 184 # Do not want FileNotFoundError raised. 185 self.assertIsNone(self.machinery.PathFinder.find_spec('whatever')) 186 187 188class FindModuleTests(FinderTests): 189 def find(self, *args, **kwargs): 190 return self.machinery.PathFinder.find_module(*args, **kwargs) 191 def check_found(self, found, importer): 192 self.assertIs(found, importer) 193 194 195(Frozen_FindModuleTests, 196 Source_FindModuleTests 197) = util.test_both(FindModuleTests, importlib=importlib, machinery=machinery) 198 199 200class FindSpecTests(FinderTests): 201 def find(self, *args, **kwargs): 202 return self.machinery.PathFinder.find_spec(*args, **kwargs) 203 def check_found(self, found, importer): 204 self.assertIs(found.loader, importer) 205 206 207(Frozen_FindSpecTests, 208 Source_FindSpecTests 209 ) = util.test_both(FindSpecTests, importlib=importlib, machinery=machinery) 210 211 212class PathEntryFinderTests: 213 214 def test_finder_with_failing_find_spec(self): 215 # PathEntryFinder with find_module() defined should work. 216 # Issue #20763. 217 class Finder: 218 path_location = 'test_finder_with_find_module' 219 def __init__(self, path): 220 if path != self.path_location: 221 raise ImportError 222 223 @staticmethod 224 def find_module(fullname): 225 return None 226 227 228 with util.import_state(path=[Finder.path_location]+sys.path[:], 229 path_hooks=[Finder]): 230 self.machinery.PathFinder.find_spec('importlib') 231 232 def test_finder_with_failing_find_module(self): 233 # PathEntryFinder with find_module() defined should work. 234 # Issue #20763. 235 class Finder: 236 path_location = 'test_finder_with_find_module' 237 def __init__(self, path): 238 if path != self.path_location: 239 raise ImportError 240 241 @staticmethod 242 def find_module(fullname): 243 return None 244 245 246 with util.import_state(path=[Finder.path_location]+sys.path[:], 247 path_hooks=[Finder]): 248 self.machinery.PathFinder.find_module('importlib') 249 250 251(Frozen_PEFTests, 252 Source_PEFTests 253 ) = util.test_both(PathEntryFinderTests, machinery=machinery) 254 255 256if __name__ == '__main__': 257 unittest.main() 258