[Python-checkins] python/dist/src/Python import.c,2.214,2.215 importdl.h,2.18,2.19 pythonrun.c,2.171,2.172

jvr@users.sourceforge.net jvr@users.sourceforge.net
Mon, 30 Dec 2002 14:08:07 -0800


Update of /cvsroot/python/python/dist/src/Python
In directory sc8-pr-cvs1:/tmp/cvs-serv32400/Python

Modified Files:
	import.c importdl.h pythonrun.c 
Log Message:
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.


Index: import.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Python/import.c,v
retrieving revision 2.214
retrieving revision 2.215
diff -C2 -d -r2.214 -r2.215
*** import.c	25 Dec 2002 23:13:34 -0000	2.214
--- import.c	30 Dec 2002 22:08:04 -0000	2.215
***************
*** 154,157 ****
--- 154,223 ----
  
  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)
  {
***************
*** 247,250 ****
--- 313,317 ----
  	"exc_type", "exc_value", "exc_traceback",
  	"last_type", "last_value", "last_traceback",
+ 	"path_hooks", "path_importer_cache", "meta_path",
  	NULL
  };
***************
*** 809,815 ****
  
  /* Forward */
! static PyObject *load_module(char *, FILE *, char *, int);
! static struct filedescr *find_module(char *, PyObject *,
! 				     char *, size_t, FILE **);
  static struct _frozen *find_frozen(char *name);
  
--- 876,882 ----
  
  /* Forward */
! 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);
  
***************
*** 849,853 ****
  	}
  	buf[0] = '\0';
! 	fdp = find_module("__init__", path, buf, sizeof(buf), &fp);
  	if (fdp == NULL) {
  		if (PyErr_ExceptionMatches(PyExc_ImportError)) {
--- 916,920 ----
  	}
  	buf[0] = '\0';
! 	fdp = find_module(name, "__init__", path, buf, sizeof(buf), &fp, NULL);
  	if (fdp == NULL) {
  		if (PyErr_ExceptionMatches(PyExc_ImportError)) {
***************
*** 858,862 ****
  		goto cleanup;
  	}
! 	m = load_module(name, fp, buf, fdp->type);
  	if (fp != NULL)
  		fclose(fp);
--- 925,929 ----
  		goto cleanup;
  	}
! 	m = load_module(name, fp, buf, fdp->type, NULL);
  	if (fp != NULL)
  		fclose(fp);
***************
*** 886,889 ****
--- 953,1011 ----
  
  
+ /* 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
***************
*** 897,904 ****
  static int case_ok(char *, int, int, char *);
  static int find_init_module(char *); /* Forward */
  
  static struct filedescr *
! find_module(char *realname, PyObject *path, char *buf, size_t buflen,
! 	    FILE **p_fp)
  {
  	int i, npath;
--- 1019,1027 ----
  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 *fullname, char *subname, PyObject *path, char *buf,
! 	    size_t buflen, FILE **p_fp, PyObject **p_loader)
  {
  	int i, npath;
***************
*** 907,910 ****
--- 1030,1034 ----
  	char *filemode;
  	FILE *fp = NULL;
+ 	PyObject *path_hooks, *path_importer_cache;
  #ifndef RISCOS
  	struct stat statbuf;
***************
*** 919,929 ****
  	char *saved_buf = NULL;
  #endif
  
! 	if (strlen(realname) > MAXPATHLEN) {
  		PyErr_SetString(PyExc_OverflowError,
  				"module name is too long");
  		return NULL;
  	}
! 	strcpy(name, realname);
  
  	if (path != NULL && PyString_Check(path)) {
--- 1043,1090 ----
  	char *saved_buf = NULL;
  #endif
+ 	if (p_loader != NULL)
+ 		*p_loader = NULL;
  
! 	if (strlen(subname) > MAXPATHLEN) {
  		PyErr_SetString(PyExc_OverflowError,
  				"module name is too long");
  		return NULL;
  	}
! 	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)) {
***************
*** 979,982 ****
--- 1140,1159 ----
  		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);
***************
*** 1006,1009 ****
--- 1183,1213 ----
  			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
  		/*
***************
*** 1080,1084 ****
  			 * truncate the name before trying
  			 */
! 			if (strlen(realname) > 8) {
  				/* is this an attempt to load a C extension? */
  				const struct filedescr *scan;
--- 1284,1288 ----
  			 * truncate the name before trying
  			 */
! 			if (strlen(subname) > 8) {
  				/* is this an attempt to load a C extension? */
  				const struct filedescr *scan;
***************
*** 1093,1097 ****
  					/* yes, so truncate the name */
  					namelen = 8;
! 					len -= strlen(realname) - namelen;
  					buf[len] = '\0';
  				}
--- 1297,1301 ----
  					/* yes, so truncate the name */
  					namelen = 8;
! 					len -= strlen(subname) - namelen;
  					buf[len] = '\0';
  				}
***************
*** 1445,1449 ****
  
  static PyObject *
! load_module(char *name, FILE *fp, char *buf, int type)
  {
  	PyObject *modules;
--- 1649,1653 ----
  
  static PyObject *
! load_module(char *name, FILE *fp, char *buf, int type, PyObject *loader)
  {
  	PyObject *modules;
***************
*** 1524,1527 ****
--- 1728,1741 ----
  		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,
***************
*** 1979,1983 ****
  	}
  	else {
! 		PyObject *path;
  		char buf[MAXPATHLEN+1];
  		struct filedescr *fdp;
--- 2193,2197 ----
  	}
  	else {
! 		PyObject *path, *loader = NULL;
  		char buf[MAXPATHLEN+1];
  		struct filedescr *fdp;
***************
*** 1996,2000 ****
  
  		buf[0] = '\0';
! 		fdp = find_module(subname, path, buf, MAXPATHLEN+1, &fp);
  		Py_XDECREF(path);
  		if (fdp == NULL) {
--- 2210,2215 ----
  
  		buf[0] = '\0';
! 		fdp = find_module(fullname, subname, path, buf, MAXPATHLEN+1,
! 				  &fp, &loader);
  		Py_XDECREF(path);
  		if (fdp == NULL) {
***************
*** 2005,2009 ****
  			return Py_None;
  		}
! 		m = load_module(fullname, fp, buf, fdp->type);
  		if (fp)
  			fclose(fp);
--- 2220,2225 ----
  			return Py_None;
  		}
! 		m = load_module(fullname, fp, buf, fdp->type, loader);
! 		Py_XDECREF(loader);
  		if (fp)
  			fclose(fp);
***************
*** 2081,2089 ****
  	}
  	buf[0] = '\0';
! 	fdp = find_module(subname, path, buf, MAXPATHLEN+1, &fp);
  	Py_XDECREF(path);
  	if (fdp == NULL)
  		return NULL;
! 	m = load_module(name, fp, buf, fdp->type);
  	if (fp)
  		fclose(fp);
--- 2297,2305 ----
  	}
  	buf[0] = '\0';
! 	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, NULL);
  	if (fp)
  		fclose(fp);
***************
*** 2229,2233 ****
  	if (path == Py_None)
  		path = NULL;
! 	fdp = find_module(name, path, pathname, MAXPATHLEN+1, &fp);
  	if (fdp == NULL)
  		return NULL;
--- 2445,2449 ----
  	if (path == Py_None)
  		path = NULL;
! 	fdp = find_module(NULL, name, path, pathname, MAXPATHLEN+1, &fp, NULL);
  	if (fdp == NULL)
  		return NULL;
***************
*** 2466,2470 ****
  			return NULL;
  	}
! 	return load_module(name, fp, pathname, type);
  }
  
--- 2682,2686 ----
  			return NULL;
  	}
! 	return load_module(name, fp, pathname, type, NULL);
  }
  
***************
*** 2580,2583 ****
--- 2796,2800 ----
  	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:

Index: importdl.h
===================================================================
RCS file: /cvsroot/python/python/dist/src/Python/importdl.h,v
retrieving revision 2.18
retrieving revision 2.19
diff -C2 -d -r2.18 -r2.19
*** importdl.h	26 Feb 2002 11:41:34 -0000	2.18
--- importdl.h	30 Dec 2002 22:08:05 -0000	2.19
***************
*** 17,21 ****
  	C_BUILTIN,
  	PY_FROZEN,
! 	PY_CODERESOURCE /* Mac only */
  };
  
--- 17,22 ----
  	C_BUILTIN,
  	PY_FROZEN,
! 	PY_CODERESOURCE, /* Mac only */
! 	IMP_HOOK
  };
  

Index: pythonrun.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Python/pythonrun.c,v
retrieving revision 2.171
retrieving revision 2.172
diff -C2 -d -r2.171 -r2.172
*** pythonrun.c	13 Dec 2002 15:23:00 -0000	2.171
--- pythonrun.c	30 Dec 2002 22:08:05 -0000	2.172
***************
*** 162,165 ****
--- 162,167 ----
  	_PyImport_FixupExtension("__builtin__", "__builtin__");
  
+ 	_PyImportHooks_Init();
+ 
  	initsigs(); /* Signal handling stuff, including initintr() */