mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 13:41:24 +00:00 
			
		
		
		
	Issue #14605: Use None in sys.path_importer_cache to represent no
finder instead of using some (now non-existent) implicit finder.
This commit is contained in:
		
							parent
							
								
									9e66ac683c
								
							
						
					
					
						commit
						aa93642a35
					
				
					 7 changed files with 1096 additions and 1172 deletions
				
			
		|  | @ -766,17 +766,14 @@ def _path_hooks(cls, path): | |||
|             except ImportError: | ||||
|                 continue | ||||
|         else: | ||||
|             raise ImportError("no path hook found for {0}".format(path), | ||||
|                               path=path) | ||||
|             return None | ||||
| 
 | ||||
|     @classmethod | ||||
|     def _path_importer_cache(cls, path): | ||||
|         """Get the finder for the path from sys.path_importer_cache. | ||||
| 
 | ||||
|         If the path is not in the cache, find the appropriate finder and cache | ||||
|         it. Because of NullImporter, some finder should be returned. The only | ||||
|         explicit fail case is if None is cached but the path cannot be used for | ||||
|         the default hook, for which ImportError is raised. | ||||
|         it. If no finder is available, store None. | ||||
| 
 | ||||
|         """ | ||||
|         if path == '': | ||||
|  | @ -786,15 +783,6 @@ def _path_importer_cache(cls, path): | |||
|         except KeyError: | ||||
|             finder = cls._path_hooks(path) | ||||
|             sys.path_importer_cache[path] = finder | ||||
|         else: | ||||
|             if finder is None: | ||||
|                 msg = ("'None' in sys.path_importer_cache[{!r}], so retrying " | ||||
|                        "finder search; in future versions of Python 'None' " | ||||
|                        "will represent no finder".format(path)) | ||||
|                 _warnings.warn(msg, ImportWarning) | ||||
|                 del sys.path_importer_cache[path] | ||||
|                 finder = cls._path_hooks(path) | ||||
|                 sys.path_importer_cache[path] = finder | ||||
|         return finder | ||||
| 
 | ||||
|     @classmethod | ||||
|  | @ -804,11 +792,8 @@ def find_module(cls, fullname, path=None): | |||
|         if path is None: | ||||
|             path = sys.path | ||||
|         for entry in path: | ||||
|             try: | ||||
|                 finder = cls._path_importer_cache(entry) | ||||
|             except ImportError: | ||||
|                 continue | ||||
|             if finder: | ||||
|             finder = cls._path_importer_cache(entry) | ||||
|             if finder is not None: | ||||
|                 loader = finder.find_module(fullname) | ||||
|                 if loader: | ||||
|                     return loader | ||||
|  | @ -1192,6 +1177,5 @@ def _install(sys_module, _imp_module): | |||
|     supported_loaders = [(ExtensionFileLoader, _suffix_list(3), False), | ||||
|                          (SourceFileLoader, _suffix_list(1), True), | ||||
|                          (SourcelessFileLoader, _suffix_list(2), True)] | ||||
|     sys.path_hooks.extend([FileFinder.path_hook(*supported_loaders), | ||||
|                            _imp.NullImporter]) | ||||
|     sys.path_hooks.extend([FileFinder.path_hook(*supported_loaders)]) | ||||
|     sys.meta_path.extend([BuiltinImporter, FrozenImporter, PathFinder]) | ||||
|  |  | |||
|  | @ -66,36 +66,18 @@ def test_path_hooks(self): | |||
|             self.assertTrue(sys.path_importer_cache[path] is importer) | ||||
| 
 | ||||
|     def test_empty_path_hooks(self): | ||||
|         # Test that if sys.path_hooks is empty a warning is raised and | ||||
|         # PathFinder returns None. | ||||
|         # tried again (with a warning). | ||||
|         # Test that if sys.path_hooks is empty a warning is raised, | ||||
|         # sys.path_importer_cache gets None set, and PathFinder returns None. | ||||
|         path_entry = 'bogus_path' | ||||
|         with util.import_state(path_importer_cache={}, path_hooks=[], | ||||
|                                path=['bogus_path']): | ||||
|                                path=[path_entry]): | ||||
|             with warnings.catch_warnings(record=True) as w: | ||||
|                 warnings.simplefilter('always') | ||||
|                 self.assertIsNone(machinery.PathFinder.find_module('os')) | ||||
|                 self.assertNotIn('os', sys.path_importer_cache) | ||||
|                 self.assertIsNone(sys.path_importer_cache[path_entry]) | ||||
|                 self.assertEqual(len(w), 1) | ||||
|                 self.assertTrue(issubclass(w[-1].category, ImportWarning)) | ||||
| 
 | ||||
|     def test_path_importer_cache_has_None_continues(self): | ||||
|         # Test that having None in sys.path_importer_cache causes the search to | ||||
|         # continue. | ||||
|         path = '<test path>' | ||||
|         module = '<test module>' | ||||
|         importer = util.mock_modules(module) | ||||
|         with util.import_state(path=['1', '2'], | ||||
|                             path_importer_cache={'1': None, '2': importer}, | ||||
|                             path_hooks=[imp.NullImporter]): | ||||
|             with warnings.catch_warnings(record=True) as w: | ||||
|                 warnings.simplefilter('always') | ||||
|                 loader = machinery.PathFinder.find_module(module) | ||||
|                 self.assertTrue(loader is importer) | ||||
|                 self.assertEqual(len(w), 1) | ||||
|                 warned = w[0] | ||||
|                 self.assertTrue(issubclass(warned.category, ImportWarning)) | ||||
|                 self.assertIn(repr(None), str(warned.message)) | ||||
| 
 | ||||
|     def test_path_importer_cache_empty_string(self): | ||||
|         # The empty string should create a finder using the cwd. | ||||
|         path = '' | ||||
|  |  | |||
|  | @ -9,6 +9,7 @@ | |||
| # Written by Nick Coghlan <ncoghlan at gmail.com> | ||||
| #    to implement PEP 338 (Executing Modules as Scripts) | ||||
| 
 | ||||
| 
 | ||||
| import os | ||||
| import sys | ||||
| import imp | ||||
|  | @ -206,11 +207,7 @@ def _get_importer(path_name): | |||
|             except ImportError: | ||||
|                 pass | ||||
|         else: | ||||
|             # The following check looks a bit odd. The trick is that | ||||
|             # NullImporter throws ImportError if the supplied path is a | ||||
|             # *valid* directory entry (and hence able to be handled | ||||
|             # by the standard import machinery) | ||||
|             importer = imp.NullImporter(path_name) | ||||
|             importer = None | ||||
|         cache[path_name] = importer | ||||
|     return importer | ||||
| 
 | ||||
|  | @ -237,7 +234,7 @@ def run_path(path_name, init_globals=None, run_name=None): | |||
|     if run_name is None: | ||||
|         run_name = "<run_path>" | ||||
|     importer = _get_importer(path_name) | ||||
|     if isinstance(importer, imp.NullImporter): | ||||
|     if isinstance(importer, (type(None), imp.NullImporter)): | ||||
|         # Not a valid sys.path entry, so run the code directly | ||||
|         # execfile() doesn't help as we want to allow compiled files | ||||
|         code = _get_code_from_file(path_name) | ||||
|  |  | |||
|  | @ -14,9 +14,9 @@ Core and Builtins | |||
|   sys.meta_path is found to be empty, raise ImportWarning. | ||||
| 
 | ||||
| - Issue #14605: No longer have implicit entries in sys.path_hooks. If | ||||
|   sys.path_hooks is found to be empty, a warning will be raised. If None is | ||||
|   found in sys.path_importer_cache, a warning is raised and a search on | ||||
|   sys.path_hooks is attempted. | ||||
|   sys.path_hooks is found to be empty, a warning will be raised. None is now | ||||
|   inserted into sys.path_importer_cache if no finder was discovered. This also | ||||
|   means imp.NullImporter is no longer implicitly used. | ||||
| 
 | ||||
| - Issue #13903: Implement PEP 412. Individual dictionary instances can now share | ||||
|   their keys with other dictionaries. Classes take advantage of this to share | ||||
|  |  | |||
|  | @ -224,7 +224,7 @@ RunMainFromImporter(wchar_t *filename) | |||
|     if (importer == NULL) | ||||
|         goto error; | ||||
| 
 | ||||
|     if (importer->ob_type == &PyNullImporter_Type) { | ||||
|     if (importer == Py_None) { | ||||
|         Py_DECREF(argv0); | ||||
|         Py_DECREF(importer); | ||||
|         return -1; | ||||
|  |  | |||
|  | @ -1186,15 +1186,7 @@ get_path_importer(PyObject *path_importer_cache, PyObject *path_hooks, | |||
|         PyErr_Clear(); | ||||
|     } | ||||
|     if (importer == NULL) { | ||||
|         importer = PyObject_CallFunctionObjArgs( | ||||
|             (PyObject *)&PyNullImporter_Type, p, NULL | ||||
|         ); | ||||
|         if (importer == NULL) { | ||||
|             if (PyErr_ExceptionMatches(PyExc_ImportError)) { | ||||
|                 PyErr_Clear(); | ||||
|                 return Py_None; | ||||
|             } | ||||
|         } | ||||
|         return Py_None; | ||||
|     } | ||||
|     if (importer != NULL) { | ||||
|         int err = PyDict_SetItem(path_importer_cache, p, importer); | ||||
|  |  | |||
							
								
								
									
										2187
									
								
								Python/importlib.h
									
										
									
									
									
								
							
							
						
						
									
										2187
									
								
								Python/importlib.h
									
										
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Brett Cannon
						Brett Cannon