From: Victor Stinner Date: Thu, 15 Sep 2011 17:38:54 +0000 (+0200) Subject: Merge 3.2: Fix the import machinery if there is an error on sys.path or sys.meta_path X-Git-Tag: v3.3.0a1~1531 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=84b8e40fd7229303ddc76f13b33f5fa00687de2a;p=thirdparty%2FPython%2Fcpython.git Merge 3.2: Fix the import machinery if there is an error on sys.path or sys.meta_path 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. --- 84b8e40fd7229303ddc76f13b33f5fa00687de2a diff --cc Python/import.c index 141124830a00,ee905eb286af..7902721a92ee --- a/Python/import.c +++ b/Python/import.c @@@ -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 * ^ ^ ^ ^