# HG changeset patch
# User ZyX <[email protected]>
# Date 1371034574 -14400
#      Wed Jun 12 14:56:14 2013 +0400
# Branch python-path
# Node ID a1b8a5ddecec70085e7e62f8ea9bc6c46ecea530
# Parent  c37e77761d00748eec028883e5a6f999d50c3479
Fix for python2

Python-3 now fails like it failed previously: on python-3.2.
Python-3.3 is fine.

diff -r c37e77761d00 -r a1b8a5ddecec runtime/doc/if_pyth.txt
--- a/runtime/doc/if_pyth.txt   Tue Jun 11 22:44:09 2013 +0200
+++ b/runtime/doc/if_pyth.txt   Wed Jun 12 14:56:14 2013 +0400
@@ -315,52 +315,53 @@
 {rtp}/python2 (or python3) and {rtp}/pythonx (for both python versions) for 
 each {rtp} found in 'runtimepath'.
 
-Implementation for python 2 is the following: usual importing code with empty 
-lists in place of sys.path_hooks and sys.meta_path. Code is similar to the 
-below, but written in C: >
+Implementation for python 2 is similar to the following, but written in C: >
 
-    # Assuming vim variable is already accessible and is set to the current 
-    # module
+    from imp import find_module, load_module
+    import vim
     import sys
 
-    def find_module(fullname):
-        return vim
+    class VimModuleLoader(object):
+        def __init__(self, module):
+            self.module = module
 
-    def load_module(fullname):
-        # see vim._get_paths below
-        new_path = _get_paths()
+        def load_module(self, fullname, path=None):
+            return self.module
 
-        try:         old_path = sys.path
-        except: pass
-        try:         old_meta_path = sys.meta_path
-        except: pass
-        try:         old_path_hooks = sys.path_hooks
-        except: pass
+    def _find_module(fullname, oldtail, path):
+        idx = oldtail.find('.')
+        if idx > 0:
+            name = oldtail[:idx]
+            tail = oldtail[idx+1:]
+            fmr = find_module(name, path)
+            module = load_module(fullname[:-len(oldtail)] + name, *fmr)
+            return _find_module(fullname, tail, module.__path__)
+        else:
+            fmr = find_module(fullname, path)
+            return load_module(fullname, *fmr)
 
-        sys.meta_path = []
-        sys.path_hooks = sys.meta_path
-        sys.path = new_path
+    # It uses vim module itself in place of VimPathFinder class: it does not 
+    # matter for python which object has find_module function attached to as 
+    # an attribute.
+    class VimPathFinder(object):
+        def find_module(cls, fullname, path=None):
+            try:
+                return VimModuleLoader(_find_module(fullname, fullname, path 
or vim._get_paths()))
+            except ImportError:
+                return None
+        find_module = classmethod(find_module)
 
-        try:
-            exec ('import ' + fullname + ' as m')  # No actual exec in C code
-            return m
-        finally:
-            e = None
-            try:                        sys.path = old_path
-            except Exception as e: pass
-            try:                        sys.meta_path = old_meta_path
-            except Exception as e: pass
-            try:                        sys.path_hooks = old_path_hooks
-            except Exception as e: pass
-            if e:
-                raise e
+        def load_module(cls, fullname, path=None):
+            return _find_module(fullname, fullname, path or vim._get_paths())
+        load_module = classmethod(load_module)
 
-    def path_hook(d):
-        if d == VIM_SPECIAL_PATH:
-            return vim
-        raise ImportError
+    def hook(path):
+        if path == vim.VIM_SPECIAL_PATH:
+            return VimPathFinder
+        else:
+            raise ImportError
 
-    sys.path_hooks.append(path_hook)
+    sys.path_hooks.append(hook)
 
 Implementation for python 3 is cleaner: code is similar to the following, but, 
 again, written in C: >
@@ -395,14 +396,13 @@
        Note: you must not use value of this constant directly, always use 
              vim.VIM_SPECIAL_PATH object.
 
-vim.load_module(name)                                  *python-load_module*
 vim.find_module(...)                                   *python-find_module*
 vim.path_hook(path)                                    *python-path_hook*
        Methods or objects used to implement path loading as described above. 
        You should not be using any of these directly except for vim.path_hook 
        in case you need to do something with sys.meta_path. It is not 
        guaranteed that any of the objects will exist in the future vim 
-       versions. In fact, load_module and find_module methods do not exists 
+       versions. In fact, find_module methods do not exists 
        in python3.
 
 vim._get_paths                                         *python-_get_paths*
diff -r c37e77761d00 -r a1b8a5ddecec src/if_py_both.h
--- a/src/if_py_both.h  Tue Jun 11 22:44:09 2013 +0200
+++ b/src/if_py_both.h  Wed Jun 12 14:56:14 2013 +0400
@@ -940,7 +940,6 @@
     {"foreach_rtp", VimForeachRTP,             METH_VARARGS,                   
"Call given callable for each path in &rtp"},
 #if PY_MAJOR_VERSION < 3
     {"find_module", FinderFindModule,          METH_VARARGS,                   
"Internal use only, returns loader object for any input it receives"},
-    {"load_module", LoaderLoadModule,          METH_VARARGS,                   
"Internal use only, tries importing the given module from &rtp by temporary 
mocking sys.path (to an rtp-based one) and unsetting sys.meta_path and 
sys.path_hooks"},
 #endif
     {"path_hook",   VimPathHook,               METH_VARARGS,                   
"Hook function to install in sys.path_hooks"},
     {"_get_paths",  (PyCFunction)Vim_GetPaths, METH_NOARGS,                    
"Get &rtp-based additions to sys.path"},
@@ -5195,6 +5194,13 @@
     PyObject_HEAD
 } FinderObject;
 static PyTypeObject FinderType;
+#else
+typedef struct
+{
+    PyObject_HEAD
+    PyObject   *module;
+} LoaderObject;
+static PyTypeObject LoaderType;
 #endif
 
     static void
@@ -5444,6 +5450,8 @@
     PYTYPE_READY(OutputType);
 #if PY_MAJOR_VERSION >= 3
     PYTYPE_READY(FinderType);
+#else
+    PYTYPE_READY(LoaderType);
 #endif
     return 0;
 }
@@ -5570,6 +5578,8 @@
     {"Options",    (PyObject *)&OptionsType},
 #if PY_MAJOR_VERSION >= 3
     {"Finder",     (PyObject *)&FinderType},
+#else
+    {"Loader",     (PyObject *)&LoaderType},
 #endif
 };
 
@@ -5666,6 +5676,9 @@
     ADD_CHECKED_OBJECT(m, "_find_module",
            (py_find_module = PyObject_GetAttrString(path_finder,
                                                     "find_module")));
+#else
+    ADD_OBJECT(m, "_find_module", py_find_module);
+    ADD_OBJECT(m, "_load_module", py_load_module);
 #endif
 
     return 0;
diff -r c37e77761d00 -r a1b8a5ddecec src/if_python.c
--- a/src/if_python.c   Tue Jun 11 22:44:09 2013 +0200
+++ b/src/if_python.c   Wed Jun 12 14:56:14 2013 +0400
@@ -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,128 @@
 }
 #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   *r;
+    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 +1511,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);
+    Py_DECREF(new_path);
 
-    GET_SYS_OBJECT("meta_path", meta_path);
-    if (PySys_SetObject("meta_path", new_list))
+    if (!module)
     {
-       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); \
+       Py_INCREF(Py_None);
+       return Py_None;
     }
 
-    GET_SYS_OBJECT("path_hooks", path_hooks);
-    if (PySys_SetObject("path_hooks", new_list))
+    if (!(loader = PyObject_NEW(LoaderObject, &LoaderType)))
     {
-       RESTORE_SYS_OBJECT("meta_path", meta_path);
-       Py_XDECREF(path_hooks);
+       Py_DECREF(module);
        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);
+    loader->module = module;
 
-    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())
-    {
-       Py_XDECREF(r);
-       return NULL;
-    }
-
-    return r;
-}
-
-    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 +1553,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;
diff -r c37e77761d00 -r a1b8a5ddecec src/testdir/python2/module.py
--- a/src/testdir/python2/module.py     Tue Jun 11 22:44:09 2013 +0200
+++ b/src/testdir/python2/module.py     Wed Jun 12 14:56:14 2013 +0400
@@ -1,1 +1,2 @@
+import before_1
 dir = '2'
diff -r c37e77761d00 -r a1b8a5ddecec src/testdir/python3/module.py
--- a/src/testdir/python3/module.py     Tue Jun 11 22:44:09 2013 +0200
+++ b/src/testdir/python3/module.py     Wed Jun 12 14:56:14 2013 +0400
@@ -1,1 +1,2 @@
+import before_1
 dir = '3'
diff -r c37e77761d00 -r a1b8a5ddecec src/testdir/python_after/after.py
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/src/testdir/python_after/after.py Wed Jun 12 14:56:14 2013 +0400
@@ -0,0 +1,2 @@
+import before_2
+dir = "after"
diff -r c37e77761d00 -r a1b8a5ddecec src/testdir/python_before/before.py
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/src/testdir/python_before/before.py       Wed Jun 12 14:56:14 2013 +0400
@@ -0,0 +1,1 @@
+dir = "before"
diff -r c37e77761d00 -r a1b8a5ddecec src/testdir/test86.in
--- a/src/testdir/test86.in     Tue Jun 11 22:44:09 2013 +0200
+++ b/src/testdir/test86.in     Wed Jun 12 14:56:14 2013 +0400
@@ -8,6 +8,7 @@
 STARTTEST
 :so small.vim
 :set encoding=latin1
+:set noswapfile
 :if !has('python') | e! test.ok | wq! test.out | endif
 :lang C
 :py import vim
@@ -1071,10 +1072,16 @@
 :"
 :" Test import
 py << EOF
+sys.path.insert(0, os.path.join(os.getcwd(), 'python_before'))
+sys.path.append(os.path.join(os.getcwd(), 'python_after'))
 vim.options['rtp'] = os.getcwd().replace(',', '\\,').replace('\\', '\\\\')
 from module import dir as d
 from modulex import ddir
 cb.append(d + ',' + ddir)
+import before
+cb.append(before.dir)
+import after
+cb.append(after.dir)
 EOF
 :"
 :" Test exceptions
diff -r c37e77761d00 -r a1b8a5ddecec src/testdir/test86.ok
--- a/src/testdir/test86.ok     Tue Jun 11 22:44:09 2013 +0200
+++ b/src/testdir/test86.ok     Wed Jun 12 14:56:14 2013 +0400
@@ -1084,6 +1084,8 @@
 vim.current.tabpage = True:(<type 'exceptions.TypeError'>, TypeError('expected 
vim.TabPage object',))
 vim.current.xxx = True:(<type 'exceptions.AttributeError'>, 
AttributeError('xxx',))
 2,xx
+before
+after
 vim.command("throw 'abc'"):(<class 'vim.error'>, error('abc',))
 Exe("throw 'def'"):(<class 'vim.error'>, error('def',))
 vim.eval("Exe('throw ''ghi''')"):(<class 'vim.error'>, error('ghi',))
diff -r c37e77761d00 -r a1b8a5ddecec src/testdir/test87.in
--- a/src/testdir/test87.in     Tue Jun 11 22:44:09 2013 +0200
+++ b/src/testdir/test87.in     Wed Jun 12 14:56:14 2013 +0400
@@ -2,6 +2,7 @@
 
 STARTTEST
 :so small.vim
+:set noswapfile
 :if !has('python3') | e! test.ok | wq! test.out | endif
 :lang C
 :py3 import vim
@@ -1038,10 +1039,16 @@
 :"
 :" Test import
 py3 << EOF
+sys.path.insert(0, os.path.join(os.getcwd(), 'python_before'))
+sys.path.append(os.path.join(os.getcwd(), 'python_after'))
 vim.options['rtp'] = os.getcwd().replace(',', '\\,').replace('\\', '\\\\')
 from module import dir as d
 from modulex import ddir
 cb.append(d + ',' + ddir)
+import before
+cb.append(before.dir)
+import after
+cb.append(after.dir)
 EOF
 :"
 :" Test exceptions
diff -r c37e77761d00 -r a1b8a5ddecec src/testdir/test87.ok
--- a/src/testdir/test87.ok     Tue Jun 11 22:44:09 2013 +0200
+++ b/src/testdir/test87.ok     Wed Jun 12 14:56:14 2013 +0400
@@ -1093,6 +1093,8 @@
 vim.current.tabpage = True:(<class 'TypeError'>, TypeError('expected 
vim.TabPage object',))
 vim.current.xxx = True:(<class 'AttributeError'>, AttributeError('xxx',))
 3,xx
+before
+after
 vim.command("throw 'abc'"):(<class 'vim.error'>, error('abc',))
 Exe("throw 'def'"):(<class 'vim.error'>, error('def',))
 vim.eval("Exe('throw ''ghi''')"):(<class 'vim.error'>, error('ghi',))

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.


diff -crN vim.c37e77761d00/runtime/doc/if_pyth.txt vim.a1b8a5ddecec/runtime/doc/if_pyth.txt
*** vim.c37e77761d00/runtime/doc/if_pyth.txt	2013-06-12 15:00:18.728340677 +0400
--- vim.a1b8a5ddecec/runtime/doc/if_pyth.txt	2013-06-12 15:00:18.750340468 +0400
***************
*** 315,366 ****
  {rtp}/python2 (or python3) and {rtp}/pythonx (for both python versions) for 
  each {rtp} found in 'runtimepath'.
  
! Implementation for python 2 is the following: usual importing code with empty 
! lists in place of sys.path_hooks and sys.meta_path. Code is similar to the 
! below, but written in C: >
  
!     # Assuming vim variable is already accessible and is set to the current 
!     # module
      import sys
  
!     def find_module(fullname):
!         return vim
  
!     def load_module(fullname):
!         # see vim._get_paths below
!         new_path = _get_paths()
! 
!         try:         old_path = sys.path
!         except: pass
!         try:         old_meta_path = sys.meta_path
!         except: pass
!         try:         old_path_hooks = sys.path_hooks
!         except: pass
! 
!         sys.meta_path = []
!         sys.path_hooks = sys.meta_path
!         sys.path = new_path
! 
!         try:
!             exec ('import ' + fullname + ' as m')  # No actual exec in C code
!             return m
!         finally:
!             e = None
!             try:                        sys.path = old_path
!             except Exception as e: pass
!             try:                        sys.meta_path = old_meta_path
!             except Exception as e: pass
!             try:                        sys.path_hooks = old_path_hooks
!             except Exception as e: pass
!             if e:
!                 raise e
! 
!     def path_hook(d):
!         if d == VIM_SPECIAL_PATH:
!             return vim
!         raise ImportError
! 
!     sys.path_hooks.append(path_hook)
  
  Implementation for python 3 is cleaner: code is similar to the following, but, 
  again, written in C: >
--- 315,367 ----
  {rtp}/python2 (or python3) and {rtp}/pythonx (for both python versions) for 
  each {rtp} found in 'runtimepath'.
  
! Implementation for python 2 is similar to the following, but written in C: >
  
!     from imp import find_module, load_module
!     import vim
      import sys
  
!     class VimModuleLoader(object):
!         def __init__(self, module):
!             self.module = module
! 
!         def load_module(self, fullname, path=None):
!             return self.module
! 
!     def _find_module(fullname, oldtail, path):
!         idx = oldtail.find('.')
!         if idx > 0:
!             name = oldtail[:idx]
!             tail = oldtail[idx+1:]
!             fmr = find_module(name, path)
!             module = load_module(fullname[:-len(oldtail)] + name, *fmr)
!             return _find_module(fullname, tail, module.__path__)
!         else:
!             fmr = find_module(fullname, path)
!             return load_module(fullname, *fmr)
! 
!     # It uses vim module itself in place of VimPathFinder class: it does not 
!     # matter for python which object has find_module function attached to as 
!     # an attribute.
!     class VimPathFinder(object):
!         def find_module(cls, fullname, path=None):
!             try:
!                 return VimModuleLoader(_find_module(fullname, fullname, path or vim._get_paths()))
!             except ImportError:
!                 return None
!         find_module = classmethod(find_module)
! 
!         def load_module(cls, fullname, path=None):
!             return _find_module(fullname, fullname, path or vim._get_paths())
!         load_module = classmethod(load_module)
! 
!     def hook(path):
!         if path == vim.VIM_SPECIAL_PATH:
!             return VimPathFinder
!         else:
!             raise ImportError
  
!     sys.path_hooks.append(hook)
  
  Implementation for python 3 is cleaner: code is similar to the following, but, 
  again, written in C: >
***************
*** 395,408 ****
  	Note: you must not use value of this constant directly, always use 
  	      vim.VIM_SPECIAL_PATH object.
  
- vim.load_module(name)					*python-load_module*
  vim.find_module(...)					*python-find_module*
  vim.path_hook(path)					*python-path_hook*
  	Methods or objects used to implement path loading as described above. 
  	You should not be using any of these directly except for vim.path_hook 
  	in case you need to do something with sys.meta_path. It is not 
  	guaranteed that any of the objects will exist in the future vim 
! 	versions. In fact, load_module and find_module methods do not exists 
  	in python3.
  
  vim._get_paths						*python-_get_paths*
--- 396,408 ----
  	Note: you must not use value of this constant directly, always use 
  	      vim.VIM_SPECIAL_PATH object.
  
  vim.find_module(...)					*python-find_module*
  vim.path_hook(path)					*python-path_hook*
  	Methods or objects used to implement path loading as described above. 
  	You should not be using any of these directly except for vim.path_hook 
  	in case you need to do something with sys.meta_path. It is not 
  	guaranteed that any of the objects will exist in the future vim 
! 	versions. In fact, find_module methods do not exists 
  	in python3.
  
  vim._get_paths						*python-_get_paths*
diff -crN vim.c37e77761d00/src/if_py_both.h vim.a1b8a5ddecec/src/if_py_both.h
*** vim.c37e77761d00/src/if_py_both.h	2013-06-12 15:00:18.741340553 +0400
--- vim.a1b8a5ddecec/src/if_py_both.h	2013-06-12 15:00:18.764340335 +0400
***************
*** 940,946 ****
      {"foreach_rtp", VimForeachRTP,		METH_VARARGS,			"Call given callable for each path in &rtp"},
  #if PY_MAJOR_VERSION < 3
      {"find_module", FinderFindModule,		METH_VARARGS,			"Internal use only, returns loader object for any input it receives"},
-     {"load_module", LoaderLoadModule,		METH_VARARGS,			"Internal use only, tries importing the given module from &rtp by temporary mocking sys.path (to an rtp-based one) and unsetting sys.meta_path and sys.path_hooks"},
  #endif
      {"path_hook",   VimPathHook,		METH_VARARGS,			"Hook function to install in sys.path_hooks"},
      {"_get_paths",  (PyCFunction)Vim_GetPaths,	METH_NOARGS,			"Get &rtp-based additions to sys.path"},
--- 940,945 ----
***************
*** 5195,5200 ****
--- 5194,5206 ----
      PyObject_HEAD
  } FinderObject;
  static PyTypeObject FinderType;
+ #else
+ typedef struct
+ {
+     PyObject_HEAD
+     PyObject	*module;
+ } LoaderObject;
+ static PyTypeObject LoaderType;
  #endif
  
      static void
***************
*** 5444,5449 ****
--- 5450,5457 ----
      PYTYPE_READY(OutputType);
  #if PY_MAJOR_VERSION >= 3
      PYTYPE_READY(FinderType);
+ #else
+     PYTYPE_READY(LoaderType);
  #endif
      return 0;
  }
***************
*** 5570,5575 ****
--- 5578,5585 ----
      {"Options",    (PyObject *)&OptionsType},
  #if PY_MAJOR_VERSION >= 3
      {"Finder",     (PyObject *)&FinderType},
+ #else
+     {"Loader",     (PyObject *)&LoaderType},
  #endif
  };
  
***************
*** 5666,5671 ****
--- 5676,5684 ----
      ADD_CHECKED_OBJECT(m, "_find_module",
  	    (py_find_module = PyObject_GetAttrString(path_finder,
  						     "find_module")));
+ #else
+     ADD_OBJECT(m, "_find_module", py_find_module);
+     ADD_OBJECT(m, "_load_module", py_load_module);
  #endif
  
      return 0;
diff -crN vim.c37e77761d00/src/if_python.c vim.a1b8a5ddecec/src/if_python.c
*** vim.c37e77761d00/src/if_python.c	2013-06-12 15:00:18.732340639 +0400
--- vim.a1b8a5ddecec/src/if_python.c	2013-06-12 15:00:18.754340430 +0400
***************
*** 150,155 ****
--- 150,156 ----
  # undef Py_InitModule4
  # undef Py_InitModule4_64
  # undef PyObject_CallMethod
+ # undef PyObject_CallFunction
  
  /*
   * Wrapper defines
***************
*** 219,224 ****
--- 220,226 ----
  # 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,362 ****
--- 359,365 ----
  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,533 ****
--- 531,537 ----
      {"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,757 ****
  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 *);
  
  #ifndef Py_VISIT
  # define Py_VISIT(obj) visit(obj, arg)
  #endif
--- 752,763 ----
  static PyObject *ListGetattr(PyObject *, char *);
  static PyObject *FunctionGetattr(PyObject *, char *);
  
  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,1465 ****
  }
  #endif
  
      static PyObject *
! LoaderLoadModule(PyObject *self, PyObject *args)
  {
-     char	*fullname;
-     PyObject	*path;
-     PyObject	*meta_path;
-     PyObject	*path_hooks;
-     PyObject	*new_path;
      PyObject	*r;
!     PyObject	*new_list;
  
!     if (!PyArg_ParseTuple(args, "s", &fullname))
  	return NULL;
  
!     if (!(new_path = Vim_GetPaths(self)))
  	return NULL;
  
!     if (!(new_list = PyList_New(0)))
! 	return NULL;
  
! #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())
      {
! 	Py_XDECREF(r);
  	return NULL;
      }
  
!     return r;
! }
  
!     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;
  }
  
      static PyObject *
--- 1382,1535 ----
  }
  #endif
  
+     static void
+ LoaderDestructor(LoaderObject *self)
+ {
+     Py_DECREF(self->module);
+     DESTRUCTOR_FINISH(self);
+ }
+ 
      static PyObject *
! 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	*r;
!     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	*module;
!     PyObject	*new_path;
!     LoaderObject	*loader;
! 
!     if (!PyArg_ParseTuple(args, "s", &fullname))
  	return NULL;
  
!     if (!(new_path = Vim_GetPaths(self)))
  	return NULL;
  
!     module = find_module(fullname, fullname, new_path);
  
!     Py_DECREF(new_path);
  
!     if (!module)
      {
! 	Py_INCREF(Py_None);
! 	return Py_None;
!     }
! 
!     if (!(loader = PyObject_NEW(LoaderObject, &LoaderType)))
!     {
! 	Py_DECREF(module);
  	return NULL;
      }
  
!     loader->module = module;
  
!     return (PyObject *) loader;
  }
  
      static PyObject *
***************
*** 1483,1489 ****
  PythonMod_Init(void)
  {
      /* The special value is removed from sys.path in Python_Init(). */
!     static char *(argv[2]) = {"/must>not&exist/foo", NULL};
  
      if (init_types())
  	return -1;
--- 1553,1586 ----
  PythonMod_Init(void)
  {
      /* The special value is removed from sys.path in Python_Init(). */
!     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;
diff -crN vim.c37e77761d00/src/testdir/python2/module.py vim.a1b8a5ddecec/src/testdir/python2/module.py
*** vim.c37e77761d00/src/testdir/python2/module.py	2013-06-12 15:00:18.732340639 +0400
--- vim.a1b8a5ddecec/src/testdir/python2/module.py	2013-06-12 15:00:18.745340516 +0400
***************
*** 1 ****
--- 1,2 ----
+ import before_1
  dir = '2'
diff -crN vim.c37e77761d00/src/testdir/python3/module.py vim.a1b8a5ddecec/src/testdir/python3/module.py
*** vim.c37e77761d00/src/testdir/python3/module.py	2013-06-12 15:00:18.733340630 +0400
--- vim.a1b8a5ddecec/src/testdir/python3/module.py	2013-06-12 15:00:18.756340412 +0400
***************
*** 1 ****
--- 1,2 ----
+ import before_1
  dir = '3'
diff -crN vim.c37e77761d00/src/testdir/python_after/after.py vim.a1b8a5ddecec/src/testdir/python_after/after.py
*** vim.c37e77761d00/src/testdir/python_after/after.py	1970-01-01 03:00:00.000000000 +0300
--- vim.a1b8a5ddecec/src/testdir/python_after/after.py	2013-06-12 15:00:18.768340298 +0400
***************
*** 0 ****
--- 1,2 ----
+ import before_2
+ dir = "after"
diff -crN vim.c37e77761d00/src/testdir/python_before/before.py vim.a1b8a5ddecec/src/testdir/python_before/before.py
*** vim.c37e77761d00/src/testdir/python_before/before.py	1970-01-01 03:00:00.000000000 +0300
--- vim.a1b8a5ddecec/src/testdir/python_before/before.py	2013-06-12 15:00:18.747340496 +0400
***************
*** 0 ****
--- 1 ----
+ dir = "before"
diff -crN vim.c37e77761d00/src/testdir/test86.in vim.a1b8a5ddecec/src/testdir/test86.in
*** vim.c37e77761d00/src/testdir/test86.in	2013-06-12 15:00:18.742340544 +0400
--- vim.a1b8a5ddecec/src/testdir/test86.in	2013-06-12 15:00:18.765340325 +0400
***************
*** 8,13 ****
--- 8,14 ----
  STARTTEST
  :so small.vim
  :set encoding=latin1
+ :set noswapfile
  :if !has('python') | e! test.ok | wq! test.out | endif
  :lang C
  :py import vim
***************
*** 1071,1080 ****
--- 1072,1087 ----
  :"
  :" Test import
  py << EOF
+ sys.path.insert(0, os.path.join(os.getcwd(), 'python_before'))
+ sys.path.append(os.path.join(os.getcwd(), 'python_after'))
  vim.options['rtp'] = os.getcwd().replace(',', '\\,').replace('\\', '\\\\')
  from module import dir as d
  from modulex import ddir
  cb.append(d + ',' + ddir)
+ import before
+ cb.append(before.dir)
+ import after
+ cb.append(after.dir)
  EOF
  :"
  :" Test exceptions
diff -crN vim.c37e77761d00/src/testdir/test86.ok vim.a1b8a5ddecec/src/testdir/test86.ok
*** vim.c37e77761d00/src/testdir/test86.ok	2013-06-12 15:00:18.744340525 +0400
--- vim.a1b8a5ddecec/src/testdir/test86.ok	2013-06-12 15:00:18.767340307 +0400
***************
*** 1084,1089 ****
--- 1084,1091 ----
  vim.current.tabpage = True:(<type 'exceptions.TypeError'>, TypeError('expected vim.TabPage object',))
  vim.current.xxx = True:(<type 'exceptions.AttributeError'>, AttributeError('xxx',))
  2,xx
+ before
+ after
  vim.command("throw 'abc'"):(<class 'vim.error'>, error('abc',))
  Exe("throw 'def'"):(<class 'vim.error'>, error('def',))
  vim.eval("Exe('throw ''ghi''')"):(<class 'vim.error'>, error('ghi',))
diff -crN vim.c37e77761d00/src/testdir/test87.in vim.a1b8a5ddecec/src/testdir/test87.in
*** vim.c37e77761d00/src/testdir/test87.in	2013-06-12 15:00:18.724340714 +0400
--- vim.a1b8a5ddecec/src/testdir/test87.in	2013-06-12 15:00:18.756340412 +0400
***************
*** 2,7 ****
--- 2,8 ----
  
  STARTTEST
  :so small.vim
+ :set noswapfile
  :if !has('python3') | e! test.ok | wq! test.out | endif
  :lang C
  :py3 import vim
***************
*** 1038,1047 ****
--- 1039,1054 ----
  :"
  :" Test import
  py3 << EOF
+ sys.path.insert(0, os.path.join(os.getcwd(), 'python_before'))
+ sys.path.append(os.path.join(os.getcwd(), 'python_after'))
  vim.options['rtp'] = os.getcwd().replace(',', '\\,').replace('\\', '\\\\')
  from module import dir as d
  from modulex import ddir
  cb.append(d + ',' + ddir)
+ import before
+ cb.append(before.dir)
+ import after
+ cb.append(after.dir)
  EOF
  :"
  :" Test exceptions
diff -crN vim.c37e77761d00/src/testdir/test87.ok vim.a1b8a5ddecec/src/testdir/test87.ok
*** vim.c37e77761d00/src/testdir/test87.ok	2013-06-12 15:00:18.725340705 +0400
--- vim.a1b8a5ddecec/src/testdir/test87.ok	2013-06-12 15:00:18.747340496 +0400
***************
*** 1093,1098 ****
--- 1093,1100 ----
  vim.current.tabpage = True:(<class 'TypeError'>, TypeError('expected vim.TabPage object',))
  vim.current.xxx = True:(<class 'AttributeError'>, AttributeError('xxx',))
  3,xx
+ before
+ after
  vim.command("throw 'abc'"):(<class 'vim.error'>, error('abc',))
  Exe("throw 'def'"):(<class 'vim.error'>, error('def',))
  vim.eval("Exe('throw ''ghi''')"):(<class 'vim.error'>, error('ghi',))

Raspunde prin e-mail lui