updated for version 7.3.1172
Problem: Python 2: loading modules doesn't work well.
Solution: Fix the code. Add more tests. (ZyX)
diff --git a/src/if_python.c b/src/if_python.c
index 09b3ca5..d19ef3a 100644
--- a/src/if_python.c
+++ b/src/if_python.c
@@ -150,6 +150,7 @@
# undef Py_InitModule4
# undef Py_InitModule4_64
# undef PyObject_CallMethod
+# undef PyObject_CallFunction
/*
* Wrapper defines
@@ -219,6 +220,7 @@
# define PyObject_HasAttrString dll_PyObject_HasAttrString
# define PyObject_SetAttrString dll_PyObject_SetAttrString
# define PyObject_CallFunctionObjArgs dll_PyObject_CallFunctionObjArgs
+# define PyObject_CallFunction dll_PyObject_CallFunction
# define PyObject_Call dll_PyObject_Call
# define PyString_AsString dll_PyString_AsString
# define PyString_AsStringAndSize dll_PyString_AsStringAndSize
@@ -357,6 +359,7 @@
static int (*dll_PyObject_HasAttrString)(PyObject *, const char *);
static PyObject* (*dll_PyObject_SetAttrString)(PyObject *, const char *, PyObject *);
static PyObject* (*dll_PyObject_CallFunctionObjArgs)(PyObject *, ...);
+static PyObject* (*dll_PyObject_CallFunction)(PyObject *, char *, ...);
static PyObject* (*dll_PyObject_Call)(PyObject *, PyObject *, PyObject *);
static char*(*dll_PyString_AsString)(PyObject *);
static int(*dll_PyString_AsStringAndSize)(PyObject *, char **, int *);
@@ -528,6 +531,7 @@
{"PyObject_HasAttrString", (PYTHON_PROC*)&dll_PyObject_HasAttrString},
{"PyObject_SetAttrString", (PYTHON_PROC*)&dll_PyObject_SetAttrString},
{"PyObject_CallFunctionObjArgs", (PYTHON_PROC*)&dll_PyObject_CallFunctionObjArgs},
+ {"PyObject_CallFunction", (PYTHON_PROC*)&dll_PyObject_CallFunction},
{"PyObject_Call", (PYTHON_PROC*)&dll_PyObject_Call},
{"PyString_AsString", (PYTHON_PROC*)&dll_PyString_AsString},
{"PyString_AsStringAndSize", (PYTHON_PROC*)&dll_PyString_AsStringAndSize},
@@ -748,10 +752,12 @@
static PyObject *ListGetattr(PyObject *, char *);
static PyObject *FunctionGetattr(PyObject *, char *);
-static PyObject *LoaderLoadModule(PyObject *, PyObject *);
static PyObject *FinderFindModule(PyObject *, PyObject *);
static PyObject *VimPathHook(PyObject *, PyObject *);
+static PyObject *py_find_module;
+static PyObject *py_load_module;
+
#ifndef Py_VISIT
# define Py_VISIT(obj) visit(obj, arg)
#endif
@@ -1376,16 +1382,127 @@
}
#endif
+ static void
+LoaderDestructor(LoaderObject *self)
+{
+ Py_DECREF(self->module);
+ DESTRUCTOR_FINISH(self);
+}
+
static PyObject *
-LoaderLoadModule(PyObject *self, PyObject *args)
+LoaderLoadModule(LoaderObject *self, PyObject *args UNUSED)
+{
+ PyObject *r = self->module;
+
+ Py_INCREF(r);
+ return r;
+}
+
+static struct PyMethodDef LoaderMethods[] = {
+ /* name, function, calling, doc */
+ {"load_module", (PyCFunction)LoaderLoadModule, METH_VARARGS, ""},
+ { NULL, NULL, 0, NULL}
+};
+
+ static PyObject *
+call_load_module(char *name, int len, PyObject *find_module_result)
+{
+ PyObject *fd, *pathname, *description;
+
+ if (!PyTuple_Check(find_module_result)
+ || PyTuple_GET_SIZE(find_module_result) != 3)
+ {
+ PyErr_SetString(PyExc_TypeError,
+ _("expected 3-tuple as imp.find_module() result"));
+ return NULL;
+ }
+
+ if (!(fd = PyTuple_GET_ITEM(find_module_result, 0))
+ || !(pathname = PyTuple_GET_ITEM(find_module_result, 1))
+ || !(description = PyTuple_GET_ITEM(find_module_result, 2)))
+ {
+ PyErr_SetString(PyExc_RuntimeError,
+ _("internal error: imp.find_module returned tuple with NULL"));
+ return NULL;
+ }
+
+ return PyObject_CallFunction(py_load_module,
+ "s#OOO", name, len, fd, pathname, description);
+}
+
+ static PyObject *
+find_module(char *fullname, char *tail, PyObject *new_path)
+{
+ PyObject *find_module_result;
+ PyObject *module;
+ char *dot;
+
+ if ((dot = (char *) vim_strchr((char_u *) tail, '.')))
+ {
+ /*
+ * There is a dot in the name: call find_module recursively without the
+ * first component
+ */
+ PyObject *newest_path;
+ int partlen = (int) (dot - 1 - tail);
+
+ if (!(find_module_result = PyObject_CallFunction(py_find_module,
+ "s#O", tail, partlen, new_path)))
+ return NULL;
+
+ if (!(module = call_load_module(
+ fullname,
+ ((int) (tail - fullname)) + partlen,
+ find_module_result)))
+ {
+ Py_DECREF(find_module_result);
+ return NULL;
+ }
+
+ Py_DECREF(find_module_result);
+
+ if (!(newest_path = PyObject_GetAttrString(module, "__path__")))
+ {
+ Py_DECREF(module);
+ return NULL;
+ }
+
+ Py_DECREF(module);
+
+ module = find_module(fullname, dot + 1, newest_path);
+
+ Py_DECREF(newest_path);
+
+ return module;
+ }
+ else
+ {
+ if (!(find_module_result = PyObject_CallFunction(py_find_module,
+ "sO", tail, new_path)))
+ return NULL;
+
+ if (!(module = call_load_module(
+ fullname,
+ STRLEN(fullname),
+ find_module_result)))
+ {
+ Py_DECREF(find_module_result);
+ return NULL;
+ }
+
+ Py_DECREF(find_module_result);
+
+ return module;
+ }
+}
+
+ static PyObject *
+FinderFindModule(PyObject *self, PyObject *args)
{
char *fullname;
- PyObject *path;
- PyObject *meta_path;
- PyObject *path_hooks;
+ PyObject *module;
PyObject *new_path;
- PyObject *r;
- PyObject *new_list;
+ LoaderObject *loader;
if (!PyArg_ParseTuple(args, "s", &fullname))
return NULL;
@@ -1393,73 +1510,25 @@
if (!(new_path = Vim_GetPaths(self)))
return NULL;
- if (!(new_list = PyList_New(0)))
- return NULL;
+ module = find_module(fullname, fullname, new_path);
-#define GET_SYS_OBJECT(objstr, obj) \
- obj = PySys_GetObject(objstr); \
- PyErr_Clear(); \
- Py_XINCREF(obj);
-
- GET_SYS_OBJECT("meta_path", meta_path);
- if (PySys_SetObject("meta_path", new_list))
- {
- Py_XDECREF(meta_path);
- Py_DECREF(new_list);
- return NULL;
- }
- Py_DECREF(new_list); /* Now it becomes a reference borrowed from
- sys.meta_path */
-
-#define RESTORE_SYS_OBJECT(objstr, obj) \
- if (obj) \
- { \
- PySys_SetObject(objstr, obj); \
- Py_DECREF(obj); \
- }
-
- GET_SYS_OBJECT("path_hooks", path_hooks);
- if (PySys_SetObject("path_hooks", new_list))
- {
- RESTORE_SYS_OBJECT("meta_path", meta_path);
- Py_XDECREF(path_hooks);
- return NULL;
- }
-
- GET_SYS_OBJECT("path", path);
- if (PySys_SetObject("path", new_path))
- {
- RESTORE_SYS_OBJECT("meta_path", meta_path);
- RESTORE_SYS_OBJECT("path_hooks", path_hooks);
- Py_XDECREF(path);
- return NULL;
- }
Py_DECREF(new_path);
- r = PyImport_ImportModule(fullname);
-
- RESTORE_SYS_OBJECT("meta_path", meta_path);
- RESTORE_SYS_OBJECT("path_hooks", path_hooks);
- RESTORE_SYS_OBJECT("path", path);
-
- if (PyErr_Occurred())
+ if (!module)
{
- Py_XDECREF(r);
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ if (!(loader = PyObject_NEW(LoaderObject, &LoaderType)))
+ {
+ Py_DECREF(module);
return NULL;
}
- return r;
-}
+ loader->module = module;
- static PyObject *
-FinderFindModule(PyObject *self UNUSED, PyObject *args UNUSED)
-{
- /*
- * Don't bother actually finding the module, it is delegated to the "loader"
- * object (which is basically the same object: vim module).
- */
- Py_INCREF(vim_module);
- return vim_module;
+ return (PyObject *) loader;
}
static PyObject *
@@ -1483,7 +1552,34 @@
PythonMod_Init(void)
{
/* The special value is removed from sys.path in Python_Init(). */
- static char *(argv[2]) = {"/must>not&exist/foo", NULL};
+ static char *(argv[2]) = {"/must>not&exist/foo", NULL};
+ PyObject *imp;
+
+ if (!(imp = PyImport_ImportModule("imp")))
+ return -1;
+
+ if (!(py_find_module = PyObject_GetAttrString(imp, "find_module")))
+ {
+ Py_DECREF(imp);
+ return -1;
+ }
+
+ if (!(py_load_module = PyObject_GetAttrString(imp, "load_module")))
+ {
+ Py_DECREF(py_find_module);
+ Py_DECREF(imp);
+ return -1;
+ }
+
+ Py_DECREF(imp);
+
+ vim_memset(&LoaderType, 0, sizeof(LoaderType));
+ LoaderType.tp_name = "vim.Loader";
+ LoaderType.tp_basicsize = sizeof(LoaderObject);
+ LoaderType.tp_flags = Py_TPFLAGS_DEFAULT;
+ LoaderType.tp_doc = "vim message object";
+ LoaderType.tp_methods = LoaderMethods;
+ LoaderType.tp_dealloc = (destructor)LoaderDestructor;
if (init_types())
return -1;