mirror of
				https://github.com/python/cpython.git
				synced 2025-10-30 21:21:22 +00:00 
			
		
		
		
	gh-130094: Fix race conditions in importlib (gh-130101)
				
					
				
			Entries may be added or removed from `sys.meta_path` concurrently. For example, setuptools temporarily adds and removes the `distutils` finder from the beginning of the list. The local copy ensures that we don't skip over any entries. Some packages modify `sys.modules` during import. For example, `collections` inserts the entry for `collections.abc` into `sys.modules` during import. We need to ensure that we re-check `sys.modules` *after* the parent module is fully initialized.
This commit is contained in:
		
							parent
							
								
									8207454bc0
								
							
						
					
					
						commit
						857bdba0ac
					
				
					 2 changed files with 14 additions and 3 deletions
				
			
		|  | @ -1244,6 +1244,9 @@ def _find_spec(name, path, target=None): | |||
|         raise ImportError("sys.meta_path is None, Python is likely " | ||||
|                           "shutting down") | ||||
| 
 | ||||
|     # gh-130094: Copy sys.meta_path so that we have a consistent view of the | ||||
|     # list while iterating over it. | ||||
|     meta_path = list(meta_path) | ||||
|     if not meta_path: | ||||
|         _warnings.warn('sys.meta_path is empty', ImportWarning) | ||||
| 
 | ||||
|  | @ -1298,7 +1301,6 @@ def _sanity_check(name, package, level): | |||
| 
 | ||||
| 
 | ||||
| _ERR_MSG_PREFIX = 'No module named ' | ||||
| _ERR_MSG = _ERR_MSG_PREFIX + '{!r}' | ||||
| 
 | ||||
| def _find_and_load_unlocked(name, import_): | ||||
|     path = None | ||||
|  | @ -1308,8 +1310,9 @@ def _find_and_load_unlocked(name, import_): | |||
|         if parent not in sys.modules: | ||||
|             _call_with_frames_removed(import_, parent) | ||||
|         # Crazy side-effects! | ||||
|         if name in sys.modules: | ||||
|             return sys.modules[name] | ||||
|         module = sys.modules.get(name) | ||||
|         if module is not None: | ||||
|             return module | ||||
|         parent_module = sys.modules[parent] | ||||
|         try: | ||||
|             path = parent_module.__path__ | ||||
|  | @ -1317,6 +1320,12 @@ def _find_and_load_unlocked(name, import_): | |||
|             msg = f'{_ERR_MSG_PREFIX}{name!r}; {parent!r} is not a package' | ||||
|             raise ModuleNotFoundError(msg, name=name) from None | ||||
|         parent_spec = parent_module.__spec__ | ||||
|         if getattr(parent_spec, '_initializing', False): | ||||
|             _call_with_frames_removed(import_, parent) | ||||
|         # Crazy side-effects (again)! | ||||
|         module = sys.modules.get(name) | ||||
|         if module is not None: | ||||
|             return module | ||||
|         child = name.rpartition('.')[2] | ||||
|     spec = _find_spec(name, path) | ||||
|     if spec is None: | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Sam Gross
						Sam Gross