diff Python/import.c @ 68887:5deb2094f033

Make importlib compatible with __import__ by "fixing" code.co_filename paths. __import__ does a little trick when importing from bytecode by back-patching the co_filename paths to point to the file location where the code object was loaded from, *not* where the code object was originally created. This allows co_filename to point to a valid path. Problem is that co_filename is immutable from Python, so a private function -- imp._fix_co_filename() -- had to be introduced in order to get things working properly. Originally the plan was to add a file argument to marshal.loads(), but that failed as the algorithm used by __import__ is not fully recursive as one might expect, so to be fully backwards-compatible the code used by __import__ needed to be exposed. This closes issue #6811 by taking a different approach than outlined in the issue.
author Brett Cannon <brett@python.org>
date Wed, 23 Mar 2011 16:14:42 -0700
parents 3114f26d5d54
children 7b8d625eb6e4
line wrap: on
line diff
--- a/Python/import.c	Wed Mar 23 16:06:00 2011 -0700
+++ b/Python/import.c	Wed Mar 23 16:14:42 2011 -0700
@@ -1374,6 +1374,32 @@
     Py_DECREF(oldname);
 }
 
+static PyObject *
+imp_fix_co_filename(PyObject *self, PyObject *args)
+{
+    PyObject *co;
+    PyObject *file_path;
+
+    if (!PyArg_ParseTuple(args, "OO:_fix_co_filename", &co, &file_path))
+        return NULL;
+
+    if (!PyCode_Check(co)) {
+        PyErr_SetString(PyExc_TypeError,
+                        "first argument must be a code object");
+        return NULL;
+    }
+
+    if (!PyUnicode_Check(file_path)) {
+        PyErr_SetString(PyExc_TypeError,
+                        "second argument must be a string");
+        return NULL;
+    }
+
+    update_compiled_module((PyCodeObject*)co, file_path);
+
+    Py_RETURN_NONE;
+}
+
 /* Load a source module from a given file and return its module
    object WITH INCREMENTED REFERENCE COUNT.  If there's a matching
    byte-compiled file, use that instead. */
@@ -3976,6 +4002,7 @@
 #endif
     {"load_package",            imp_load_package,       METH_VARARGS},
     {"load_source",             imp_load_source,        METH_VARARGS},
+    {"_fix_co_filename",        imp_fix_co_filename,    METH_VARARGS},
     {NULL,                      NULL}           /* sentinel */
 };