]> granicus.if.org Git - python/commitdiff
Phase two of package import. "import a.b.c" and all variants now do the
authorGuido van Rossum <guido@python.org>
Sat, 6 Sep 1997 18:52:03 +0000 (18:52 +0000)
committerGuido van Rossum <guido@python.org>
Sat, 6 Sep 1997 18:52:03 +0000 (18:52 +0000)
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

index 971e658c2c27d014b32d174ae6483e8039e99aba..a581c4f75f6881b6d3612b0c8526c99eeb56d9f9 100644 (file)
@@ -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,35 +984,314 @@ 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;
        PyObject *globals;
        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[] = {