From 17fc85f2f581cd5fcbd139aeb1b5078e0e509cc1 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Sat, 6 Sep 1997 18:52:03 +0000 Subject: Phase two of package import. "import a.b.c" and all variants now do the right thing. Still to do: - Make reload() of a submodule work. - Performance tweaks -- currently, a submodule that tries to import a global module *always* searches the package directory first, even if the global module was already imported. Not sure how to solve this one; probably need to record misses per package. - Documentation! --- Python/import.c | 316 +++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 299 insertions(+), 17 deletions(-) diff --git a/Python/import.c b/Python/import.c index 971e658..a581c4f 100644 --- a/Python/import.c +++ b/Python/import.c @@ -564,6 +564,9 @@ load_package(name, pathname) m = PyImport_AddModule(name); if (m == NULL) return NULL; + if (Py_VerboseFlag) + fprintf(stderr, "import %s # directory %s\n", + name, pathname); d = PyModule_GetDict(m); file = PyString_FromString(pathname); if (file == NULL) @@ -981,9 +984,33 @@ PyObject * PyImport_ImportModule(name) char *name; { - return PyImport_ImportModuleEx(name, NULL, NULL, NULL); + static PyObject *fromlist = NULL; + if (fromlist == NULL && strchr(name, '.') != NULL) { + fromlist = Py_BuildValue("[s]", "*"); + if (fromlist == NULL) + return NULL; + } + return PyImport_ImportModuleEx(name, NULL, NULL, fromlist); } +/* Forward declarations for helper routines */ +static PyObject *get_parent Py_PROTO((PyObject *globals, + char *buf, int *p_buflen)); +static PyObject *load_next Py_PROTO((PyObject *mod, PyObject *altmod, + char **p_name, char *buf, int *p_buflen)); +static int ensure_fromlist Py_PROTO((PyObject *mod, PyObject *fromlist, + char *buf, int buflen)); +static PyObject * import_submodule Py_PROTO((PyObject *mod, + char *name, char *fullname)); + +/* The Magnum Opus of dotted-name import :-) */ + +/* XXX TO DO: + - Remember misses in package directories so package submodules + that all import the same toplevel module don't keep hitting on the + package directory first +*/ + PyObject * PyImport_ImportModuleEx(name, globals, locals, fromlist) char *name; @@ -991,25 +1018,280 @@ PyImport_ImportModuleEx(name, globals, locals, fromlist) PyObject *locals; PyObject *fromlist; { + char buf[MAXPATHLEN+1]; + int buflen = 0; + PyObject *parent, *head, *next, *tail; + + parent = get_parent(globals, buf, &buflen); + if (parent == NULL) + return NULL; + + head = load_next(parent, Py_None, &name, buf, &buflen); + if (head == NULL) + return NULL; + + tail = head; + Py_INCREF(tail); + while (name) { + next = load_next(tail, tail, &name, buf, &buflen); + Py_DECREF(tail); + if (next == NULL) { + Py_DECREF(head); + return NULL; + } + tail = next; + } + + if (fromlist != NULL) { + if (fromlist == Py_None || !PyObject_IsTrue(fromlist)) + fromlist = NULL; + } + + if (fromlist == NULL) { + Py_DECREF(tail); + return head; + } + + Py_DECREF(head); + if (!ensure_fromlist(tail, fromlist, buf, buflen)) { + Py_DECREF(tail); + return NULL; + } + + return tail; +} + +static PyObject * +get_parent(globals, buf, p_buflen) + PyObject *globals; + char *buf; + int *p_buflen; +{ + static PyObject *namestr = NULL; + static PyObject *pathstr = NULL; + PyObject *modname, *modpath, *modules, *parent; + + if (globals == NULL || !PyDict_Check(globals)) + return Py_None; + + if (namestr == NULL) { + namestr = PyString_InternFromString("__name__"); + if (namestr == NULL) + return NULL; + } + if (pathstr == NULL) { + pathstr = PyString_InternFromString("__path__"); + if (pathstr == NULL) + return NULL; + } + + *buf = '\0'; + *p_buflen = 0; + modname = PyDict_GetItem(globals, namestr); + if (modname == NULL || !PyString_Check(modname)) + return Py_None; + + modpath = PyDict_GetItem(globals, pathstr); + if (modpath != NULL) { + int len = PyString_GET_SIZE(modname); + if (len > MAXPATHLEN) { + PyErr_SetString(PyExc_ValueError, + "Module name too long"); + return NULL; + } + strcpy(buf, PyString_AS_STRING(modname)); + *p_buflen = len; + } + else { + char *start = PyString_AS_STRING(modname); + char *lastdot = strrchr(start, '.'); + int len; + if (lastdot == NULL) + return Py_None; + len = lastdot - start; + if (len >= MAXPATHLEN) { + PyErr_SetString(PyExc_ValueError, + "Module name too long"); + return NULL; + } + strncpy(buf, start, len); + buf[len] = '\0'; + *p_buflen = len; + } + + modules = PyImport_GetModuleDict(); + parent = PyDict_GetItemString(modules, buf); + if (parent == NULL) + parent = Py_None; + return parent; + /* We expect, but can't guarantee, if parent != None, that: + - parent.__name__ == buf + - parent.__dict__ is globals + If this is violated... Who cares? */ +} + +static PyObject * +load_next(mod, altmod, p_name, buf, p_buflen) + PyObject *mod; + PyObject *altmod; /* Either None or same as mod */ + char **p_name; + char *buf; + int *p_buflen; +{ + char *name = *p_name; + char *dot = strchr(name, '.'); + int len; + char *p; + PyObject *result; + + if (dot == NULL) { + *p_name = NULL; + len = strlen(name); + } + else { + *p_name = dot+1; + len = dot-name; + } + + p = buf + *p_buflen; + if (p != buf) + *p++ = '.'; + if (p+len-buf >= MAXPATHLEN) { + PyErr_SetString(PyExc_ValueError, + "Module name too long"); + return NULL; + } + strncpy(p, name, len); + p[len] = '\0'; + *p_buflen = p+len-buf; + + result = import_submodule(mod, p, buf); + if (result == Py_None && altmod != mod) { + Py_DECREF(result); + /* Here, altmod must be None */ + strncpy(buf, name, len); + buf[len] = '\0'; + *p_buflen = len; + result = import_submodule(altmod, buf, buf); + } + if (result == NULL) + return NULL; + + if (result == Py_None) { + Py_DECREF(result); + PyErr_Format(PyExc_ImportError, + "No module named %.200s", name); + return NULL; + } + + return result; +} + +static int +ensure_fromlist(mod, fromlist, buf, buflen) + PyObject *mod; + PyObject *fromlist; + char *buf; + int buflen; +{ + int i; + + if (!PyObject_HasAttrString(mod, "__path__")) + return 1; + + for (i = 0; ; i++) { + PyObject *item = PySequence_GetItem(fromlist, i); + int hasit; + if (item == NULL) { + if (PyErr_ExceptionMatches(PyExc_IndexError)) { + PyErr_Clear(); + return 1; + } + return 0; + } + if (!PyString_Check(item)) { + PyErr_SetString(PyExc_TypeError, + "Item in ``from list'' not a string"); + Py_DECREF(item); + return 0; + } + if (PyString_AS_STRING(item)[0] == '*') { + Py_DECREF(item); + continue; + } + hasit = PyObject_HasAttr(mod, item); + if (!hasit) { + char *subname = PyString_AS_STRING(item); + PyObject *submod; + char *p; + if (buflen + strlen(subname) >= MAXPATHLEN) { + PyErr_SetString(PyExc_ValueError, + "Module name too long"); + Py_DECREF(item); + return 0; + } + p = buf + buflen; + *p++ = '.'; + strcpy(p, subname); + submod = import_submodule(mod, subname, buf); + Py_XDECREF(submod); + if (submod == NULL) { + Py_DECREF(item); + return 0; + } + } + Py_DECREF(item); + } + + return 1; +} + +static PyObject * +import_submodule(mod, subname, fullname) + PyObject *mod; /* May be None */ + char *subname; + char *fullname; +{ PyObject *modules = PyImport_GetModuleDict(); PyObject *m; - if ((m = PyDict_GetItemString(modules, name)) != NULL) { + /* Require: + if mod == None: subname == fullname + else: mod.__name__ + "." + subname == fullname + */ + + if ((m = PyDict_GetItemString(modules, fullname)) != NULL) { Py_INCREF(m); } else { + PyObject *path; char buf[MAXPATHLEN+1]; struct filedescr *fdp; FILE *fp = NULL; + path = PyObject_GetAttrString(mod, "__path__"); + if (path == NULL) + PyErr_Clear(); + buf[0] = '\0'; - fdp = find_module(name, (PyObject *)NULL, + fdp = find_module(subname, path, buf, MAXPATHLEN+1, &fp); - if (fdp == NULL) - return NULL; - m = load_module(name, fp, buf, fdp->type); + if (fdp == NULL) { + if (!PyErr_ExceptionMatches(PyExc_ImportError)) + return NULL; + PyErr_Clear(); + Py_INCREF(Py_None); + return Py_None; + } + m = load_module(fullname, fp, buf, fdp->type); if (fp) fclose(fp); + if (m != NULL && mod != Py_None) { + if (PyObject_SetAttrString(mod, subname, m) < 0) { + Py_DECREF(m); + m = NULL; + } + } } return m; @@ -1186,7 +1468,7 @@ imp_get_suffixes(self, args) static PyObject * call_find_module(name, path) char *name; - PyObject *path; /* list or NULL */ + PyObject *path; /* list or None or NULL */ { extern int fclose Py_PROTO((FILE *)); PyObject *fob, *ret; @@ -1195,6 +1477,8 @@ call_find_module(name, path) FILE *fp = NULL; pathname[0] = '\0'; + if (path == Py_None) + path = NULL; fdp = find_module(name, path, pathname, MAXPATHLEN+1, &fp); if (fdp == NULL) return NULL; @@ -1222,7 +1506,7 @@ imp_find_module(self, args) { char *name; PyObject *path = NULL; - if (!PyArg_ParseTuple(args, "s|O!", &name, &PyList_Type, &path)) + if (!PyArg_ParseTuple(args, "s|O", &name, &path)) return NULL; return call_find_module(name, path); } @@ -1474,18 +1758,16 @@ imp_find_module_in_package(self, args) PyObject *self; PyObject *args; { - PyObject *name; + char *name; PyObject *packagename = NULL; PyObject *package; PyObject *modules; PyObject *path; - if (!PyArg_ParseTuple(args, "S|S", &name, &packagename)) + if (!PyArg_ParseTuple(args, "s|S", &name, &packagename)) return NULL; if (packagename == NULL || PyString_GET_SIZE(packagename) == 0) { - return call_find_module( - PyString_AS_STRING(name), - (PyObject *)NULL); + return call_find_module(name, (PyObject *)NULL); } modules = PyImport_GetModuleDict(); package = PyDict_GetItem(modules, packagename); @@ -1502,7 +1784,7 @@ imp_find_module_in_package(self, args) PyString_AS_STRING(packagename)); return NULL; } - return call_find_module(PyString_AS_STRING(name), path); + return call_find_module(name, path); } static PyObject * @@ -1510,16 +1792,16 @@ imp_find_module_in_directory(self, args) PyObject *self; PyObject *args; { - PyObject *name; + char *name; PyObject *directory; PyObject *path; - if (!PyArg_ParseTuple(args, "SS", &name, &directory)) + if (!PyArg_ParseTuple(args, "sS", &name, &directory)) return NULL; path = Py_BuildValue("[O]", directory); if (path == NULL) return NULL; - return call_find_module(PyString_AS_STRING(name), path); + return call_find_module(name, path); } static PyMethodDef imp_methods[] = { -- cgit v0.12