mirror of
https://github.com/python/cpython.git
synced 2025-10-09 16:34:44 +00:00
gh-112660: Do not clear arbitrary errors on import (GH-112661)
Previously arbitrary errors could be cleared during formatting error messages for ImportError or AttributeError for modules. Now all unexpected errors are reported.
This commit is contained in:
parent
953ee622b3
commit
8660fb7fd7
4 changed files with 72 additions and 58 deletions
|
@ -0,0 +1,2 @@
|
||||||
|
Do not clear unexpected errors during formatting error messages for
|
||||||
|
ImportError and AttributeError for modules.
|
|
@ -749,27 +749,20 @@ module_repr(PyModuleObject *m)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if the "_initializing" attribute of the module spec is set to true.
|
/* Check if the "_initializing" attribute of the module spec is set to true.
|
||||||
Clear the exception and return 0 if spec is NULL.
|
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
_PyModuleSpec_IsInitializing(PyObject *spec)
|
_PyModuleSpec_IsInitializing(PyObject *spec)
|
||||||
{
|
{
|
||||||
if (spec != NULL) {
|
if (spec == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
PyObject *value;
|
PyObject *value;
|
||||||
int ok = PyObject_GetOptionalAttr(spec, &_Py_ID(_initializing), &value);
|
int rc = PyObject_GetOptionalAttr(spec, &_Py_ID(_initializing), &value);
|
||||||
if (ok == 0) {
|
if (rc > 0) {
|
||||||
return 0;
|
rc = PyObject_IsTrue(value);
|
||||||
}
|
|
||||||
if (value != NULL) {
|
|
||||||
int initializing = PyObject_IsTrue(value);
|
|
||||||
Py_DECREF(value);
|
Py_DECREF(value);
|
||||||
if (initializing >= 0) {
|
|
||||||
return initializing;
|
|
||||||
}
|
}
|
||||||
}
|
return rc;
|
||||||
}
|
|
||||||
PyErr_Clear();
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if the submodule name is in the "_uninitialized_submodules" attribute
|
/* Check if the submodule name is in the "_uninitialized_submodules" attribute
|
||||||
|
@ -782,17 +775,13 @@ _PyModuleSpec_IsUninitializedSubmodule(PyObject *spec, PyObject *name)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject *value = PyObject_GetAttr(spec, &_Py_ID(_uninitialized_submodules));
|
PyObject *value;
|
||||||
if (value == NULL) {
|
int rc = PyObject_GetOptionalAttr(spec, &_Py_ID(_uninitialized_submodules), &value);
|
||||||
return 0;
|
if (rc > 0) {
|
||||||
}
|
rc = PySequence_Contains(value, name);
|
||||||
|
|
||||||
int is_uninitialized = PySequence_Contains(value, name);
|
|
||||||
Py_DECREF(value);
|
Py_DECREF(value);
|
||||||
if (is_uninitialized == -1) {
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
return is_uninitialized;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject*
|
PyObject*
|
||||||
|
@ -840,25 +829,29 @@ _Py_module_getattro_impl(PyModuleObject *m, PyObject *name, int suppress)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (suppress != 1) {
|
if (suppress != 1) {
|
||||||
if (_PyModuleSpec_IsInitializing(spec)) {
|
int rc = _PyModuleSpec_IsInitializing(spec);
|
||||||
|
if (rc > 0) {
|
||||||
PyErr_Format(PyExc_AttributeError,
|
PyErr_Format(PyExc_AttributeError,
|
||||||
"partially initialized "
|
"partially initialized "
|
||||||
"module '%U' has no attribute '%U' "
|
"module '%U' has no attribute '%U' "
|
||||||
"(most likely due to a circular import)",
|
"(most likely due to a circular import)",
|
||||||
mod_name, name);
|
mod_name, name);
|
||||||
}
|
}
|
||||||
else if (_PyModuleSpec_IsUninitializedSubmodule(spec, name)) {
|
else if (rc == 0) {
|
||||||
|
rc = _PyModuleSpec_IsUninitializedSubmodule(spec, name);
|
||||||
|
if (rc > 0) {
|
||||||
PyErr_Format(PyExc_AttributeError,
|
PyErr_Format(PyExc_AttributeError,
|
||||||
"cannot access submodule '%U' of module '%U' "
|
"cannot access submodule '%U' of module '%U' "
|
||||||
"(most likely due to a circular import)",
|
"(most likely due to a circular import)",
|
||||||
name, mod_name);
|
name, mod_name);
|
||||||
}
|
}
|
||||||
else {
|
else if (rc == 0) {
|
||||||
PyErr_Format(PyExc_AttributeError,
|
PyErr_Format(PyExc_AttributeError,
|
||||||
"module '%U' has no attribute '%U'",
|
"module '%U' has no attribute '%U'",
|
||||||
mod_name, name);
|
mod_name, name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
Py_XDECREF(spec);
|
Py_XDECREF(spec);
|
||||||
Py_DECREF(mod_name);
|
Py_DECREF(mod_name);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
|
@ -2614,11 +2614,10 @@ import_from(PyThreadState *tstate, PyObject *v, PyObject *name)
|
||||||
/* Issue #17636: in case this failed because of a circular relative
|
/* Issue #17636: in case this failed because of a circular relative
|
||||||
import, try to fallback on reading the module directly from
|
import, try to fallback on reading the module directly from
|
||||||
sys.modules. */
|
sys.modules. */
|
||||||
pkgname = PyObject_GetAttr(v, &_Py_ID(__name__));
|
if (PyObject_GetOptionalAttr(v, &_Py_ID(__name__), &pkgname) < 0) {
|
||||||
if (pkgname == NULL) {
|
return NULL;
|
||||||
goto error;
|
|
||||||
}
|
}
|
||||||
if (!PyUnicode_Check(pkgname)) {
|
if (pkgname == NULL || !PyUnicode_Check(pkgname)) {
|
||||||
Py_CLEAR(pkgname);
|
Py_CLEAR(pkgname);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
@ -2635,42 +2634,59 @@ import_from(PyThreadState *tstate, PyObject *v, PyObject *name)
|
||||||
Py_DECREF(pkgname);
|
Py_DECREF(pkgname);
|
||||||
return x;
|
return x;
|
||||||
error:
|
error:
|
||||||
pkgpath = PyModule_GetFilenameObject(v);
|
|
||||||
if (pkgname == NULL) {
|
if (pkgname == NULL) {
|
||||||
pkgname_or_unknown = PyUnicode_FromString("<unknown module name>");
|
pkgname_or_unknown = PyUnicode_FromString("<unknown module name>");
|
||||||
if (pkgname_or_unknown == NULL) {
|
if (pkgname_or_unknown == NULL) {
|
||||||
Py_XDECREF(pkgpath);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
pkgname_or_unknown = pkgname;
|
pkgname_or_unknown = pkgname;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pkgpath == NULL || !PyUnicode_Check(pkgpath)) {
|
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);
|
_PyErr_Clear(tstate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pkgpath == NULL || !PyUnicode_Check(pkgpath)) {
|
||||||
|
Py_CLEAR(pkgpath);
|
||||||
errmsg = PyUnicode_FromFormat(
|
errmsg = PyUnicode_FromFormat(
|
||||||
"cannot import name %R from %R (unknown location)",
|
"cannot import name %R from %R (unknown location)",
|
||||||
name, pkgname_or_unknown
|
name, pkgname_or_unknown
|
||||||
);
|
);
|
||||||
/* NULL checks for errmsg and pkgname done by PyErr_SetImportError. */
|
|
||||||
_PyErr_SetImportErrorWithNameFrom(errmsg, pkgname, NULL, name);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
PyObject *spec = PyObject_GetAttr(v, &_Py_ID(__spec__));
|
PyObject *spec;
|
||||||
|
int rc = PyObject_GetOptionalAttr(v, &_Py_ID(__spec__), &spec);
|
||||||
|
if (rc > 0) {
|
||||||
|
rc = _PyModuleSpec_IsInitializing(spec);
|
||||||
|
Py_DECREF(spec);
|
||||||
|
}
|
||||||
|
if (rc < 0) {
|
||||||
|
Py_DECREF(pkgname_or_unknown);
|
||||||
|
Py_DECREF(pkgpath);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
const char *fmt =
|
const char *fmt =
|
||||||
_PyModuleSpec_IsInitializing(spec) ?
|
rc ?
|
||||||
"cannot import name %R from partially initialized module %R "
|
"cannot import name %R from partially initialized module %R "
|
||||||
"(most likely due to a circular import) (%S)" :
|
"(most likely due to a circular import) (%S)" :
|
||||||
"cannot import name %R from %R (%S)";
|
"cannot import name %R from %R (%S)";
|
||||||
Py_XDECREF(spec);
|
|
||||||
|
|
||||||
errmsg = PyUnicode_FromFormat(fmt, name, pkgname_or_unknown, pkgpath);
|
errmsg = PyUnicode_FromFormat(fmt, name, pkgname_or_unknown, pkgpath);
|
||||||
|
}
|
||||||
/* NULL checks for errmsg and pkgname done by PyErr_SetImportError. */
|
/* NULL checks for errmsg and pkgname done by PyErr_SetImportError. */
|
||||||
_PyErr_SetImportErrorWithNameFrom(errmsg, pkgname, pkgpath, name);
|
_PyErr_SetImportErrorWithNameFrom(errmsg, pkgname, pkgpath, name);
|
||||||
}
|
|
||||||
|
|
||||||
Py_XDECREF(errmsg);
|
Py_XDECREF(errmsg);
|
||||||
Py_XDECREF(pkgname_or_unknown);
|
Py_DECREF(pkgname_or_unknown);
|
||||||
Py_XDECREF(pkgpath);
|
Py_XDECREF(pkgpath);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -252,10 +252,14 @@ import_ensure_initialized(PyInterpreterState *interp, PyObject *mod, PyObject *n
|
||||||
NOTE: because of this, initializing must be set *before*
|
NOTE: because of this, initializing must be set *before*
|
||||||
stuffing the new module in sys.modules.
|
stuffing the new module in sys.modules.
|
||||||
*/
|
*/
|
||||||
spec = PyObject_GetAttr(mod, &_Py_ID(__spec__));
|
int rc = PyObject_GetOptionalAttr(mod, &_Py_ID(__spec__), &spec);
|
||||||
int busy = _PyModuleSpec_IsInitializing(spec);
|
if (rc > 0) {
|
||||||
Py_XDECREF(spec);
|
rc = _PyModuleSpec_IsInitializing(spec);
|
||||||
if (busy) {
|
Py_DECREF(spec);
|
||||||
|
}
|
||||||
|
if (rc <= 0) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
/* Wait until module is done importing. */
|
/* Wait until module is done importing. */
|
||||||
PyObject *value = PyObject_CallMethodOneArg(
|
PyObject *value = PyObject_CallMethodOneArg(
|
||||||
IMPORTLIB(interp), &_Py_ID(_lock_unlock_module), name);
|
IMPORTLIB(interp), &_Py_ID(_lock_unlock_module), name);
|
||||||
|
@ -263,7 +267,6 @@ import_ensure_initialized(PyInterpreterState *interp, PyObject *mod, PyObject *n
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
Py_DECREF(value);
|
Py_DECREF(value);
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue