Issue #25791: Warn when __package__ != __spec__.parent.

In a previous change, __spec__.parent was prioritized over
__package__. That is a backwards-compatibility break, but we do
eventually want __spec__ to be the ground truth for module details. So
this change reverts the change in semantics and instead raises an
ImportWarning when __package__ != __spec__.parent to give people time
to adjust to using spec objects.
This commit is contained in:
Brett Cannon 2016-01-22 15:25:50 -08:00
parent 52c854a838
commit 849113af6b
8 changed files with 184 additions and 121 deletions

View file

@ -1415,60 +1415,79 @@ PyImport_ImportModuleLevelObject(PyObject *name, PyObject *given_globals,
goto error;
}
else if (level > 0) {
package = _PyDict_GetItemId(globals, &PyId___package__);
spec = _PyDict_GetItemId(globals, &PyId___spec__);
if (spec != NULL) {
package = PyObject_GetAttrString(spec, "parent");
}
if (package != NULL && package != Py_None) {
Py_INCREF(package);
if (!PyUnicode_Check(package)) {
PyErr_SetString(PyExc_TypeError, "package must be a string");
goto error;
}
else if (spec != NULL) {
int equal;
PyObject *parent = PyObject_GetAttrString(spec, "parent");
if (parent == NULL) {
goto error;
}
equal = PyObject_RichCompareBool(package, parent, Py_EQ);
Py_DECREF(parent);
if (equal < 0) {
goto error;
}
else if (equal == 0) {
if (PyErr_WarnEx(PyExc_ImportWarning,
"__package__ != __spec__.parent", 1) < 0) {
goto error;
}
}
}
}
else if (spec != NULL) {
package = PyObject_GetAttrString(spec, "parent");
if (package == NULL) {
goto error;
}
else if (!PyUnicode_Check(package)) {
PyErr_SetString(PyExc_TypeError,
"__spec__.parent must be a string");
goto error;
}
}
else {
package = _PyDict_GetItemId(globals, &PyId___package__);
if (package != NULL && package != Py_None) {
Py_INCREF(package);
if (!PyUnicode_Check(package)) {
PyErr_SetString(PyExc_TypeError, "package must be a string");
goto error;
}
if (PyErr_WarnEx(PyExc_ImportWarning,
"can't resolve package from __spec__ or __package__, "
"falling back on __name__ and __path__", 1) < 0) {
goto error;
}
else {
if (PyErr_WarnEx(PyExc_ImportWarning,
"can't resolve package from __spec__ or __package__, "
"falling back on __name__ and __path__", 1) < 0) {
package = _PyDict_GetItemId(globals, &PyId___name__);
if (package == NULL) {
PyErr_SetString(PyExc_KeyError, "'__name__' not in globals");
goto error;
}
Py_INCREF(package);
if (!PyUnicode_Check(package)) {
PyErr_SetString(PyExc_TypeError, "__name__ must be a string");
goto error;
}
if (_PyDict_GetItemId(globals, &PyId___path__) == NULL) {
PyObject *partition = NULL;
PyObject *borrowed_dot = _PyUnicode_FromId(&single_dot);
if (borrowed_dot == NULL) {
goto error;
}
package = _PyDict_GetItemId(globals, &PyId___name__);
if (package == NULL) {
PyErr_SetString(PyExc_KeyError, "'__name__' not in globals");
partition = PyUnicode_RPartition(package, borrowed_dot);
Py_DECREF(package);
if (partition == NULL) {
goto error;
}
package = PyTuple_GET_ITEM(partition, 0);
Py_INCREF(package);
if (!PyUnicode_Check(package)) {
PyErr_SetString(PyExc_TypeError, "__name__ must be a string");
goto error;
}
if (_PyDict_GetItemId(globals, &PyId___path__) == NULL) {
PyObject *partition = NULL;
PyObject *borrowed_dot = _PyUnicode_FromId(&single_dot);
if (borrowed_dot == NULL) {
goto error;
}
partition = PyUnicode_RPartition(package, borrowed_dot);
Py_DECREF(package);
if (partition == NULL) {
goto error;
}
package = PyTuple_GET_ITEM(partition, 0);
Py_INCREF(package);
Py_DECREF(partition);
}
Py_DECREF(partition);
}
}