diff options
author | Just van Rossum <just@letterror.com> | 2002-12-30 22:08:05 (GMT) |
---|---|---|
committer | Just van Rossum <just@letterror.com> | 2002-12-30 22:08:05 (GMT) |
commit | 52e14d640be3a7fa2c17f5a2a6bc9626d622aa40 (patch) | |
tree | 417c361ba0bae8b22b262570769933ccdd5ad5e0 /Python | |
parent | 60087fb45092d9c199cea162e58d9193c7c1558c (diff) | |
download | cpython-52e14d640be3a7fa2c17f5a2a6bc9626d622aa40.zip cpython-52e14d640be3a7fa2c17f5a2a6bc9626d622aa40.tar.gz cpython-52e14d640be3a7fa2c17f5a2a6bc9626d622aa40.tar.bz2 |
PEP 302 + zipimport:
- new import hooks in import.c, exposed in the sys module
- new module called 'zipimport'
- various changes to allow bootstrapping from zip files
I hope I didn't break the Windows build (or anything else for that
matter), but then again, it's been sitting on sf long enough...
Regarding the latest discussions on python-dev: zipimport sets
pkg.__path__ as specified in PEP 273, and likewise, sys.path item such as
/path/to/Archive.zip/subdir/ are supported again.
Diffstat (limited to 'Python')
-rw-r--r-- | Python/import.c | 255 | ||||
-rw-r--r-- | Python/importdl.h | 3 | ||||
-rw-r--r-- | Python/pythonrun.c | 2 |
3 files changed, 240 insertions, 20 deletions
diff --git a/Python/import.c b/Python/import.c index 9b3944a..5df1f0a 100644 --- a/Python/import.c +++ b/Python/import.c @@ -153,6 +153,72 @@ _PyImport_Init(void) } void +_PyImportHooks_Init(void) +{ + PyObject *v, *path_hooks = NULL, *zimpimport; + int err = 0; + + /* adding sys.path_hooks and sys.path_importer_cache, setting up + zipimport */ + + if (Py_VerboseFlag) + PySys_WriteStderr("# installing zipimport hook\n"); + + v = PyList_New(0); + if (v == NULL) + goto error; + err = PySys_SetObject("meta_path", v); + Py_DECREF(v); + if (err) + goto error; + v = PyDict_New(); + if (v == NULL) + goto error; + err = PySys_SetObject("path_importer_cache", v); + Py_DECREF(v); + if (err) + goto error; + path_hooks = PyList_New(0); + if (path_hooks == NULL) + goto error; + err = PySys_SetObject("path_hooks", path_hooks); + if (err) { + error: + PyErr_Print(); + Py_FatalError("initializing sys.meta_path, sys.path_hooks or " + "path_importer_cache failed"); + } + zimpimport = PyImport_ImportModule("zipimport"); + if (zimpimport == NULL) { + PyErr_Clear(); /* No zip import module -- okay */ + if (Py_VerboseFlag) + PySys_WriteStderr("# can't import zipimport\n"); + } + else { + PyObject *zipimporter = PyObject_GetAttrString(zimpimport, + "zipimporter"); + Py_DECREF(zimpimport); + if (zipimporter == NULL) { + PyErr_Clear(); /* No zipimporter object -- okay */ + if (Py_VerboseFlag) + PySys_WriteStderr( + "# can't import zipimport.zimimporter\n"); + } + else { + /* sys.path_hooks.append(zipimporter) */ + err = PyList_Append(path_hooks, zipimporter); + Py_DECREF(zipimporter); + if (err) + goto error; + if (Py_VerboseFlag) + PySys_WriteStderr( + "# installed zipimport hook\n"); + } + } + Py_DECREF(path_hooks); +} + +void _PyImport_Fini(void) { Py_XDECREF(extensions); @@ -246,6 +312,7 @@ static char* sys_deletes[] = { "path", "argv", "ps1", "ps2", "exitfunc", "exc_type", "exc_value", "exc_traceback", "last_type", "last_value", "last_traceback", + "path_hooks", "path_importer_cache", "meta_path", NULL }; @@ -808,9 +875,9 @@ load_source_module(char *name, char *pathname, FILE *fp) /* Forward */ -static PyObject *load_module(char *, FILE *, char *, int); -static struct filedescr *find_module(char *, PyObject *, - char *, size_t, FILE **); +static PyObject *load_module(char *, FILE *, char *, int, PyObject *); +static struct filedescr *find_module(char *, char *, PyObject *, + char *, size_t, FILE **, PyObject **); static struct _frozen *find_frozen(char *name); /* Load a package and return its module object WITH INCREMENTED @@ -848,7 +915,7 @@ load_package(char *name, char *pathname) goto cleanup; } buf[0] = '\0'; - fdp = find_module("__init__", path, buf, sizeof(buf), &fp); + fdp = find_module(name, "__init__", path, buf, sizeof(buf), &fp, NULL); if (fdp == NULL) { if (PyErr_ExceptionMatches(PyExc_ImportError)) { PyErr_Clear(); @@ -857,7 +924,7 @@ load_package(char *name, char *pathname) m = NULL; goto cleanup; } - m = load_module(name, fp, buf, fdp->type); + m = load_module(name, fp, buf, fdp->type, NULL); if (fp != NULL) fclose(fp); cleanup: @@ -885,6 +952,61 @@ is_builtin(char *name) } +/* Return an importer object for a sys.path/pkg.__path__ item 'p', + possibly by fetching it from the path_importer_cache dict. If it + wasn't yet cached, traverse path_hooks until it a hook is found + that can handle the path item. Return None if no hook could; + this tells our caller it should fall back to the builtin + import mechanism. Cache the result in path_importer_cache. + Returns a borrowed reference. */ + +static PyObject * +get_path_importer(PyObject *path_importer_cache, PyObject *path_hooks, + PyObject *p) +{ + PyObject *importer; + int j, nhooks; + + /* These conditions are the caller's responsibility: */ + assert(PyList_Check(path_hooks)); + assert(PyDict_Check(path_importer_cache)); + + nhooks = PyList_Size(path_hooks); + if (nhooks < 0) + return NULL; /* Shouldn't happen */ + + importer = PyDict_GetItem(path_importer_cache, p); + if (importer != NULL) + return importer; + + /* set path_importer_cache[p] to None to avoid recursion */ + if (PyDict_SetItem(path_importer_cache, p, Py_None) != 0) + return NULL; + + for (j = 0; j < nhooks; j++) { + PyObject *hook = PyList_GetItem(path_hooks, j); + if (hook == NULL) + return NULL; + importer = PyObject_CallFunction(hook, "O", p); + if (importer != NULL) + break; + + if (!PyErr_ExceptionMatches(PyExc_ImportError)) { + return NULL; + } + PyErr_Clear(); + } + if (importer == NULL) + importer = Py_None; + else if (importer != Py_None) { + int err = PyDict_SetItem(path_importer_cache, p, importer); + Py_DECREF(importer); + if (err != 0) + return NULL; + } + return importer; +} + /* Search the path (default sys.path) for a module. Return the corresponding filedescr struct, and (via return arguments) the pathname and an open file. Return NULL if the module is not found. */ @@ -896,16 +1018,18 @@ extern FILE *PyWin_FindRegisteredModule(const char *, struct filedescr **, static int case_ok(char *, int, int, char *); static int find_init_module(char *); /* Forward */ +static struct filedescr importhookdescr = {"", "", IMP_HOOK}; static struct filedescr * -find_module(char *realname, PyObject *path, char *buf, size_t buflen, - FILE **p_fp) +find_module(char *fullname, char *subname, PyObject *path, char *buf, + size_t buflen, FILE **p_fp, PyObject **p_loader) { int i, npath; size_t len, namelen; struct filedescr *fdp = NULL; char *filemode; FILE *fp = NULL; + PyObject *path_hooks, *path_importer_cache; #ifndef RISCOS struct stat statbuf; #endif @@ -918,13 +1042,50 @@ find_module(char *realname, PyObject *path, char *buf, size_t buflen, size_t saved_namelen; char *saved_buf = NULL; #endif + if (p_loader != NULL) + *p_loader = NULL; - if (strlen(realname) > MAXPATHLEN) { + if (strlen(subname) > MAXPATHLEN) { PyErr_SetString(PyExc_OverflowError, "module name is too long"); return NULL; } - strcpy(name, realname); + strcpy(name, subname); + + /* 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, + "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", + "sO", fullname, + path != NULL ? + path : 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 (path != NULL && PyString_Check(path)) { /* The only type of submodule allowed inside a "frozen" @@ -978,6 +1139,22 @@ find_module(char *realname, PyObject *path, char *buf, size_t buflen, "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, + "sys.path_hooks must be a list of " + "import hooks"); + return NULL; + } + path_importer_cache = PySys_GetObject("path_importer_cache"); + if (path_importer_cache == NULL || + !PyDict_Check(path_importer_cache)) { + PyErr_SetString(PyExc_ImportError, + "sys.path_importer_cache must be a dict"); + return NULL; + } + npath = PyList_Size(path); namelen = strlen(name); for (i = 0; i < npath; i++) { @@ -1005,6 +1182,33 @@ find_module(char *realname, PyObject *path, char *buf, size_t buflen, Py_XDECREF(copy); continue; /* v contains '\0' */ } + + /* sys.path_hooks import hook */ + if (p_loader != NULL) { + PyObject *importer; + + importer = get_path_importer(path_importer_cache, + path_hooks, v); + if (importer == NULL) + return NULL; + /* Note: importer is a borrowed reference */ + if (importer != Py_None) { + PyObject *loader; + loader = PyObject_CallMethod(importer, + "find_module", + "s", fullname); + if (loader == NULL) + return NULL; /* error */ + if (loader != Py_None) { + /* a loader was found */ + *p_loader = loader; + return &importhookdescr; + } + Py_DECREF(loader); + } + /* no hook was successful, use builtin import */ + } + #ifdef macintosh /* ** Speedup: each sys.path item is interned, and @@ -1079,7 +1283,7 @@ find_module(char *realname, PyObject *path, char *buf, size_t buflen, * dynamically loaded module we're going to try, * truncate the name before trying */ - if (strlen(realname) > 8) { + if (strlen(subname) > 8) { /* is this an attempt to load a C extension? */ const struct filedescr *scan; scan = _PyImport_DynLoadFiletab; @@ -1092,7 +1296,7 @@ find_module(char *realname, PyObject *path, char *buf, size_t buflen, if (scan->suffix != NULL) { /* yes, so truncate the name */ namelen = 8; - len -= strlen(realname) - namelen; + len -= strlen(subname) - namelen; buf[len] = '\0'; } } @@ -1444,7 +1648,7 @@ static int init_builtin(char *); /* Forward */ its module object WITH INCREMENTED REFERENCE COUNT */ static PyObject * -load_module(char *name, FILE *fp, char *buf, int type) +load_module(char *name, FILE *fp, char *buf, int type, PyObject *loader) { PyObject *modules; PyObject *m; @@ -1523,6 +1727,16 @@ load_module(char *name, FILE *fp, char *buf, int type) Py_INCREF(m); break; + case IMP_HOOK: { + if (loader == NULL) { + PyErr_SetString(PyExc_ImportError, + "import hook without loader"); + return NULL; + } + m = PyObject_CallMethod(loader, "load_module", "s", name); + break; + } + default: PyErr_Format(PyExc_ImportError, "Don't know how to import %.200s (type code %d)", @@ -1978,7 +2192,7 @@ import_submodule(PyObject *mod, char *subname, char *fullname) Py_INCREF(m); } else { - PyObject *path; + PyObject *path, *loader = NULL; char buf[MAXPATHLEN+1]; struct filedescr *fdp; FILE *fp = NULL; @@ -1995,7 +2209,8 @@ import_submodule(PyObject *mod, char *subname, char *fullname) } buf[0] = '\0'; - fdp = find_module(subname, path, buf, MAXPATHLEN+1, &fp); + fdp = find_module(fullname, subname, path, buf, MAXPATHLEN+1, + &fp, &loader); Py_XDECREF(path); if (fdp == NULL) { if (!PyErr_ExceptionMatches(PyExc_ImportError)) @@ -2004,7 +2219,8 @@ import_submodule(PyObject *mod, char *subname, char *fullname) Py_INCREF(Py_None); return Py_None; } - m = load_module(fullname, fp, buf, fdp->type); + m = load_module(fullname, fp, buf, fdp->type, loader); + Py_XDECREF(loader); if (fp) fclose(fp); if (mod != Py_None) { @@ -2080,11 +2296,11 @@ PyImport_ReloadModule(PyObject *m) PyErr_Clear(); } buf[0] = '\0'; - fdp = find_module(subname, path, buf, MAXPATHLEN+1, &fp); + fdp = find_module(name, subname, path, buf, MAXPATHLEN+1, &fp, NULL); Py_XDECREF(path); if (fdp == NULL) return NULL; - m = load_module(name, fp, buf, fdp->type); + m = load_module(name, fp, buf, fdp->type, NULL); if (fp) fclose(fp); return m; @@ -2228,7 +2444,7 @@ call_find_module(char *name, PyObject *path) pathname[0] = '\0'; if (path == Py_None) path = NULL; - fdp = find_module(name, path, pathname, MAXPATHLEN+1, &fp); + fdp = find_module(NULL, name, path, pathname, MAXPATHLEN+1, &fp, NULL); if (fdp == NULL) return NULL; if (fp != NULL) { @@ -2465,7 +2681,7 @@ imp_load_module(PyObject *self, PyObject *args) if (fp == NULL) return NULL; } - return load_module(name, fp, pathname, type); + return load_module(name, fp, pathname, type, NULL); } static PyObject * @@ -2579,6 +2795,7 @@ initimp(void) if (setint(d, "C_BUILTIN", C_BUILTIN) < 0) goto failure; if (setint(d, "PY_FROZEN", PY_FROZEN) < 0) goto failure; if (setint(d, "PY_CODERESOURCE", PY_CODERESOURCE) < 0) goto failure; + if (setint(d, "IMP_HOOK", IMP_HOOK) < 0) goto failure; failure: ; diff --git a/Python/importdl.h b/Python/importdl.h index 8e04f28..5a2d45c 100644 --- a/Python/importdl.h +++ b/Python/importdl.h @@ -16,7 +16,8 @@ enum filetype { PKG_DIRECTORY, C_BUILTIN, PY_FROZEN, - PY_CODERESOURCE /* Mac only */ + PY_CODERESOURCE, /* Mac only */ + IMP_HOOK }; struct filedescr { diff --git a/Python/pythonrun.c b/Python/pythonrun.c index a31c2d9..7469cb8 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -161,6 +161,8 @@ Py_Initialize(void) /* phase 2 of builtins */ _PyImport_FixupExtension("__builtin__", "__builtin__"); + _PyImportHooks_Init(); + initsigs(); /* Signal handling stuff, including initintr() */ initmain(); /* Module __main__ */ |