[Python-checkins] r85378 - python/branches/pep-382/Python/import.c

martin.v.loewis python-checkins at python.org
Tue Oct 12 17:02:05 CEST 2010


Author: martin.v.loewis
Date: Tue Oct 12 17:02:05 2010
New Revision: 85378

Log:
Expand wildcard paths on importing the package, not
on importing submodules.


Modified:
   python/branches/pep-382/Python/import.c

Modified: python/branches/pep-382/Python/import.c
==============================================================================
--- python/branches/pep-382/Python/import.c	(original)
+++ python/branches/pep-382/Python/import.c	Tue Oct 12 17:02:05 2010
@@ -1318,6 +1318,21 @@
     return m;
 }
 
+/* Check wether s=='*' or s==b'*' */
+static int
+is_star(PyObject *s)
+{
+    if (PyUnicode_Check(s)) {
+        Py_UNICODE *u = PyUnicode_AsUnicode(s);
+        return u[0] == (Py_UNICODE)'*' && u[1] == 0;
+    }
+    else if (PyBytes_Check(s)) {
+        char* c = PyBytes_AsString(s);
+        return c[0] == (int)'*' && c[1] == 0;
+    }
+    return 0;
+}
+
 /* Get source file -> unicode or None
  * Returns the path to the py file if available, else the given path
  */
@@ -1359,12 +1374,14 @@
 }
 
 /* Forward */
-static PyObject *load_module(char *, FILE *, char *, int, PyObject *, 
+static PyObject *load_module(char *, FILE *, char *, int,
                              PyObject*, PyObject *);
-static struct filedescr *find_module(char *, char *, PyObject *, PyObject*,
+static struct filedescr *find_module(char *, char *, PyObject *,
                                      char *, size_t, FILE **, PyObject **,
                                      PyObject **);
 static struct _frozen * find_frozen(char *);
+static int find_pth_files(char *buf, int buflen, PyObject **p_result);
+static int case_ok(char *, Py_ssize_t, Py_ssize_t, char *);
 
 /* Load a package and return its module object WITH INCREMENTED
    REFERENCE COUNT */
@@ -1399,7 +1416,7 @@
     if (err != 0)
         goto error;
     buf[0] = '\0';
-    fdp = find_module(name, "__init__", path, NULL, buf, sizeof(buf), &fp, NULL, NULL);
+    fdp = find_module(name, "__init__", path, buf, sizeof(buf), &fp, NULL, NULL);
     if (fdp == NULL) {
         if (PyErr_ExceptionMatches(PyExc_ImportError)) {
             PyErr_Clear();
@@ -1409,7 +1426,7 @@
             m = NULL;
         goto cleanup;
     }
-    m = load_module(name, fp, buf, fdp->type, NULL, NULL, NULL);
+    m = load_module(name, fp, buf, fdp->type, NULL, NULL);
     if (fp != NULL)
         fclose(fp);
     goto cleanup;
@@ -1422,12 +1439,200 @@
     return m;
 }
 
+/* Add all pathes in pth_list to path; set starred if the resulting
+   path is a wildcard path. */
+static int
+merge_pth_list(PyObject* path, PyObject* pth_list, int* starred)
+{
+    PyObject *sublist = NULL;
+    Py_ssize_t i, len, sublen, subi;
+    len = PyList_Size(pth_list);
+    for (i = 0; i < len; i++) {
+        PyObject *item = PyList_GetItem(pth_list, i); /* borrowed */
+        if (item == 0)
+            goto error;
+        if (!PyUnicode_Check(item)) {
+            PyErr_SetString(PyExc_TypeError, "path item is not str");
+            goto error;
+        }
+        sublist = PyUnicode_Splitlines(item, 0);
+        if (!sublist)
+            goto error;
+        sublen = PyList_Size(sublist);
+        /* Add all items to the path */
+        for (subi = 0; subi < sublen; subi++) {
+            PyObject *item = PyList_GetItem(sublist, subi);
+            Py_UNICODE *uitem = PyUnicode_AsUnicode(item);
+            if (uitem[0] == 0)
+                continue; /* skip empty lines */
+            if (uitem[0] == (Py_UNICODE)'#')
+                continue; /* skip comment lines */
+            if (is_star(item)) {
+                if (*starred)
+                    continue;
+                /* Insert in the front */
+                if (PyList_Insert(path, 0, item) < 0)
+                    goto error;
+                *starred = 1;
+                continue;
+            }
+            if (PyList_Append(path, item) == -1)
+                goto error;
+        }
+        Py_CLEAR(sublist);
+    }
+    return 1;
+  error:
+    Py_XDECREF(sublist);
+    return 0;
+}
+
+/* Expand wildcard path to search parent path */
+static int
+expand_wildcard_path(char *name, PyObject *path, int* starred,
+                     char* buf, int buflen)
+{
+    PyObject *ppath = NULL, *newdir = NULL, *newpath = NULL;
+    char *parentname = NULL;
+    char *modulename;
+    char *lastdot;
+    size_t namelen;
+    Py_ssize_t i, len;
+    PyObject *pth_files;
+    struct stat st;
+    int status;
+
+    parentname = strdup(name);
+    if (!parentname)
+        goto error;
+    lastdot = strrchr(parentname, '.');
+    if (lastdot) {
+        PyObject *modules; /* borrowed */
+        PyObject *module;
+        *lastdot = '\0';
+        modulename = lastdot+1;
+        modules = PyImport_GetModuleDict();
+        module = PyDict_GetItemString(modules, parentname);
+        if (!module)
+            goto error;
+        ppath = PyObject_GetAttrString(module, "__path__");
+        Py_DECREF(module);
+    }
+    else {
+        modulename = name;
+        ppath = PySys_GetObject("path");
+        if (ppath)
+            Py_INCREF(ppath);
+    }
+    if (!ppath || !PyList_Check(ppath)) {
+        PyErr_SetString(PyExc_ImportError, "parent path not found");
+        goto error;
+    }
+    namelen = strlen(modulename);
+
+    /* Iterate over parent path, looking for further pth files */
+    len = PyList_GET_SIZE(ppath);
+    for (i = 0; i < len; i++) {
+        PyObject *v = PyList_GetItem(ppath, i);
+        char *base;
+        Py_ssize_t size;
+        if (i == 0 && is_star(v))
+            /* wildcard in parent, skip */
+            continue;
+        if (PyUnicode_Check(v)) {
+            v = PyUnicode_EncodeFSDefault(v);
+            if (v == NULL)
+                goto error;
+        }
+        else if (!PyBytes_Check(v))
+            continue;
+        else
+            Py_INCREF(v);
+        /* XXX for path hooks, use find_path */
+        base = PyBytes_AS_STRING(v);
+        size = PyBytes_GET_SIZE(v);
+        if (size + namelen + 1 > MAXPATHLEN) {
+            /* XXX no error here? */
+            Py_DECREF(v);
+            continue;
+        }
+        if (size) {
+            strcpy(buf, base);
+            buf[size++] = SEP;
+            strcpy(buf+size, modulename);
+            size += namelen;
+        }
+        else {
+            strcpy(buf, modulename);
+            size = namelen;
+        }
+        Py_DECREF(v);
+        if (stat(buf, &st) == -1)
+            continue;
+        if (!S_ISDIR(st.st_mode))
+            continue;
+        if (!case_ok(buf, size, namelen, name))
+            continue;
+        newdir = PyUnicode_DecodeFSDefault(buf);
+        if (!newdir)
+            goto error;
+        /* Check whether this is already in the path */
+        status = PySequence_Contains(path, newdir);
+        if (status == -1)
+            goto error;
+        if (status == 1) {
+            Py_CLEAR(newdir);
+            continue;
+        }
+
+        /* Check for .pth and __init__.py */        
+        status = find_pth_files(buf, MAXPATHLEN, &pth_files);
+        if (status == -1)
+            goto error;
+        if (status == 0) {
+            /* No pth files found, check for __init__, 
+               by trying to find it on a single-item path. */
+            struct filedescr *fdp;
+            FILE *fp;
+            newpath = Py_BuildValue("[O]", newdir);
+            fdp = find_module(name, "__init__", newpath, buf, buflen, &fp, NULL, NULL);
+            Py_CLEAR(newpath);
+            if (fdp == NULL) {
+                if (!PyErr_ExceptionMatches(PyExc_ImportError))
+                    goto error;
+                PyErr_Clear();
+                continue;
+            }
+            /* __init__ exists; it may not get imported since it may not
+               be the first one on the path. */
+            fclose(fp);
+        }
+        /* Add directory itself to path */
+        if (PyList_Append(path, newdir) == -1)
+            goto error;
+        Py_CLEAR(newdir);
+        /* Also add contents of pth files, if any */
+        if (pth_files && !merge_pth_list(path, pth_files, starred))
+            goto error;
+        Py_CLEAR(pth_files);
+    }
+    free(parentname);
+    Py_DECREF(ppath);
+    return 1;
+  error:
+    free(parentname);
+    Py_XDECREF(ppath);
+    Py_XDECREF(pth_files);
+    Py_XDECREF(newdir);
+    return 0;
+}
+
+
 static PyObject*
 load_namespace_package(char *name, char *pathname, 
-                       PyObject* parent_path, PyObject *pth_list)
+                       PyObject *pth_list)
 {
-    PyObject *m, *d, *file, *path, *sublist = NULL;
-    Py_ssize_t i, len;
+    PyObject *m, *d, *file, *path;
     int starred = 0;
     char buf[MAXPATHLEN+1];
     FILE *fp = NULL;
@@ -1449,45 +1654,20 @@
     Py_CLEAR(file);
     if (path == NULL)
         return NULL;
-    len = PyList_Size(pth_list);
-    for (i = 0; i < len; i++) {
-        PyObject *item = PyList_GetItem(pth_list, i); /* borrowed */
-        PyObject *extend_res;
-        if (item == 0)
-            goto error;
-        if (!PyUnicode_Check(item)) {
-            PyErr_SetString(PyExc_TypeError, "path item is not str");
-            goto error;
-        }
-        sublist = PyUnicode_Splitlines(item, 0);
-        if (!sublist)
-            goto error;
-        /* if sublist starts with *, add to path, unless it's already there */
-        if (PyList_Size(sublist) > 0) {
-            PyObject *first = PyList_GetItem(sublist, 0); /* borrowed */
-            Py_UNICODE *s_first = PyUnicode_AS_UNICODE(first);
-            if (s_first[0] == (int)'*' && s_first[1] == 0) {
-                if (!starred) {
-                    if (PyList_Insert(path, 0, first) < 0)
-                        goto error;
-                    starred = 1;
-                }
-                if (PySequence_DelItem(sublist, 0) < 0)
-                    goto error;
-            }
-        }
-        extend_res = _PyList_Extend((PyListObject*)path, sublist);
-        if (extend_res == NULL)
+    if (!merge_pth_list(path, pth_list, &starred))
+        goto error;
+
+    if (starred) {
+        if (!expand_wildcard_path(name, path, &starred, buf, sizeof(buf)))
             goto error;
-        Py_DECREF(extend_res); /* should be None */
-        Py_CLEAR(sublist);
     }
+
     if (PyDict_SetItemString(d, "__path__", path) < 0)
         goto error;
 
     /* find __init__.py, if any */
     buf[0] = '\0';
-    fdp = find_module(name, "__init__", path, parent_path, buf, sizeof(buf), &fp, NULL, NULL);
+    fdp = find_module(name, "__init__", path, buf, sizeof(buf), &fp, NULL, NULL);
     if (fdp == NULL) {
         if (PyErr_ExceptionMatches(PyExc_ImportError)) {
             PyErr_Clear();
@@ -1496,7 +1676,7 @@
         }
         goto error;
     }
-    m = load_module(name, fp, buf, fdp->type, NULL, NULL, NULL);
+    m = load_module(name, fp, buf, fdp->type, NULL, NULL);
     /* XXX success/fail change to cleanup, adjust INCREF(m) */
     Py_INCREF(m);
     if (fp != NULL)
@@ -1506,7 +1686,6 @@
     m = NULL;
   cleanup:
     Py_DECREF(path);
-    Py_XDECREF(sublist);
     return m;
 }
 
@@ -1615,26 +1794,22 @@
                                         char *, Py_ssize_t);
 #endif
 
-static int case_ok(char *, Py_ssize_t, Py_ssize_t, char *);
 static int find_init_module(char *); /* Forward */
-static int find_pth_files(char *buf, int buflen, PyObject **p_result);
 static struct filedescr importhookdescr = {"", "", IMP_HOOK};
 static struct filedescr namespacepkgdescr = {"", "", NAMESPACE_PACKAGE};
 
 static struct filedescr *
-find_module(char *fullname, char *subname, PyObject *path, PyObject *ppath,
+find_module(char *fullname, char *subname, PyObject *path,
             char *buf, size_t buflen, FILE **p_fp, PyObject **p_loader,
             PyObject **p_pth_list)
 {
-    Py_ssize_t i, npath, nppath = 0;
+    Py_ssize_t i, npath;
     size_t len, namelen, pkgnamelen = 0;
     struct filedescr *fdp = NULL;
     char *filemode;
     char *pkgname = NULL;
     FILE *fp = NULL;
-    PyObject *path_hooks, *path_importer_cache, *curpath;
-    int starred = 0;
-    int toplevel = path == NULL;
+    PyObject *path_hooks, *path_importer_cache;
     struct stat statbuf;
     static struct filedescr fd_frozen = {"", "", PY_FROZEN};
     static struct filedescr fd_builtin = {"", "", C_BUILTIN};
@@ -1760,61 +1935,12 @@
 
     npath = PyList_Size(path);
     namelen = strlen(name);
-    curpath = path; /* may change to ppath below */
-    if (!toplevel && npath > 1) {
-        /* Check whether path[0] == '*' */
-        PyObject *first = PyList_GetItem(path, 0);
-        if (!first)
-            return NULL;
-        if (PyUnicode_Check(first)) {
-            Py_UNICODE *ufirst = PyUnicode_AsUnicode(first);
-            starred = ufirst[0] == (Py_UNICODE)'*' && ufirst[1] == 0;
-        }
-        else if (PyBytes_Check(first)) {
-            char* cfirst = PyBytes_AsString(first);
-            starred = cfirst[0] == (int)'*' && cfirst[1] == 0;
-        }
-        if (starred) {
-            if (ppath == NULL)
-                ppath = PySys_GetObject("path");
-            nppath = PyList_Size(ppath);
-            npath += nppath;
-            curpath = ppath;
-            pkgname = strrchr(fullname, '.');
-            if (pkgname && strcmp(pkgname+1, subname) == 0) {
-                /* last part of fullname is typically subname,
-                   except when __init__ is loaded. */
-                char *pkgname2 = pkgname-1;
-                /* move backwards up to another dot, or the start of fullname */
-                while(pkgname2 > fullname && pkgname2[-1] != '.')
-                    pkgname2--;
-                pkgnamelen = pkgname-pkgname2;
-                pkgname = pkgname2;
-            }
-            else {
-                pkgname = pkgname ? pkgname+1 : fullname;
-                pkgnamelen = strlen(pkgname);
-            }
-            pkgnamelen++; /* accounting for / */
-        }   
-    }
     for (i = 0; i < npath; i++) {
         PyObject *v;
         PyObject *origv;
         const char *base;
         Py_ssize_t size;
-        if (starred && i == nppath) {
-            /* exhausted ppath, go to path, skipping star */
-            curpath = path;
-            npath -= nppath;
-            i = 1;
-            pkgname = NULL;
-            pkgnamelen = 0;
-            if (i == npath)
-                /* path has only * on it */
-                break;
-        }
-        v = PyList_GetItem(curpath, i);
+        v = PyList_GetItem(path, i);
         if (!v)
             return NULL;
         origv = v;
@@ -2299,7 +2425,7 @@
         PyErr_SetFromErrno(PyExc_IOError);
         goto fail;
     }
-    data = malloc(st.st_size);
+    data = malloc(st.st_size + 1);
     if (!data) {
         PyErr_NoMemory();
         goto fail;
@@ -2316,6 +2442,7 @@
     }
     fclose(f);
     f=NULL;
+    data[st.st_size] = '\0';
     /* list.append(data) */
     string = PyUnicode_DecodeFSDefault(data);
     if (!string)
@@ -2428,7 +2555,7 @@
 
 static PyObject *
 load_module(char *name, FILE *fp, char *pathname, int type, 
-            PyObject *loader, PyObject *parent_path, PyObject *pth_list)
+            PyObject *loader, PyObject *pth_list)
 {
     PyObject *m;
 
@@ -2484,7 +2611,7 @@
     }
 
     case NAMESPACE_PACKAGE: {
-        m = load_namespace_package(name, pathname, parent_path, pth_list);
+        m = load_namespace_package(name, pathname, pth_list);
         break;
     }
 
@@ -3238,7 +3365,7 @@
         }
 
         buf[0] = '\0';
-        fdp = find_module(fullname, subname, path, NULL, buf, MAXPATHLEN+1,
+        fdp = find_module(fullname, subname, path, buf, MAXPATHLEN+1,
                           &fp, &loader, &pth_list);
         if (fdp == NULL) {
             Py_XDECREF(loader);
@@ -3249,7 +3376,7 @@
             Py_INCREF(Py_None);
             return Py_None;
         }
-        m = load_module(fullname, fp, buf, fdp->type, loader, path, pth_list);
+        m = load_module(fullname, fp, buf, fdp->type, loader, pth_list);
         Py_XDECREF(loader);
         Py_XDECREF(path);
         if (fp)
@@ -3336,7 +3463,7 @@
             PyErr_Clear();
     }
     buf[0] = '\0';
-    fdp = find_module(name, subname, path, NULL,
+    fdp = find_module(name, subname, path,
                       buf, MAXPATHLEN+1, &fp, &loader, &pth_list);
 
     if (fdp == NULL) {
@@ -3346,7 +3473,7 @@
         return NULL;
     }
 
-    newm = load_module(name, fp, buf, fdp->type, loader, path, pth_list);
+    newm = load_module(name, fp, buf, fdp->type, loader, pth_list);
     Py_XDECREF(loader);
     Py_XDECREF(path);
 
@@ -3523,7 +3650,7 @@
     pathname[0] = '\0';
     if (path == Py_None)
         path = NULL;
-    fdp = find_module(NULL, name, path, NULL, pathname, MAXPATHLEN+1, &fp, NULL, NULL);
+    fdp = find_module(NULL, name, path, pathname, MAXPATHLEN+1, &fp, NULL, NULL);
     if (fdp == NULL)
         return NULL;
     if (fp != NULL) {
@@ -3805,7 +3932,7 @@
             return NULL;
         }
     }
-    ret = load_module(name, fp, pathname, type, NULL, NULL, NULL);
+    ret = load_module(name, fp, pathname, type, NULL, NULL);
     PyMem_Free(pathname);
     if (fp)
         fclose(fp);


More information about the Python-checkins mailing list