]> granicus.if.org Git - python/commitdiff
Merge 3.2: Fix the import machinery if there is an error on sys.path or sys.meta_path
authorVictor Stinner <victor.stinner@haypocalc.com>
Thu, 15 Sep 2011 17:38:54 +0000 (19:38 +0200)
committerVictor Stinner <victor.stinner@haypocalc.com>
Thu, 15 Sep 2011 17:38:54 +0000 (19:38 +0200)
find_module() now raises a RuntimeError, instead of ImportError, on an error on
sys.path or sys.meta_path because load_package() and import_submodule() returns
None and clear the exception if a ImportError occurred.

1  2 
Python/import.c

diff --cc Python/import.c
index 141124830a00237107a6f19560dbe05d23f41875,ee905eb286af8d1f48caabc5a3b774cf4a883f04..7902721a92ee2f4111f709cd6f07ca8671e6697a
@@@ -1895,182 -1766,71 +1895,182 @@@ find_module_path_list(PyObject *fullnam
              filemode = fdp->mode;
              if (filemode[0] == 'U')
                  filemode = "r" PY_STDIOTEXTMODE;
 -            fp = fopen(buf, filemode);
 -            if (fp != NULL) {
 -                if (case_ok(buf, len, namelen, name))
 -                    break;
 -                else {                   /* continue search */
 -                    fclose(fp);
 -                    fp = NULL;
 +
 +            filename = PyUnicode_FromFormat("%U%s", prefix, fdp->suffix);
 +            if (filename == NULL) {
 +                Py_DECREF(prefix);
 +                return NULL;
 +            }
 +
 +            if (Py_VerboseFlag > 1)
 +                PySys_FormatStderr("# trying %R\n", filename);
 +
 +            fp = _Py_fopen(filename, filemode);
 +            if (fp == NULL) {
 +                Py_DECREF(filename);
 +                if (PyErr_Occurred()) {
 +                    Py_DECREF(prefix);
 +                    return NULL;
                  }
 +                continue;
              }
 -#if defined(PYOS_OS2)
 -            /* restore the saved snapshot */
 -            strcpy(buf, saved_buf);
 -            len = saved_len;
 -            namelen = saved_namelen;
 -#endif
 +            match = case_ok(filename, -(Py_ssize_t)strlen(fdp->suffix), name);
 +            if (match < 0) {
 +                Py_DECREF(prefix);
 +                Py_DECREF(filename);
 +                return NULL;
 +            }
 +            if (match) {
 +                Py_DECREF(prefix);
 +                *p_path = filename;
 +                *p_fp = fp;
 +                return fdp;
 +            }
 +            Py_DECREF(filename);
 +
 +            fclose(fp);
 +            fp = NULL;
          }
 -#if defined(PYOS_OS2)
 -        /* don't need/want the module name snapshot anymore */
 -        if (saved_buf)
 -        {
 -            free(saved_buf);
 -            saved_buf = NULL;
 +        Py_DECREF(prefix);
 +    }
 +    PyErr_Format(PyExc_ImportError,
 +                 "No module named %R", name);
 +    return NULL;
 +}
 +
 +/* Find a module:
 +
 +   - try find_module() of each sys.meta_path hook
 +   - try find_frozen()
 +   - try is_builtin()
 +   - try _PyWin_FindRegisteredModule() (Windows only)
 +   - otherwise, call find_module_path_list() with search_path_list (if not
 +     NULL) or sys.path
 +
 +   fullname can be NULL, but only if p_loader is NULL.
 +
 +   Return:
 +
 +   - &fd_builtin (C_BUILTIN) if it is a builtin
 +   - &fd_frozen (PY_FROZEN) if it is frozen
 +   - &fd_package (PKG_DIRECTORY) and write the filename into *p_path
 +     if it is a package
 +   - &importhookdescr (IMP_HOOK) and write the loader into *p_loader if a
 +     importer loader was found
 +   - a file descriptor (PY_SOURCE, PY_COMPILED, C_EXTENSION, PY_RESOURCE or
 +     PY_CODERESOURCE: see _PyImport_Filetab), write the filename into
 +     *p_path and the pointer to the open file into *p_fp
 +   - NULL on error
 +
 +   By default, *p_path, *p_fp and *p_loader (if set) are set to NULL.
 +   Eg. *p_path is set to NULL for a builtin package.
 +*/
 +
 +static struct filedescr *
 +find_module(PyObject *fullname, PyObject *name, PyObject *search_path_list,
 +            PyObject **p_path, FILE **p_fp, PyObject **p_loader)
 +{
 +    Py_ssize_t i, npath;
 +    static struct filedescr fd_frozen = {"", "", PY_FROZEN};
 +    static struct filedescr fd_builtin = {"", "", C_BUILTIN};
 +    PyObject *path_hooks, *path_importer_cache;
 +
 +    *p_path = NULL;
 +    *p_fp = NULL;
 +    if (p_loader != NULL)
 +        *p_loader = NULL;
 +
 +    if (PyUnicode_GET_SIZE(name) > MAXPATHLEN) {
 +        PyErr_SetString(PyExc_OverflowError,
 +                        "module name is too long");
 +        return NULL;
 +    }
 +
 +    /* sys.meta_path import hook */
 +    if (p_loader != NULL) {
 +        PyObject *meta_path;
 +
 +        meta_path = PySys_GetObject("meta_path");
 +        if (meta_path == NULL || !PyList_Check(meta_path)) {
-             PyErr_SetString(PyExc_ImportError,
++            PyErr_SetString(PyExc_RuntimeError,
 +                            "sys.meta_path must be a list of "
 +                            "import hooks");
 +            return NULL;
 +        }
 +        Py_INCREF(meta_path);  /* zap guard */
 +        npath = PyList_Size(meta_path);
 +        for (i = 0; i < npath; i++) {
 +            PyObject *loader;
 +            PyObject *hook = PyList_GetItem(meta_path, i);
 +            loader = PyObject_CallMethod(hook, "find_module",
 +                                         "OO", fullname,
 +                                         search_path_list != NULL ?
 +                                         search_path_list : Py_None);
 +            if (loader == NULL) {
 +                Py_DECREF(meta_path);
 +                return NULL;  /* true error */
 +            }
 +            if (loader != Py_None) {
 +                /* a loader was found */
 +                *p_loader = loader;
 +                Py_DECREF(meta_path);
 +                return &importhookdescr;
 +            }
 +            Py_DECREF(loader);
          }
 +        Py_DECREF(meta_path);
 +    }
 +
 +    if (find_frozen(fullname) != NULL)
 +        return &fd_frozen;
 +
 +    if (search_path_list == NULL) {
 +#ifdef MS_COREDLL
 +        FILE *fp;
 +        struct filedescr *fdp;
  #endif
 -        if (fp != NULL)
 -            break;
 +        if (is_builtin(name))
 +            return &fd_builtin;
 +#ifdef MS_COREDLL
 +        fp = _PyWin_FindRegisteredModule(name, &fdp, p_path);
 +        if (fp != NULL) {
 +            *p_fp = fp;
 +            return fdp;
 +        }
 +        else if (PyErr_Occurred())
 +            return NULL;
 +#endif
 +        search_path_list = PySys_GetObject("path");
      }
 -    if (fp == NULL) {
 -        PyErr_Format(PyExc_ImportError,
 -                     "No module named %.200s", name);
 +
 +    if (search_path_list == NULL || !PyList_Check(search_path_list)) {
-         PyErr_SetString(PyExc_ImportError,
++        PyErr_SetString(PyExc_RuntimeError,
 +                        "sys.path must be a list of directory names");
 +        return NULL;
 +    }
 +
 +    path_hooks = PySys_GetObject("path_hooks");
 +    if (path_hooks == NULL || !PyList_Check(path_hooks)) {
-         PyErr_SetString(PyExc_ImportError,
++        PyErr_SetString(PyExc_RuntimeError,
 +                        "sys.path_hooks must be a list of "
 +                        "import hooks");
          return NULL;
      }
 -    *p_fp = fp;
 -    return fdp;
 +    path_importer_cache = PySys_GetObject("path_importer_cache");
 +    if (path_importer_cache == NULL ||
 +        !PyDict_Check(path_importer_cache)) {
-         PyErr_SetString(PyExc_ImportError,
++        PyErr_SetString(PyExc_RuntimeError,
 +                        "sys.path_importer_cache must be a dict");
 +        return NULL;
 +    }
 +
 +    return find_module_path_list(fullname, name,
 +                                 search_path_list, path_hooks,
 +                                 path_importer_cache,
 +                                 p_path, p_fp, p_loader);
  }
  
 -/* case_ok(char* buf, Py_ssize_t len, Py_ssize_t namelen, char* name)
 +/* case_bytes(char* buf, Py_ssize_t len, Py_ssize_t namelen, char* name)
   * The arguments here are tricky, best shown by example:
   *    /a/b/c/d/e/f/g/h/i/j/k/some_long_module_name.py\0
   *    ^                      ^                   ^    ^