mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 05:31:20 +00:00 
			
		
		
		
	[3.13] gh-123930: Better error for "from imports" when script shadows module (GH-123929) (#125937)
gh-123930: Better error for "from imports" when script shadows module (#123929)
(cherry picked from commit 500f5338a8)
			
			
This commit is contained in:
		
							parent
							
								
									4b55d53316
								
							
						
					
					
						commit
						3d8b6f0977
					
				
					 6 changed files with 344 additions and 171 deletions
				
			
		
							
								
								
									
										150
									
								
								Python/ceval.c
									
										
									
									
									
								
							
							
						
						
									
										150
									
								
								Python/ceval.c
									
										
									
									
									
								
							|  | @ -2708,7 +2708,7 @@ static PyObject * | |||
| import_from(PyThreadState *tstate, PyObject *v, PyObject *name) | ||||
| { | ||||
|     PyObject *x; | ||||
|     PyObject *fullmodname, *pkgname, *pkgpath, *pkgname_or_unknown, *errmsg; | ||||
|     PyObject *fullmodname, *mod_name, *origin, *mod_name_or_unknown, *errmsg, *spec; | ||||
| 
 | ||||
|     if (PyObject_GetOptionalAttr(v, name, &x) != 0) { | ||||
|         return x; | ||||
|  | @ -2716,16 +2716,16 @@ import_from(PyThreadState *tstate, PyObject *v, PyObject *name) | |||
|     /* Issue #17636: in case this failed because of a circular relative
 | ||||
|        import, try to fallback on reading the module directly from | ||||
|        sys.modules. */ | ||||
|     if (PyObject_GetOptionalAttr(v, &_Py_ID(__name__), &pkgname) < 0) { | ||||
|     if (PyObject_GetOptionalAttr(v, &_Py_ID(__name__), &mod_name) < 0) { | ||||
|         return NULL; | ||||
|     } | ||||
|     if (pkgname == NULL || !PyUnicode_Check(pkgname)) { | ||||
|         Py_CLEAR(pkgname); | ||||
|     if (mod_name == NULL || !PyUnicode_Check(mod_name)) { | ||||
|         Py_CLEAR(mod_name); | ||||
|         goto error; | ||||
|     } | ||||
|     fullmodname = PyUnicode_FromFormat("%U.%U", pkgname, name); | ||||
|     fullmodname = PyUnicode_FromFormat("%U.%U", mod_name, name); | ||||
|     if (fullmodname == NULL) { | ||||
|         Py_DECREF(pkgname); | ||||
|         Py_DECREF(mod_name); | ||||
|         return NULL; | ||||
|     } | ||||
|     x = PyImport_GetModule(fullmodname); | ||||
|  | @ -2733,63 +2733,121 @@ import_from(PyThreadState *tstate, PyObject *v, PyObject *name) | |||
|     if (x == NULL && !_PyErr_Occurred(tstate)) { | ||||
|         goto error; | ||||
|     } | ||||
|     Py_DECREF(pkgname); | ||||
|     Py_DECREF(mod_name); | ||||
|     return x; | ||||
| 
 | ||||
|  error: | ||||
|     if (pkgname == NULL) { | ||||
|         pkgname_or_unknown = PyUnicode_FromString("<unknown module name>"); | ||||
|         if (pkgname_or_unknown == NULL) { | ||||
|     if (mod_name == NULL) { | ||||
|         mod_name_or_unknown = PyUnicode_FromString("<unknown module name>"); | ||||
|         if (mod_name_or_unknown == NULL) { | ||||
|             return NULL; | ||||
|         } | ||||
|     } else { | ||||
|         pkgname_or_unknown = pkgname; | ||||
|         mod_name_or_unknown = mod_name; | ||||
|     } | ||||
|     // mod_name is no longer an owned reference
 | ||||
|     assert(mod_name_or_unknown); | ||||
|     assert(mod_name == NULL || mod_name == mod_name_or_unknown); | ||||
| 
 | ||||
|     pkgpath = NULL; | ||||
|     if (PyModule_Check(v)) { | ||||
|         pkgpath = PyModule_GetFilenameObject(v); | ||||
|         if (pkgpath == NULL) { | ||||
|             if (!PyErr_ExceptionMatches(PyExc_SystemError)) { | ||||
|                 Py_DECREF(pkgname_or_unknown); | ||||
|                 return NULL; | ||||
|             } | ||||
|             // module filename missing
 | ||||
|             _PyErr_Clear(tstate); | ||||
|         } | ||||
|     origin = NULL; | ||||
|     if (PyObject_GetOptionalAttr(v, &_Py_ID(__spec__), &spec) < 0) { | ||||
|         Py_DECREF(mod_name_or_unknown); | ||||
|         return NULL; | ||||
|     } | ||||
|     if (pkgpath == NULL || !PyUnicode_Check(pkgpath)) { | ||||
|         Py_CLEAR(pkgpath); | ||||
|     if (spec == NULL) { | ||||
|         errmsg = PyUnicode_FromFormat( | ||||
|             "cannot import name %R from %R (unknown location)", | ||||
|             name, pkgname_or_unknown | ||||
|             name, mod_name_or_unknown | ||||
|         ); | ||||
|         goto done_with_errmsg; | ||||
|     } | ||||
|     if (_PyModuleSpec_GetFileOrigin(spec, &origin) < 0) { | ||||
|         goto done; | ||||
|     } | ||||
| 
 | ||||
|     int is_possibly_shadowing = _PyModule_IsPossiblyShadowing(origin); | ||||
|     if (is_possibly_shadowing < 0) { | ||||
|         goto done; | ||||
|     } | ||||
|     int is_possibly_shadowing_stdlib = 0; | ||||
|     if (is_possibly_shadowing) { | ||||
|         PyObject *stdlib_modules = PySys_GetObject("stdlib_module_names"); | ||||
|         if (stdlib_modules && PyAnySet_Check(stdlib_modules)) { | ||||
|             is_possibly_shadowing_stdlib = PySet_Contains(stdlib_modules, mod_name_or_unknown); | ||||
|             if (is_possibly_shadowing_stdlib < 0) { | ||||
|                 goto done; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if (is_possibly_shadowing_stdlib) { | ||||
|         assert(origin); | ||||
|         errmsg = PyUnicode_FromFormat( | ||||
|             "cannot import name %R from %R " | ||||
|             "(consider renaming %R since it has the same " | ||||
|             "name as the standard library module named %R " | ||||
|             "and prevents importing that standard library module)", | ||||
|             name, mod_name_or_unknown, origin, mod_name_or_unknown | ||||
|         ); | ||||
|     } | ||||
|     else { | ||||
|         PyObject *spec; | ||||
|         int rc = PyObject_GetOptionalAttr(v, &_Py_ID(__spec__), &spec); | ||||
|         if (rc > 0) { | ||||
|             rc = _PyModuleSpec_IsInitializing(spec); | ||||
|             Py_DECREF(spec); | ||||
|         } | ||||
|         int rc = _PyModuleSpec_IsInitializing(spec); | ||||
|         if (rc < 0) { | ||||
|             Py_DECREF(pkgname_or_unknown); | ||||
|             Py_DECREF(pkgpath); | ||||
|             return NULL; | ||||
|             goto done; | ||||
|         } | ||||
|         else if (rc > 0) { | ||||
|             if (is_possibly_shadowing) { | ||||
|                 assert(origin); | ||||
|                 // For non-stdlib modules, only mention the possibility of
 | ||||
|                 // shadowing if the module is being initialized.
 | ||||
|                 errmsg = PyUnicode_FromFormat( | ||||
|                     "cannot import name %R from %R " | ||||
|                     "(consider renaming %R if it has the same name " | ||||
|                     "as a library you intended to import)", | ||||
|                     name, mod_name_or_unknown, origin | ||||
|                 ); | ||||
|             } | ||||
|             else if (origin) { | ||||
|                 errmsg = PyUnicode_FromFormat( | ||||
|                     "cannot import name %R from partially initialized module %R " | ||||
|                     "(most likely due to a circular import) (%S)", | ||||
|                     name, mod_name_or_unknown, origin | ||||
|                 ); | ||||
|             } | ||||
|             else { | ||||
|                 errmsg = PyUnicode_FromFormat( | ||||
|                     "cannot import name %R from partially initialized module %R " | ||||
|                     "(most likely due to a circular import)", | ||||
|                     name, mod_name_or_unknown | ||||
|                 ); | ||||
|             } | ||||
|         } | ||||
|         else { | ||||
|             assert(rc == 0); | ||||
|             if (origin) { | ||||
|                 errmsg = PyUnicode_FromFormat( | ||||
|                     "cannot import name %R from %R (%S)", | ||||
|                     name, mod_name_or_unknown, origin | ||||
|                 ); | ||||
|             } | ||||
|             else { | ||||
|                 errmsg = PyUnicode_FromFormat( | ||||
|                     "cannot import name %R from %R (unknown location)", | ||||
|                     name, mod_name_or_unknown | ||||
|                 ); | ||||
|             } | ||||
|         } | ||||
|         const char *fmt = | ||||
|             rc ? | ||||
|             "cannot import name %R from partially initialized module %R " | ||||
|             "(most likely due to a circular import) (%S)" : | ||||
|             "cannot import name %R from %R (%S)"; | ||||
| 
 | ||||
|         errmsg = PyUnicode_FromFormat(fmt, name, pkgname_or_unknown, pkgpath); | ||||
|     } | ||||
|     /* NULL checks for errmsg and pkgname done by PyErr_SetImportError. */ | ||||
|     _PyErr_SetImportErrorWithNameFrom(errmsg, pkgname, pkgpath, name); | ||||
| 
 | ||||
|     Py_XDECREF(errmsg); | ||||
|     Py_DECREF(pkgname_or_unknown); | ||||
|     Py_XDECREF(pkgpath); | ||||
| done_with_errmsg: | ||||
|     /* NULL checks for errmsg, mod_name, origin done by PyErr_SetImportError. */ | ||||
|     _PyErr_SetImportErrorWithNameFrom(errmsg, mod_name, origin, name); | ||||
|     Py_DECREF(errmsg); | ||||
| 
 | ||||
| done: | ||||
|     Py_XDECREF(origin); | ||||
|     Py_XDECREF(spec); | ||||
|     Py_DECREF(mod_name_or_unknown); | ||||
|     return NULL; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Shantanu
						Shantanu