summaryrefslogtreecommitdiffstats
path: root/Objects
diff options
context:
space:
mode:
authorSerhiy Storchaka <storchaka@gmail.com>2018-10-30 11:19:51 (GMT)
committerGitHub <noreply@github.com>2018-10-30 11:19:51 (GMT)
commit3e429dcc242e48fa4cbb1a91cf7c416c37b97b4e (patch)
tree6e84750ed25ac0ec74e491a4261ce4338bff4fa0 /Objects
parent95b6acf951fa7f503a3cc5ce7d969d7bcf2f95c9 (diff)
downloadcpython-3e429dcc242e48fa4cbb1a91cf7c416c37b97b4e.zip
cpython-3e429dcc242e48fa4cbb1a91cf7c416c37b97b4e.tar.gz
cpython-3e429dcc242e48fa4cbb1a91cf7c416c37b97b4e.tar.bz2
bpo-33237: Improve AttributeError message for partially initialized module. (GH-6398)
Diffstat (limited to 'Objects')
-rw-r--r--Objects/moduleobject.c41
1 files changed, 39 insertions, 2 deletions
diff --git a/Objects/moduleobject.c b/Objects/moduleobject.c
index ccf5f8e..5181941 100644
--- a/Objects/moduleobject.c
+++ b/Objects/moduleobject.c
@@ -698,6 +698,27 @@ module_repr(PyModuleObject *m)
return PyObject_CallMethod(interp->importlib, "_module_repr", "O", m);
}
+/* Check if the "_initializing" attribute of the module spec is set to true.
+ Clear the exception and return 0 if spec is NULL.
+ */
+int
+_PyModuleSpec_IsInitializing(PyObject *spec)
+{
+ if (spec != NULL) {
+ _Py_IDENTIFIER(_initializing);
+ PyObject *value = _PyObject_GetAttrId(spec, &PyId__initializing);
+ if (value != NULL) {
+ int initializing = PyObject_IsTrue(value);
+ Py_DECREF(value);
+ if (initializing >= 0) {
+ return initializing;
+ }
+ }
+ }
+ PyErr_Clear();
+ return 0;
+}
+
static PyObject*
module_getattro(PyModuleObject *m, PyObject *name)
{
@@ -717,8 +738,24 @@ module_getattro(PyModuleObject *m, PyObject *name)
_Py_IDENTIFIER(__name__);
mod_name = _PyDict_GetItemId(m->md_dict, &PyId___name__);
if (mod_name && PyUnicode_Check(mod_name)) {
- PyErr_Format(PyExc_AttributeError,
- "module '%U' has no attribute '%U'", mod_name, name);
+ _Py_IDENTIFIER(__spec__);
+ Py_INCREF(mod_name);
+ PyObject *spec = _PyDict_GetItemId(m->md_dict, &PyId___spec__);
+ Py_XINCREF(spec);
+ if (_PyModuleSpec_IsInitializing(spec)) {
+ PyErr_Format(PyExc_AttributeError,
+ "partially initialized "
+ "module '%U' has no attribute '%U' "
+ "(most likely due to a circular import)",
+ mod_name, name);
+ }
+ else {
+ PyErr_Format(PyExc_AttributeError,
+ "module '%U' has no attribute '%U'",
+ mod_name, name);
+ }
+ Py_XDECREF(spec);
+ Py_DECREF(mod_name);
return NULL;
}
}