Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 18d4d8f

Browse files
committed
Two changes to from...import:
1) "from M import X" now works even if M is not a real module; it's basically a getattr() operation with AttributeError exceptions changed into ImportError. 2) "from M import *" now looks for M.__all__ to decide which names to import; if M.__all__ doesn't exist, it uses M.__dict__.keys() but filters out names starting with '_' as before. Whether or not __all__ exists, there's no restriction on the type of M.
1 parent ad99177 commit 18d4d8f

1 file changed

Lines changed: 54 additions & 30 deletions

File tree

Python/ceval.c

Lines changed: 54 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3089,48 +3089,72 @@ cmp_outcome(int op, register PyObject *v, register PyObject *w)
30893089
static PyObject *
30903090
import_from(PyObject *v, PyObject *name)
30913091
{
3092-
PyObject *w, *x;
3093-
if (!PyModule_Check(v)) {
3094-
PyErr_SetString(PyExc_TypeError,
3095-
"import-from requires a module object");
3096-
return NULL;
3097-
}
3098-
w = PyModule_GetDict(v); /* TDB: can this not fail ? */
3099-
x = PyDict_GetItem(w, name);
3100-
if (x == NULL) {
3092+
PyObject *x;
3093+
3094+
x = PyObject_GetAttr(v, name);
3095+
if (x == NULL && PyErr_ExceptionMatches(PyExc_AttributeError)) {
31013096
PyErr_Format(PyExc_ImportError,
31023097
"cannot import name %.230s",
31033098
PyString_AsString(name));
3104-
} else
3105-
Py_INCREF(x);
3099+
}
31063100
return x;
31073101
}
3108-
3102+
31093103
static int
31103104
import_all_from(PyObject *locals, PyObject *v)
31113105
{
3112-
int pos = 0, err;
3113-
PyObject *name, *value;
3114-
PyObject *w;
3115-
3116-
if (!PyModule_Check(v)) {
3117-
PyErr_SetString(PyExc_TypeError,
3118-
"import-from requires a module object");
3119-
return -1;
3106+
PyObject *all = PyObject_GetAttrString(v, "__all__");
3107+
PyObject *dict, *name, *value;
3108+
int skip_leading_underscores = 0;
3109+
int pos, err;
3110+
3111+
if (all == NULL) {
3112+
if (!PyErr_ExceptionMatches(PyExc_AttributeError))
3113+
return -1; /* Unexpected error */
3114+
PyErr_Clear();
3115+
dict = PyObject_GetAttrString(v, "__dict__");
3116+
if (dict == NULL) {
3117+
if (!PyErr_ExceptionMatches(PyExc_AttributeError))
3118+
return -1;
3119+
PyErr_SetString(PyExc_ImportError,
3120+
"from-import-* object has no __dict__ and no __all__");
3121+
return -1;
3122+
}
3123+
all = PyMapping_Keys(dict);
3124+
Py_DECREF(dict);
3125+
if (all == NULL)
3126+
return -1;
3127+
skip_leading_underscores = 1;
31203128
}
3121-
w = PyModule_GetDict(v); /* TBD: can this not fail ? */
31223129

3123-
while (PyDict_Next(w, &pos, &name, &value)) {
3124-
if (!PyString_Check(name) ||
3125-
PyString_AsString(name)[0] == '_')
3126-
continue;
3127-
Py_INCREF(value);
3128-
err = PyDict_SetItem(locals, name, value);
3129-
Py_DECREF(value);
3130+
for (pos = 0, err = 0; ; pos++) {
3131+
name = PySequence_GetItem(all, pos);
3132+
if (name == NULL) {
3133+
if (!PyErr_ExceptionMatches(PyExc_IndexError))
3134+
err = -1;
3135+
else
3136+
PyErr_Clear();
3137+
break;
3138+
}
3139+
if (skip_leading_underscores &&
3140+
PyString_Check(name) &&
3141+
PyString_AS_STRING(name)[0] == '_')
3142+
{
3143+
Py_DECREF(name);
3144+
continue;
3145+
}
3146+
value = PyObject_GetAttr(v, name);
3147+
if (value == NULL)
3148+
err = -1;
3149+
else
3150+
err = PyDict_SetItem(locals, name, value);
3151+
Py_DECREF(name);
3152+
Py_XDECREF(value);
31303153
if (err != 0)
3131-
return -1;
3154+
break;
31323155
}
3133-
return 0;
3156+
Py_DECREF(all);
3157+
return err;
31343158
}
31353159

31363160
static PyObject *

0 commit comments

Comments
 (0)