mirror of
https://github.com/python/cpython.git
synced 2025-08-31 05:58:33 +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
|
@ -823,15 +823,15 @@ _PyModuleSpec_IsUninitializedSubmodule(PyObject *spec, PyObject *name)
|
|||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
_get_file_origin_from_spec(PyObject *spec, PyObject **p_origin)
|
||||
int
|
||||
_PyModuleSpec_GetFileOrigin(PyObject *spec, PyObject **p_origin)
|
||||
{
|
||||
PyObject *has_location = NULL;
|
||||
int rc = PyObject_GetOptionalAttr(spec, &_Py_ID(has_location), &has_location);
|
||||
if (rc <= 0) {
|
||||
return rc;
|
||||
}
|
||||
// If origin is not a location, or doesn't exist, or is not a str), we could consider falling
|
||||
// If origin is not a location, or doesn't exist, or is not a str, we could consider falling
|
||||
// back to module.__file__. But the cases in which module.__file__ is not __spec__.origin
|
||||
// are cases in which we probably shouldn't be guessing.
|
||||
rc = PyObject_IsTrue(has_location);
|
||||
|
@ -854,8 +854,8 @@ _get_file_origin_from_spec(PyObject *spec, PyObject **p_origin)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
_is_module_possibly_shadowing(PyObject *origin)
|
||||
int
|
||||
_PyModule_IsPossiblyShadowing(PyObject *origin)
|
||||
{
|
||||
// origin must be a unicode subtype
|
||||
// Returns 1 if the module at origin could be shadowing a module of the
|
||||
|
@ -980,11 +980,11 @@ _Py_module_getattro_impl(PyModuleObject *m, PyObject *name, int suppress)
|
|||
}
|
||||
|
||||
PyObject *origin = NULL;
|
||||
if (_get_file_origin_from_spec(spec, &origin) < 0) {
|
||||
if (_PyModuleSpec_GetFileOrigin(spec, &origin) < 0) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
int is_possibly_shadowing = _is_module_possibly_shadowing(origin);
|
||||
int is_possibly_shadowing = _PyModule_IsPossiblyShadowing(origin);
|
||||
if (is_possibly_shadowing < 0) {
|
||||
goto done;
|
||||
}
|
||||
|
@ -1005,20 +1005,23 @@ _Py_module_getattro_impl(PyModuleObject *m, PyObject *name, int suppress)
|
|||
"module '%U' has no attribute '%U' "
|
||||
"(consider renaming '%U' since it has the same "
|
||||
"name as the standard library module named '%U' "
|
||||
"and the import system gives it precedence)",
|
||||
"and prevents importing that standard library module)",
|
||||
mod_name, name, origin, mod_name);
|
||||
}
|
||||
else {
|
||||
int rc = _PyModuleSpec_IsInitializing(spec);
|
||||
if (rc > 0) {
|
||||
if (rc < 0) {
|
||||
goto done;
|
||||
}
|
||||
else if (rc > 0) {
|
||||
if (is_possibly_shadowing) {
|
||||
assert(origin);
|
||||
// For third-party modules, only mention the possibility of
|
||||
// For non-stdlib modules, only mention the possibility of
|
||||
// shadowing if the module is being initialized.
|
||||
PyErr_Format(PyExc_AttributeError,
|
||||
"module '%U' has no attribute '%U' "
|
||||
"(consider renaming '%U' if it has the same name "
|
||||
"as a third-party module you intended to import)",
|
||||
"as a library you intended to import)",
|
||||
mod_name, name, origin);
|
||||
}
|
||||
else if (origin) {
|
||||
|
@ -1036,7 +1039,8 @@ _Py_module_getattro_impl(PyModuleObject *m, PyObject *name, int suppress)
|
|||
mod_name, name);
|
||||
}
|
||||
}
|
||||
else if (rc == 0) {
|
||||
else {
|
||||
assert(rc == 0);
|
||||
rc = _PyModuleSpec_IsUninitializedSubmodule(spec, name);
|
||||
if (rc > 0) {
|
||||
PyErr_Format(PyExc_AttributeError,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue