First part of package support.

This doesn't yet support "import a.b.c" or "from a.b.c import x", but
it does recognize directories.  When importing a directory, it
initializes __path__ to a list containing the directory name, and
loads the __init__ module if found.

The (internal) find_module() and load_module() functions are
restructured so that they both also handle built-in and frozen modules
and Mac resources (and directories of course).  The imp module's
find_module() and (new) load_module() also have this functionality.
Moreover, imp unconditionally defines constants for all module types,
and has two more new functions: find_module_in_package() and
find_module_in_directory().

There's also a new API function, PyImport_ImportModuleEx(), which
takes all four __import__ arguments (name, globals, locals, fromlist).
The last three may be NULL.  This is currently the same as
PyImport_ImportModule() but in the future it will be able to do
relative dotted-path imports.

Other changes:

- bltinmodule.c: in __import__, call PyImport_ImportModuleEx().

- ceval.c: always pass the fromlist to __import__, even if it is a C
function, so PyImport_ImportModuleEx() is useful.

- getmtime.c: the function has a second argument, the FILE*, on which
it applies fstat().  According to Sjoerd this is much faster.  The
first (pathname) argument is ignored, but remains for backward
compatibility (so the Mac version still works without changes).

By cleverly combining the new imp functionality, the full support for
dotted names in Python (mini.py, not checked in) is now about 7K,
lavishly commented (vs. 14K for ni plus 11K for ihooks, also lavishly
commented).

Good night!
diff --git a/Python/import.c b/Python/import.c
index fe24b28..971e658 100644
--- a/Python/import.c
+++ b/Python/import.c
@@ -49,6 +49,22 @@
 #include <unistd.h>
 #endif
 
+/* We expect that stat exists on most systems.
+   It's confirmed on Unix, Mac and Windows.
+   If you don't have it, add #define DONT_HAVE_STAT to your config.h. */
+#ifndef DONT_HAVE_STAT
+#define HAVE_STAT
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifndef S_ISDIR
+#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
+#endif
+
+#endif
+
+
 extern long PyOS_GetLastModificationTime(); /* In getmtime.c */
 
 /* Magic word to reject .pyc files generated by other Python versions */
@@ -185,8 +201,8 @@
 	modules = PyImport_GetModuleDict();
 	mod = PyDict_GetItemString(modules, name);
 	if (mod == NULL || !PyModule_Check(mod)) {
-		PyErr_SetString(PyExc_SystemError,
-				"_PyImport_FixupExtension: module not loaded");
+		PyErr_Format(PyExc_SystemError,
+		  "_PyImport_FixupExtension: module %.200s not loaded", name);
 		return NULL;
 	}
 	dict = PyModule_GetDict(mod);
@@ -281,14 +297,15 @@
 	if (PyDict_SetItemString(d, "__file__",
 				 ((PyCodeObject *)co)->co_filename) != 0)
 		PyErr_Clear(); /* Not important enough to report */
-	v = PyEval_EvalCode((PyCodeObject *)co, d, d); /* XXX owner? */
+	v = PyEval_EvalCode((PyCodeObject *)co, d, d);
 	if (v == NULL)
 		return NULL;
 	Py_DECREF(v);
 
 	if ((m = PyDict_GetItemString(modules, name)) == NULL) {
-		PyErr_SetString(PyExc_SystemError,
-				"loaded module not found in sys.modules");
+		PyErr_Format(PyExc_ImportError,
+			     "Loaded module %.200s not found in sys.modules",
+			     name);
 		return NULL;
 	}
 
@@ -364,7 +381,8 @@
 /* Read a code object from a file and check it for validity */
 
 static PyCodeObject *
-read_compiled_module(fp)
+read_compiled_module(cpathname, fp)
+	char *cpathname;
 	FILE *fp;
 {
 	PyObject *co;
@@ -373,8 +391,8 @@
 	/* Ugly: rd_object() may return NULL with or without error */
 	if (co == NULL || !PyCode_Check(co)) {
 		if (!PyErr_Occurred())
-			PyErr_SetString(PyExc_ImportError,
-				   "Non-code object in .pyc file");
+			PyErr_Format(PyExc_ImportError,
+			    "Non-code object in %.200s", cpathname);
 		Py_XDECREF(co);
 		return NULL;
 	}
@@ -397,12 +415,12 @@
 
 	magic = PyMarshal_ReadLongFromFile(fp);
 	if (magic != MAGIC) {
-		PyErr_SetString(PyExc_ImportError,
-				"Bad magic number in .pyc file");
+		PyErr_Format(PyExc_ImportError,
+			     "Bad magic number in %.200s", cpathname);
 		return NULL;
 	}
 	(void) PyMarshal_ReadLongFromFile(fp);
-	co = read_compiled_module(fp);
+	co = read_compiled_module(cpathname, fp);
 	if (co == NULL)
 		return NULL;
 	if (Py_VerboseFlag)
@@ -496,11 +514,11 @@
 	PyCodeObject *co;
 	PyObject *m;
 
-	mtime = PyOS_GetLastModificationTime(pathname);
+	mtime = PyOS_GetLastModificationTime(pathname, fp);
 	cpathname = make_compiled_pathname(pathname, buf, MAXPATHLEN+1);
 	if (cpathname != NULL &&
 	    (fpc = check_compiled_module(pathname, mtime, cpathname))) {
-		co = read_compiled_module(fpc);
+		co = read_compiled_module(cpathname, fpc);
 		fclose(fpc);
 		if (co == NULL)
 			return NULL;
@@ -524,10 +542,108 @@
 }
 
 
+/* Forward */
+static PyObject *load_module Py_PROTO((char *, FILE *, char *, int));
+static struct filedescr *find_module Py_PROTO((char *, PyObject *,
+					       char *, int, FILE **));
+
+/* Load a package and return its module object WITH INCREMENTED
+   REFERENCE COUNT */
+
+static PyObject *
+load_package(name, pathname)
+	char *name;
+	char *pathname;
+{
+	PyObject *m, *d, *file, *path;
+	int err;
+	char buf[MAXPATHLEN+1];
+	FILE *fp = NULL;
+	struct filedescr *fdp;
+
+	m = PyImport_AddModule(name);
+	if (m == NULL)
+		return NULL;
+	d = PyModule_GetDict(m);
+	file = PyString_FromString(pathname);
+	if (file == NULL)
+		return NULL;
+	path = Py_BuildValue("[O]", file);
+	if (path == NULL) {
+		Py_DECREF(file);
+		return NULL;
+	}
+	err = PyDict_SetItemString(d, "__file__", file);
+	if (err == 0)
+		err = PyDict_SetItemString(d, "__path__", path);
+	if (err != 0) {
+		m = NULL;
+		goto cleanup;
+	}
+	buf[0] = '\0';
+	fdp = find_module("__init__", path, buf, sizeof(buf), &fp);
+	if (fdp == NULL) {
+		if (PyErr_ExceptionMatches(PyExc_ImportError)) {
+			PyErr_Clear();
+		}
+		else
+			m = NULL;
+		goto cleanup;
+	}
+	m = load_module(name, fp, buf, fdp->type);
+	if (fp != NULL)
+		fclose(fp);
+  cleanup:
+	Py_XINCREF(m);
+	Py_XDECREF(path);
+	Py_XDECREF(file);
+	return m;
+}
+
+
+/* Helper to test for built-in module */
+
+static int
+is_builtin(name)
+	char *name;
+{
+	int i;
+	for (i = 0; _PyImport_Inittab[i].name != NULL; i++) {
+		if (strcmp(name, _PyImport_Inittab[i].name) == 0) {
+			if (_PyImport_Inittab[i].initfunc == NULL)
+				return -1;
+			else
+				return 1;
+		}
+	}
+	return 0;
+}
+
+/* Helper to test for frozen module */
+
+static int
+is_frozen(name)
+	char *name;
+{
+	struct _frozen *p;
+	for (p = PyImport_FrozenModules; ; p++) {
+		if (p->name == NULL)
+			break;
+		if (strcmp(p->name, name) == 0)
+			return 1;
+	}
+	return 0;
+}
+
+
 /* 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. */
 
+#ifdef MS_COREDLL
+extern FILE *PyWin_FindRegisteredModule();
+#endif
+
 static struct filedescr *
 find_module(name, path, buf, buflen, p_fp)
 	char *name;
@@ -540,14 +656,26 @@
 	int i, npath, len, namelen;
 	struct filedescr *fdp = NULL;
 	FILE *fp = NULL;
+	struct stat statbuf;
+
+	if (path == NULL) {
+		if (is_builtin(name)) {
+			static struct filedescr fd = {"", "", C_BUILTIN};
+			return &fd;
+		}
+		if (is_frozen(name)) {
+			static struct filedescr fd = {"", "", PY_FROZEN};
+			return &fd;
+		}
 
 #ifdef MS_COREDLL
-	extern FILE *PyWin_FindRegisteredModule();
-	if ((fp=PyWin_FindRegisteredModule(name, &fdp, buf, buflen))!=NULL) {
-		*p_fp = fp;
-		return fdp;
-	}
+		fp = PyWin_FindRegisteredModule(name, &fdp, buf, buflen);
+		if (fp != NULL) {
+			*p_fp = fp;
+			return fdp;
+		}
 #endif
+	}
 
 
 	if (path == NULL)
@@ -580,14 +708,18 @@
 		PyString_InternInPlace(&PyList_GET_ITEM(path, i));
 		v = PyList_GET_ITEM(path, i);
 #endif
-		if ( PyMac_FindResourceModule((PyStringObject *)v, name, buf) ) {
+		if (PyMac_FindResourceModule((PyStringObject *)v, name, buf)) {
 			static struct filedescr resfiledescr =
 				{"", "", PY_RESOURCE};
 			
 			return &resfiledescr;
 		}
 #endif
-		if (len > 0 && buf[len-1] != SEP)
+		if (len > 0 && buf[len-1] != SEP
+#ifdef ALTSEP
+		    && buf[len-1] != ALTSEP
+#endif
+		    )
 			buf[len++] = SEP;
 #ifdef macintosh
 		fdp = PyMac_FindModuleExtension(buf, &len, name);
@@ -611,6 +743,15 @@
 			strcpy(buf+len, name);
 			len += namelen;
 		}
+#ifdef HAVE_STAT
+		if (stat(buf, &statbuf) == 0) {
+			static struct filedescr fd = {"", "", PKG_DIRECTORY};
+			if (S_ISDIR(statbuf.st_mode))
+				return &fd;
+		}
+#else
+		/* XXX How are you going to test for directories? */
+#endif
 		for (fdp = _PyImport_Filetab; fdp->suffix != NULL; fdp++) {
 			strcpy(buf+len, fdp->suffix);
 			if (Py_VerboseFlag > 1)
@@ -624,9 +765,8 @@
 			break;
 	}
 	if (fp == NULL) {
-		char buf[256];
-		sprintf(buf, "No module named %.200s", name);
-		PyErr_SetString(PyExc_ImportError, buf);
+		PyErr_Format(PyExc_ImportError,
+			     "No module named %.200s", name);
 		return NULL;
 	}
 
@@ -635,23 +775,35 @@
 }
 
 
+static int init_builtin Py_PROTO((char *)); /* Forward */
+
 /* Load an external module using the default search path and return
    its module object WITH INCREMENTED REFERENCE COUNT */
 
 static PyObject *
-load_module(name)
+load_module(name, fp, buf, type)
 	char *name;
+	FILE *fp;
+	char *buf;
+	int type;
 {
-	char buf[MAXPATHLEN+1];
-	struct filedescr *fdp;
-	FILE *fp = NULL;
+	PyObject *modules;
 	PyObject *m;
+	int err;
 
-	fdp = find_module(name, (PyObject *)NULL, buf, MAXPATHLEN+1, &fp);
-	if (fdp == NULL)
-		return NULL;
+	/* First check that there's an open file (if we need one)  */
+	switch (type) {
+	case PY_SOURCE:
+	case PY_COMPILED:
+		if (fp == NULL) {
+			PyErr_Format(PyExc_ValueError,
+			   "file object required for import (type code %d)",
+				     type);
+			return NULL;
+		}
+	}
 
-	switch (fdp->type) {
+	switch (type) {
 
 	case PY_SOURCE:
 		m = load_source_module(name, buf, fp);
@@ -671,14 +823,48 @@
 		break;
 #endif
 
+	case PKG_DIRECTORY:
+		m = load_package(name, buf);
+		break;
+
+	case C_BUILTIN:
+	case PY_FROZEN:
+		if (type == C_BUILTIN)
+			err = init_builtin(name);
+		else
+			err = PyImport_ImportFrozenModule(name);
+		if (err < 0)
+			goto failure;
+		if (err == 0) {
+			PyErr_Format(PyExc_ImportError,
+				     "Purported %s module %.200s not found",
+				     type == C_BUILTIN ?
+						"builtin" : "frozen",
+				     name);
+			goto failure;
+		}
+		modules = PyImport_GetModuleDict();
+		m = PyDict_GetItemString(modules, name);
+		if (m == NULL) {
+			PyErr_Format(
+				PyExc_ImportError,
+				"%s module %.200s not properly initialized",
+				type == C_BUILTIN ?
+					"builtin" : "frozen",
+				name);
+			goto failure;
+		}
+		Py_INCREF(m);
+		break;
+
 	default:
-		PyErr_SetString(PyExc_SystemError,
-			   "find_module returned unexpected result");
+	  failure:
+		PyErr_Format(PyExc_ImportError,
+			     "Don't know how to import %.200s (type code %d)",
+			      name, type);
 		m = NULL;
 
 	}
-	if ( fp )
-		fclose(fp);
 
 	return m;
 }
@@ -701,8 +887,9 @@
 	for (p = _PyImport_Inittab; p->name != NULL; p++) {
 		if (strcmp(name, p->name) == 0) {
 			if (p->initfunc == NULL) {
-				PyErr_SetString(PyExc_ImportError,
-					   "Cannot re-init internal module");
+				PyErr_Format(PyExc_ImportError,
+				    "Cannot re-init internal module %.200s",
+				    name);
 				return -1;
 			}
 			if (Py_VerboseFlag)
@@ -743,7 +930,9 @@
 	struct _frozen *p = find_frozen(name);
 
 	if (p == NULL) {
-		PyErr_SetString(PyExc_ImportError, "No such frozen object");
+		PyErr_Format(PyExc_ImportError,
+			     "No such frozen object named %.200s",
+			     name);
 		return NULL;
 	}
 	return PyMarshal_ReadObjectFromString((char *)p->code, p->size);
@@ -771,8 +960,9 @@
 		return -1;
 	if (!PyCode_Check(co)) {
 		Py_DECREF(co);
-		PyErr_SetString(PyExc_TypeError,
-				"frozen object is not a code object");
+		PyErr_Format(PyExc_TypeError,
+			     "frozen object %.200s is not a code object",
+			     name);
 		return -1;
 	}
 	m = PyImport_ExecCodeModule(name, co);
@@ -791,6 +981,16 @@
 PyImport_ImportModule(name)
 	char *name;
 {
+	return PyImport_ImportModuleEx(name, NULL, NULL, NULL);
+}
+
+PyObject *
+PyImport_ImportModuleEx(name, globals, locals, fromlist)
+	char *name;
+	PyObject *globals;
+	PyObject *locals;
+	PyObject *fromlist;
+{
 	PyObject *modules = PyImport_GetModuleDict();
 	PyObject *m;
 
@@ -798,22 +998,18 @@
 		Py_INCREF(m);
 	}
 	else {
-		int i;
-		if ((i = init_builtin(name)) ||
-		    (i = PyImport_ImportFrozenModule(name))) {
-			if (i < 0)
-				return NULL;
-			if ((m = PyDict_GetItemString(modules,
-						      name)) == NULL) {
-			    if (PyErr_Occurred() == NULL)
-			        PyErr_SetString(PyExc_SystemError,
-				 "built-in module not initialized properly");
-			}
-			else
-				Py_INCREF(m);
-		}
-		else
-			m = load_module(name);
+		char buf[MAXPATHLEN+1];
+		struct filedescr *fdp;
+		FILE *fp = NULL;
+
+		buf[0] = '\0';
+		fdp = find_module(name, (PyObject *)NULL,
+				  buf, MAXPATHLEN+1, &fp);
+		if (fdp == NULL)
+			return NULL;
+		m = load_module(name, fp, buf, fdp->type);
+		if (fp)
+			fclose(fp);
 	}
 
 	return m;
@@ -829,7 +1025,9 @@
 {
 	PyObject *modules = PyImport_GetModuleDict();
 	char *name;
-	int i;
+	char buf[MAXPATHLEN+1];
+	struct filedescr *fdp;
+	FILE *fp = NULL;
 
 	if (m == NULL || !PyModule_Check(m)) {
 		PyErr_SetString(PyExc_TypeError,
@@ -840,19 +1038,18 @@
 	if (name == NULL)
 		return NULL;
 	if (m != PyDict_GetItemString(modules, name)) {
-		PyErr_SetString(PyExc_ImportError,
-				"reload() module not in sys.modules");
+		PyErr_Format(PyExc_ImportError,
+			     "reload(): module %.200s not in sys.modules",
+			     name);
 		return NULL;
 	}
-	/* Check for built-in and frozen modules */
-	if ((i = init_builtin(name)) ||
-	    (i = PyImport_ImportFrozenModule(name))) {
-		if (i < 0)
-			return NULL;
-		Py_INCREF(m);
-	}
-	else
-		m = load_module(name);
+	buf[0] = '\0';
+	fdp = find_module(name, (PyObject *)NULL, buf, MAXPATHLEN+1, &fp);
+	if (fdp == NULL)
+		return NULL;
+	m = load_module(name, fp, buf, fdp->type);
+	if (fp)
+		fclose(fp);
 	return m;
 }
 
@@ -987,27 +1184,31 @@
 }
 
 static PyObject *
-imp_find_module(self, args)
-	PyObject *self;
-	PyObject *args;
+call_find_module(name, path)
+	char *name;
+	PyObject *path; /* list or NULL */
 {
 	extern int fclose Py_PROTO((FILE *));
-	char *name;
-	PyObject *path = NULL;
 	PyObject *fob, *ret;
 	struct filedescr *fdp;
 	char pathname[MAXPATHLEN+1];
-	FILE *fp;
-	if (!PyArg_ParseTuple(args, "s|O!", &name, &PyList_Type, &path))
-		return NULL;
+	FILE *fp = NULL;
+
+	pathname[0] = '\0';
 	fdp = find_module(name, path, pathname, MAXPATHLEN+1, &fp);
 	if (fdp == NULL)
 		return NULL;
-	fob = PyFile_FromFile(fp, pathname, fdp->mode, fclose);
-	if (fob == NULL) {
-		fclose(fp);
-		return NULL;
+	if (fp != NULL) {
+		fob = PyFile_FromFile(fp, pathname, fdp->mode, fclose);
+		if (fob == NULL) {
+			fclose(fp);
+			return NULL;
+		}
 	}
+	else {
+		fob = Py_None;
+		Py_INCREF(fob);
+	}		
 	ret = Py_BuildValue("Os(ssi)",
 		      fob, pathname, fdp->suffix, fdp->mode, fdp->type);
 	Py_DECREF(fob);
@@ -1015,6 +1216,18 @@
 }
 
 static PyObject *
+imp_find_module(self, args)
+	PyObject *self;
+	PyObject *args;
+{
+	char *name;
+	PyObject *path = NULL;
+	if (!PyArg_ParseTuple(args, "s|O!", &name, &PyList_Type, &path))
+		return NULL;
+	return call_find_module(name, path);
+}
+
+static PyObject *
 imp_init_builtin(self, args)
 	PyObject *self;
 	PyObject *args;
@@ -1075,19 +1288,10 @@
 	PyObject *self;
 	PyObject *args;
 {
-	int i;
 	char *name;
 	if (!PyArg_ParseTuple(args, "s", &name))
 		return NULL;
-	for (i = 0; _PyImport_Inittab[i].name != NULL; i++) {
-		if (strcmp(name, _PyImport_Inittab[i].name) == 0) {
-			if (_PyImport_Inittab[i].initfunc == NULL)
-				return PyInt_FromLong(-1);
-			else
-				return PyInt_FromLong(1);
-		}
-	}
-	return PyInt_FromLong(0);
+	return PyInt_FromLong(is_builtin(name));
 }
 
 static PyObject *
@@ -1095,17 +1299,10 @@
 	PyObject *self;
 	PyObject *args;
 {
-	struct _frozen *p;
 	char *name;
 	if (!PyArg_ParseTuple(args, "s", &name))
 		return NULL;
-	for (p = PyImport_FrozenModules; ; p++) {
-		if (p->name == NULL)
-			break;
-		if (strcmp(p->name, name) == 0)
-			return PyInt_FromLong(1);
-	}
-	return PyInt_FromLong(0);
+	return PyInt_FromLong(is_frozen(name));
 }
 
 static FILE *
@@ -1139,13 +1336,15 @@
 	PyObject *fob = NULL;
 	PyObject *m;
 	FILE *fp;
-	if (!PyArg_ParseTuple(args, "ssO!", &name, &pathname,
+	if (!PyArg_ParseTuple(args, "ss|O!", &name, &pathname,
 			      &PyFile_Type, &fob))
 		return NULL;
 	fp = get_file(pathname, fob, "rb");
 	if (fp == NULL)
 		return NULL;
 	m = load_compiled_module(name, pathname, fp);
+	if (fob == NULL)
+		fclose(fp);
 	return m;
 }
 
@@ -1162,8 +1361,11 @@
 	if (!PyArg_ParseTuple(args, "ss|O!", &name, &pathname,
 			      &PyFile_Type, &fob))
 		return NULL;
-	if (fob)
+	if (fob) {
 		fp = get_file(pathname, fob, "r");
+		if (fp == NULL)
+			return NULL;
+	}
 	m = _PyImport_LoadDynamicModule(name, pathname, fp);
 	return m;
 }
@@ -1178,13 +1380,15 @@
 	PyObject *fob = NULL;
 	PyObject *m;
 	FILE *fp;
-	if (!PyArg_ParseTuple(args, "ssO!", &name, &pathname,
+	if (!PyArg_ParseTuple(args, "ss|O!", &name, &pathname,
 			      &PyFile_Type, &fob))
 		return NULL;
 	fp = get_file(pathname, fob, "r");
 	if (fp == NULL)
 		return NULL;
 	m = load_source_module(name, pathname, fp);
+	if (fob == NULL)
+		fclose(fp);
 	return m;
 }
 
@@ -1206,6 +1410,55 @@
 #endif /* macintosh */
 
 static PyObject *
+imp_load_module(self, args)
+	PyObject *self;
+	PyObject *args;
+{
+	char *name;
+	PyObject *fob;
+	char *pathname;
+	char *suffix; /* Unused */
+	char *mode;
+	int type;
+	FILE *fp;
+
+	if (!PyArg_ParseTuple(args, "sOs(ssi)",
+			      &name, &fob, &pathname,
+			      &suffix, &mode, &type))
+		return NULL;
+	if (*mode && (*mode != 'r' || strchr(mode, '+') != NULL)) {
+		PyErr_Format(PyExc_ValueError,
+			     "invalid file open mode %.200s", mode);
+		return NULL;
+	}
+	if (fob == Py_None)
+		fp = NULL;
+	else {
+		if (!PyFile_Check(fob)) {
+			PyErr_SetString(PyExc_ValueError,
+				"load_module arg#2 should be a file or None");
+			return NULL;
+		}
+		fp = get_file(pathname, fob, mode);
+		if (fp == NULL)
+			return NULL;
+	}
+	return load_module(name, fp, pathname, type);
+}
+
+static PyObject *
+imp_load_package(self, args)
+	PyObject *self;
+	PyObject *args;
+{
+	char *name;
+	char *pathname;
+	if (!PyArg_ParseTuple(args, "ss", &name, &pathname))
+		return NULL;
+	return load_package(name, pathname);
+}
+
+static PyObject *
 imp_new_module(self, args)
 	PyObject *self;
 	PyObject *args;
@@ -1216,56 +1469,114 @@
 	return PyModule_New(name);
 }
 
+static PyObject *
+imp_find_module_in_package(self, args)
+	PyObject *self;
+	PyObject *args;
+{
+	PyObject *name;
+	PyObject *packagename = NULL;
+	PyObject *package;
+	PyObject *modules;
+	PyObject *path;
+
+	if (!PyArg_ParseTuple(args, "S|S", &name, &packagename))
+		return NULL;
+	if (packagename == NULL || PyString_GET_SIZE(packagename) == 0) {
+		return call_find_module(
+			PyString_AS_STRING(name),
+			(PyObject *)NULL);
+	}
+	modules = PyImport_GetModuleDict();
+	package = PyDict_GetItem(modules, packagename);
+	if (package == NULL) {
+		PyErr_Format(PyExc_ImportError,
+			     "No package named %.200s",
+			     PyString_AS_STRING(packagename));
+		return NULL;
+	}
+	path = PyObject_GetAttrString(package, "__path__");
+	if (path == NULL) {
+		PyErr_Format(PyExc_ImportError,
+			     "Package %.200s has no __path__ attribute",
+			     PyString_AS_STRING(packagename));
+		return NULL;
+	}
+	return call_find_module(PyString_AS_STRING(name), path);
+}
+
+static PyObject *
+imp_find_module_in_directory(self, args)
+	PyObject *self;
+	PyObject *args;
+{
+	PyObject *name;
+	PyObject *directory;
+	PyObject *path;
+
+	if (!PyArg_ParseTuple(args, "SS", &name, &directory))
+		return NULL;
+	path = Py_BuildValue("[O]", directory);
+	if (path == NULL)
+		return NULL;
+	return call_find_module(PyString_AS_STRING(name), path);
+}
+
 static PyMethodDef imp_methods[] = {
+	{"find_module",		imp_find_module,	1},
+	{"find_module_in_directory",	imp_find_module_in_directory,	1},
+	{"find_module_in_package",	imp_find_module_in_package,	1},
 	{"get_frozen_object",	imp_get_frozen_object,	1},
 	{"get_magic",		imp_get_magic,		1},
 	{"get_suffixes",	imp_get_suffixes,	1},
-	{"find_module",		imp_find_module,	1},
 	{"init_builtin",	imp_init_builtin,	1},
 	{"init_frozen",		imp_init_frozen,	1},
 	{"is_builtin",		imp_is_builtin,		1},
 	{"is_frozen",		imp_is_frozen,		1},
 	{"load_compiled",	imp_load_compiled,	1},
 	{"load_dynamic",	imp_load_dynamic,	1},
-	{"load_source",		imp_load_source,	1},
-	{"new_module",		imp_new_module,		1},
+	{"load_module",		imp_load_module,	1},
+	{"load_package",	imp_load_package,	1},
 #ifdef macintosh
 	{"load_resource",	imp_load_resource,	1},
 #endif
+	{"load_source",		imp_load_source,	1},
+	{"new_module",		imp_new_module,		1},
 	{NULL,			NULL}		/* sentinel */
 };
 
+int
+setint(d, name, value)
+	PyObject *d;
+	char *name;
+	int value;
+{
+	PyObject *v;
+	int err;
+
+	v = PyInt_FromLong((long)value);
+	err = PyDict_SetItemString(d, name, v);
+	Py_XDECREF(v);
+	return err;
+}
+
 void
 initimp()
 {
-	PyObject *m, *d, *v;
+	PyObject *m, *d;
 
 	m = Py_InitModule("imp", imp_methods);
 	d = PyModule_GetDict(m);
 
-	v = PyInt_FromLong(SEARCH_ERROR);
-	PyDict_SetItemString(d, "SEARCH_ERROR", v);
-	Py_XDECREF(v);
+	if (setint(d, "SEARCH_ERROR", SEARCH_ERROR) < 0) goto failure;
+	if (setint(d, "PY_SOURCE", PY_SOURCE) < 0) goto failure;
+	if (setint(d, "PY_COMPILED", PY_COMPILED) < 0) goto failure;
+	if (setint(d, "C_EXTENSION", C_EXTENSION) < 0) goto failure;
+	if (setint(d, "PY_RESOURCE", PY_RESOURCE) < 0) goto failure;
+	if (setint(d, "PKG_DIRECTORY", PKG_DIRECTORY) < 0) goto failure;
+	if (setint(d, "C_BUILTIN", C_BUILTIN) < 0) goto failure;
+	if (setint(d, "PY_FROZEN", PY_FROZEN) < 0) goto failure;
 
-	v = PyInt_FromLong(PY_SOURCE);
-	PyDict_SetItemString(d, "PY_SOURCE", v);
-	Py_XDECREF(v);
-
-	v = PyInt_FromLong(PY_COMPILED);
-	PyDict_SetItemString(d, "PY_COMPILED", v);
-	Py_XDECREF(v);
-
-	v = PyInt_FromLong(C_EXTENSION);
-	PyDict_SetItemString(d, "C_EXTENSION", v);
-	Py_XDECREF(v);
-
-#ifdef macintosh
-	v = PyInt_FromLong(PY_RESOURCE);
-	PyDict_SetItemString(d, "PY_RESOURCE", v);
-	Py_XDECREF(v);
-#endif
-
-
-	if (PyErr_Occurred())
-		Py_FatalError("imp module initialization failed");
+  failure:
+	;
 }