Issue #3080: Create find_module_path() subfunction

This commit is contained in:
Victor Stinner 2011-03-12 16:02:28 -05:00
parent 3758028299
commit d68c2cf237
1 changed files with 139 additions and 89 deletions

View File

@ -1598,57 +1598,53 @@ static int case_ok(char *, Py_ssize_t, Py_ssize_t, const char *);
static int find_init_module(char *); /* Forward */ static int find_init_module(char *); /* Forward */
static struct filedescr importhookdescr = {"", "", IMP_HOOK}; static struct filedescr importhookdescr = {"", "", IMP_HOOK};
static struct filedescr* /* Get the path of a module: get its importer and call importer.find_module()
find_module_path_list(char *fullname, const char *name, hook, or check if the module if a package (if path/__init__.py exists).
PyObject *search_path_list, PyObject *path_hooks,
PyObject *path_importer_cache, -1: error: a Python error occurred
0: ignore: an error occurred because of invalid data, but the error is not
important enough to be reported.
1: get path: module not found, but *buf contains its path
2: found: *p_fd is the file descriptor (IMP_HOOK or PKG_DIRECTORY)
and *buf is the path */
static int
find_module_path(char *fullname, const char *name, PyObject *path,
PyObject *path_hooks, PyObject *path_importer_cache,
char *buf, size_t buflen, char *buf, size_t buflen,
FILE **p_fp, PyObject **p_loader) PyObject **p_loader, struct filedescr **p_fd)
{ {
Py_ssize_t i, npath; PyObject *path_bytes;
size_t len, namelen; const char *base;
struct filedescr *fdp = NULL; Py_ssize_t len;
char *filemode; size_t namelen;
FILE *fp = NULL;
struct stat statbuf; struct stat statbuf;
static struct filedescr fd_package = {"", "", PKG_DIRECTORY}; static struct filedescr fd_package = {"", "", PKG_DIRECTORY};
#if defined(PYOS_OS2)
size_t saved_len;
size_t saved_namelen;
char *saved_buf = NULL;
#endif
npath = PyList_Size(search_path_list); if (PyUnicode_Check(path)) {
namelen = strlen(name); path_bytes = PyUnicode_EncodeFSDefault(path);
for (i = 0; i < npath; i++) { if (path_bytes == NULL)
PyObject *v = PyList_GetItem(search_path_list, i); return -1;
PyObject *origv = v; }
const char *base; else if (PyBytes_Check(path)) {
Py_ssize_t size; Py_INCREF(path);
if (!v) path_bytes = path;
return NULL;
if (PyUnicode_Check(v)) {
v = PyUnicode_EncodeFSDefault(v);
if (v == NULL)
return NULL;
} }
else if (!PyBytes_Check(v))
continue;
else else
Py_INCREF(v); return 0;
base = PyBytes_AS_STRING(v); namelen = strlen(name);
size = PyBytes_GET_SIZE(v); base = PyBytes_AS_STRING(path_bytes);
len = size; len = PyBytes_GET_SIZE(path_bytes);
if (len + 2 + namelen + MAXSUFFIXSIZE >= buflen) { if (len + 2 + namelen + MAXSUFFIXSIZE >= buflen) {
Py_DECREF(v); Py_DECREF(path_bytes);
continue; /* Too long */ return 0; /* Too long */
} }
strcpy(buf, base); strcpy(buf, base);
Py_DECREF(v); Py_DECREF(path_bytes);
if (strlen(buf) != len) { if (strlen(buf) != len) {
continue; /* v contains '\0' */ return 0; /* path_bytes contains '\0' */
} }
/* sys.path_hooks import hook */ /* sys.path_hooks import hook */
@ -1656,9 +1652,9 @@ find_module_path_list(char *fullname, const char *name,
PyObject *importer; PyObject *importer;
importer = get_path_importer(path_importer_cache, importer = get_path_importer(path_importer_cache,
path_hooks, origv); path_hooks, path);
if (importer == NULL) { if (importer == NULL) {
return NULL; return -1;
} }
/* Note: importer is a borrowed reference */ /* Note: importer is a borrowed reference */
if (importer != Py_None) { if (importer != Py_None) {
@ -1667,14 +1663,15 @@ find_module_path_list(char *fullname, const char *name,
"find_module", "find_module",
"s", fullname); "s", fullname);
if (loader == NULL) if (loader == NULL)
return NULL; /* error */ return -1; /* error */
if (loader != Py_None) { if (loader != Py_None) {
/* a loader was found */ /* a loader was found */
*p_loader = loader; *p_loader = loader;
return &importhookdescr; *p_fd = &importhookdescr;
return 2;
} }
Py_DECREF(loader); Py_DECREF(loader);
continue; return 0;
} }
} }
/* no hook was found, use builtin import */ /* no hook was found, use builtin import */
@ -1695,22 +1692,75 @@ find_module_path_list(char *fullname, const char *name,
S_ISDIR(statbuf.st_mode) && /* it's a directory */ S_ISDIR(statbuf.st_mode) && /* it's a directory */
case_ok(buf, len, namelen, name)) { /* case matches */ case_ok(buf, len, namelen, name)) { /* case matches */
if (find_init_module(buf)) { /* and has __init__.py */ if (find_init_module(buf)) { /* and has __init__.py */
return &fd_package; *p_fd = &fd_package;
return 2;
} }
else { else {
int err; int err;
PyObject *unicode = PyUnicode_DecodeFSDefault(buf); PyObject *unicode = PyUnicode_DecodeFSDefault(buf);
if (unicode == NULL) if (unicode == NULL)
return NULL; return -1;
err = PyErr_WarnFormat(PyExc_ImportWarning, 1, err = PyErr_WarnFormat(PyExc_ImportWarning, 1,
"Not importing directory '%U': missing __init__.py", "Not importing directory '%U': missing __init__.py",
unicode); unicode);
Py_DECREF(unicode); Py_DECREF(unicode);
if (err) if (err)
return NULL; return -1;
} }
} }
#endif #endif
return 1;
}
/* Find a module in search_path_list. For each path, try
find_module_filename() or try each _PyImport_Filetab suffix.
If the module is found, return a file descriptor, write the path in
*p_filename, write the pointer to the file object into *p_fp, and (if
p_loader is not NULL) the loader into *p_loader.
Otherwise, raise an exception and return NULL. */
static struct filedescr*
find_module_path_list(char *fullname, const char *name,
PyObject *search_path_list, PyObject *path_hooks,
PyObject *path_importer_cache,
char *buf, size_t buflen,
FILE **p_fp, PyObject **p_loader)
{
Py_ssize_t i, npath;
size_t len, namelen;
struct filedescr *fdp = NULL;
char *filemode;
FILE *fp = NULL;
#if defined(PYOS_OS2)
size_t saved_len;
size_t saved_namelen;
char *saved_buf = NULL;
#endif
npath = PyList_Size(search_path_list);
namelen = strlen(name);
for (i = 0; i < npath; i++) {
PyObject *path;
int ok;
path = PyList_GetItem(search_path_list, i);
if (path == NULL)
return NULL;
ok = find_module_path(fullname, name, path,
path_hooks, path_importer_cache,
buf, buflen,
p_loader, &fdp);
if (ok < 0)
return NULL;
if (ok == 0)
continue;
if (ok == 2)
return fdp;
len = strlen(buf);
#if defined(PYOS_OS2) #if defined(PYOS_OS2)
/* take a snapshot of the module spec for restoration /* take a snapshot of the module spec for restoration
* after the 8 character DLL hackery * after the 8 character DLL hackery