]> granicus.if.org Git - python/commitdiff
Bug #1529871: The speed enhancement patch #921466 broke Python's compliance
authorPhillip J. Eby <pje@telecommunity.com>
Fri, 28 Jul 2006 21:12:07 +0000 (21:12 +0000)
committerPhillip J. Eby <pje@telecommunity.com>
Fri, 28 Jul 2006 21:12:07 +0000 (21:12 +0000)
with PEP 302.  This was fixed by adding an ``imp.NullImporter`` type that is
used in ``sys.path_importer_cache`` to cache non-directory paths and avoid
excessive filesystem operations during imports.

Doc/lib/libimp.tex
Lib/pkgutil.py
Misc/NEWS
Python/import.c

index e0a775cad11bc2e51c19104fb6e8f6a88cd7be55..598d3518274b1987dd2625876ec627d4b456825a 100644 (file)
@@ -232,6 +232,24 @@ properly matching byte-compiled file (with suffix \file{.pyc} or
 source file.
 \end{funcdesc}
 
+\begin{classdesc}{NullImporter}{path_string}
+The \class{NullImporter} type is a \pep{302} import hook that handles
+non-directory path strings by failing to find any modules.  Calling this
+type with an existing directory or empty string raises
+\exception{ImportError}.  Otherwise, a \class{NullImporter} instance is
+returned.
+
+Python adds instances of this type to \code{sys.path_importer_cache} for
+any path entries that are not directories and are not handled by any other
+path hooks on \code{sys.path_hooks}.  Instances have only one method:
+
+\begin{methoddesc}{find_module}{fullname \optional{, path}}
+This method always returns \code{None}, indicating that the requested
+module could not be found.
+\end{methoddesc}
+
+\versionadded{2.5}
+\end{classdesc}
 
 \subsection{Examples}
 \label{examples-imp}
@@ -257,7 +275,7 @@ def __import__(name, globals=None, locals=None, fromlist=None):
     # there's a problem we can't handle -- let the caller handle it.
 
     fp, pathname, description = imp.find_module(name)
-    
+
     try:
         return imp.load_module(name, fp, pathname, description)
     finally:
index f4347e5e5446db68db20341242a91f8479105099..37738e4a75d27493b0f373122b5f28d7595c96f9 100644 (file)
@@ -381,9 +381,7 @@ def get_importer(path_item):
             importer = None
         sys.path_importer_cache.setdefault(path_item, importer)
 
-    # The boolean values are used for caching valid and invalid
-    # file paths for the built-in import machinery
-    if importer in (None, True, False):
+    if importer is None:
         try:
             importer = ImpImporter(path_item)
         except ImportError:
index d874115d12b91bf724dec2f0fa9862fd03dd86a4..6dce888c117e94728c56dfa86bae43588d2c2a82 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -12,6 +12,11 @@ What's New in Python 2.5 release candidate 1?
 Core and builtins
 -----------------
 
+- Bug #1529871: The speed enhancement patch #921466 broke Python's compliance
+  with PEP 302.  This was fixed by adding an ``imp.NullImporter`` type that is
+  used in ``sys.path_importer_cache`` to cache non-directory paths and avoid
+  excessive filesystem operations during imports.
+
 - Bug #1521947: When checking for overflow, ``PyOS_strtol()`` used some
   operations on signed longs that are formally undefined by C.
   Unfortunately, at least one compiler now cares about that, so complicated
@@ -106,10 +111,14 @@ Library
 Extension Modules
 -----------------
 
+<<<<<<< .mine
+- Bug #1471938: Fix curses module build problem on Solaris 8; patch by
+=======
 - The ``__reduce__()`` method of the new ``collections.defaultdict`` had
   a memory leak, affecting pickles and deep copies.
 
 - Bug #1471938: Fix curses module build problem on Solaris 8; patch by
+>>>>>>> .r50915
   Paul Eggert.
 
 - Patch #1448199: Release interpreter lock in _winreg.ConnectRegistry.
index 7f79aee3a9de900dca712e95f6585802a83bb5c0..ef64b21b38380e277ccec7d87e6e01f0fda40ceb 100644 (file)
@@ -98,6 +98,8 @@ static const struct filedescr _PyImport_StandardFiletab[] = {
 };
 #endif
 
+static PyTypeObject NullImporterType;  /* Forward reference */
+
 /* Initialize things */
 
 void
@@ -155,6 +157,8 @@ _PyImportHooks_Init(void)
 
        /* adding sys.path_hooks and sys.path_importer_cache, setting up
           zipimport */
+       if (PyType_Ready(&NullImporterType) < 0)
+               goto error;
 
        if (Py_VerboseFlag)
                PySys_WriteStderr("# installing zipimport hook\n");
@@ -180,9 +184,11 @@ _PyImportHooks_Init(void)
        if (err) {
   error:
                PyErr_Print();
-               Py_FatalError("initializing sys.meta_path, sys.path_hooks or "
-                             "path_importer_cache failed");
+               Py_FatalError("initializing sys.meta_path, sys.path_hooks, "
+                             "path_importer_cache, or NullImporter failed"
+                             );
        }
+
        zimpimport = PyImport_ImportModule("zipimport");
        if (zimpimport == NULL) {
                PyErr_Clear(); /* No zip import module -- okay */
@@ -1058,9 +1064,18 @@ get_path_importer(PyObject *path_importer_cache, PyObject *path_hooks,
                }
                PyErr_Clear();
        }
-       if (importer == NULL)
-               importer = Py_None;
-       else if (importer != Py_None) {
+       if (importer == NULL) {
+               importer = PyObject_CallFunctionObjArgs(
+                       (PyObject *)&NullImporterType, p, NULL
+               );
+               if (importer == NULL) {
+                       if (PyErr_ExceptionMatches(PyExc_ImportError)) {
+                               PyErr_Clear();
+                               return Py_None;
+                       }
+               }
+       }
+       if (importer != NULL) {
                int err = PyDict_SetItem(path_importer_cache, p, importer);
                Py_DECREF(importer);
                if (err != 0)
@@ -1248,35 +1263,7 @@ find_module(char *fullname, char *subname, PyObject *path, char *buf,
                                return NULL;
                        }
                        /* Note: importer is a borrowed reference */
-                       if (importer == Py_False) {
-                               /* Cached as not being a valid dir. */
-                               Py_XDECREF(copy);
-                               continue;
-                       }
-                       else if (importer == Py_True) {
-                               /* Cached as being a valid dir, so just
-                                * continue below. */
-                       }
-                       else if (importer == Py_None) {
-                               /* No importer was found, so it has to be a file.
-                                * Check if the directory is valid.
-                                * Note that the empty string is a valid path, but
-                                * not stat'able, hence the check for len. */
-#ifdef HAVE_STAT
-                               if (len && stat(buf, &statbuf) != 0) {
-                                       /* Directory does not exist. */
-                                       PyDict_SetItem(path_importer_cache,
-                                                      v, Py_False);
-                                       Py_XDECREF(copy);
-                                       continue;
-                               } else {
-                                       PyDict_SetItem(path_importer_cache,
-                                                      v, Py_True);
-                               }
-#endif
-                       }
-                       else {
-                               /* A real import hook importer was found. */
+                       if (importer != Py_None) {
                                PyObject *loader;
                                loader = PyObject_CallMethod(importer,
                                                             "find_module",
@@ -2935,11 +2922,120 @@ setint(PyObject *d, char *name, int value)
        return err;
 }
 
+typedef struct {
+    PyObject_HEAD
+} NullImporter;
+
+static int
+NullImporter_init(NullImporter *self, PyObject *args, PyObject *kwds)
+{
+       char *path;
+
+       if (!_PyArg_NoKeywords("NullImporter()", kwds))
+               return -1;
+
+       if (!PyArg_ParseTuple(args, "s:NullImporter",
+                             &path))
+               return -1;
+
+       if (strlen(path) == 0) {
+               PyErr_SetString(PyExc_ImportError, "empty pathname");
+               return -1;
+       } else {
+#ifndef RISCOS
+               struct stat statbuf;
+               int rv;
+
+               rv = stat(path, &statbuf);
+               if (rv == 0) {
+                       /* it exists */
+                       if (S_ISDIR(statbuf.st_mode)) {
+                               /* it's a directory */
+                               PyErr_SetString(PyExc_ImportError,
+                                               "existing directory");
+                               return -1;
+                       }
+               }
+#else
+               if (object_exists(path)) {
+                       /* it exists */
+                       if (isdir(path)) {
+                               /* it's a directory */
+                               PyErr_SetString(PyExc_ImportError,
+                                               "existing directory");
+                               return -1;
+                       }
+               }
+#endif
+       }
+       return 0;
+}
+
+static PyObject *
+NullImporter_find_module(NullImporter *self, PyObject *args)
+{
+       Py_RETURN_NONE;
+}
+
+static PyMethodDef NullImporter_methods[] = {
+       {"find_module", (PyCFunction)NullImporter_find_module, METH_VARARGS,
+        "Always return None"
+       },
+       {NULL}  /* Sentinel */
+};
+
+
+static PyTypeObject NullImporterType = {
+       PyObject_HEAD_INIT(NULL)
+       0,                         /*ob_size*/
+       "imp.NullImporter",        /*tp_name*/
+       sizeof(NullImporter),      /*tp_basicsize*/
+       0,                         /*tp_itemsize*/
+       0,                         /*tp_dealloc*/
+       0,                         /*tp_print*/
+       0,                         /*tp_getattr*/
+       0,                         /*tp_setattr*/
+       0,                         /*tp_compare*/
+       0,                         /*tp_repr*/
+       0,                         /*tp_as_number*/
+       0,                         /*tp_as_sequence*/
+       0,                         /*tp_as_mapping*/
+       0,                         /*tp_hash */
+       0,                         /*tp_call*/
+       0,                         /*tp_str*/
+       0,                         /*tp_getattro*/
+       0,                         /*tp_setattro*/
+       0,                         /*tp_as_buffer*/
+       Py_TPFLAGS_DEFAULT,        /*tp_flags*/
+       "Null importer object",    /* tp_doc */
+       0,                         /* tp_traverse */
+       0,                         /* tp_clear */
+       0,                         /* tp_richcompare */
+       0,                         /* tp_weaklistoffset */
+       0,                         /* tp_iter */
+       0,                         /* tp_iternext */
+       NullImporter_methods,      /* tp_methods */
+       0,                         /* tp_members */
+       0,                         /* tp_getset */
+       0,                         /* tp_base */
+       0,                         /* tp_dict */
+       0,                         /* tp_descr_get */
+       0,                         /* tp_descr_set */
+       0,                         /* tp_dictoffset */
+       (initproc)NullImporter_init,      /* tp_init */
+       0,                         /* tp_alloc */
+       PyType_GenericNew          /* tp_new */
+};
+
+
 PyMODINIT_FUNC
 initimp(void)
 {
        PyObject *m, *d;
 
+       if (PyType_Ready(&NullImporterType) < 0)
+               goto failure;
+
        m = Py_InitModule4("imp", imp_methods, doc_imp,
                           NULL, PYTHON_API_VERSION);
        if (m == NULL)
@@ -2957,6 +3053,8 @@ initimp(void)
        if (setint(d, "PY_CODERESOURCE", PY_CODERESOURCE) < 0) goto failure;
        if (setint(d, "IMP_HOOK", IMP_HOOK) < 0) goto failure;
 
+       Py_INCREF(&NullImporterType);
+       PyModule_AddObject(m, "NullImporter", (PyObject *)&NullImporterType);
   failure:
        ;
 }