To: vim_dev@googlegroups.com Subject: Patch 7.3.1163 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 7.3.1163 Problem: Not easy to load Python modules. Solution: Search "python2", "python3" and "pythonx" directories in 'runtimepath' for Python modules. (ZyX) Files: runtime/doc/if_pyth.txt, src/configure.in, src/ex_cmds2.c, src/if_py_both.h, src/if_python.c, src/if_python3.c, src/testdir/test86.in, src/testdir/test87.in, src/auto/configure *** ../vim-7.3.1162/runtime/doc/if_pyth.txt 2013-06-02 18:20:12.000000000 +0200 --- runtime/doc/if_pyth.txt 2013-06-10 20:51:21.000000000 +0200 *************** *** 180,185 **** --- 180,191 ---- Like |strwidth()|: returns number of display cells str occupies, tab is counted as one cell. + vim.foreach_rtp(callable) *python-foreach_rtp* + Call the given callable for each path in 'runtimepath' until either + callable returns something but None, the exception is raised or there + are no longer paths. If stopped in case callable returned non-None, + vim.foreach_rtp function returns the value returned by callable. + vim.chdir(*args, **kwargs) *python-chdir* vim.fchdir(*args, **kwargs) *python-fchdir* Run os.chdir or os.fchdir, then all appropriate vim stuff. *************** *** 300,305 **** --- 306,418 ---- supported, and may cause the program to crash. This should probably be fixed. + *python2-directory* *python3-directory* *pythonx-directory* + Python 'runtimepath' handling *python-special-path* + + In python vim.VIM_SPECIAL_PATH special directory is used as a replacement for + the list of paths found in 'runtimepath': with this directory in sys.path and + vim.path_hooks in sys.path_hooks python will try to load module from + {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: > + + from importlib.machinery import PathFinder + import sys + + class Finder(PathFinder): + @classmethod + def find_module(cls, fullname): + # see vim._get_paths below + new_path = _get_paths() + + # super().find_module is also a class method + # super() is not used because this variant is easier to implement + # in C + return PathFinder.find_module(fullname, new_path) + + def path_hook(path): + if path == VIM_SPECIAL_PATH: + return Finder + raise ImportError + + sys.path_hooks.append(path_hook) + + vim.VIM_SPECIAL_PATH *python-VIM_SPECIAL_PATH* + String constant used in conjunction with vim path hook. If path hook + installed by vim is requested to handle anything but path equal to + vim.VIM_SPECIAL_PATH constant it raises ImportError. In the only other + case it uses special loader. + + 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* + Methods returning a list of paths which will be searched for by path + hook. You should not rely on this method being present in future + versions, but can use it for debugging. + + It returns a list of {rtp}/python2 (or {rtp}/python3) and + {rtp}/pythonx directories for each {rtp} in 'runtimepath'. + ============================================================================== 3. Buffer objects *python-buffer* *************** *** 340,346 **** |BufFilePost| autocommands are launched. b.number Buffer number. Can be used as |python-buffers| key. Read-only. ! b.valid True or False. Buffer object becames invalid when corresponding buffer is wiped out. The buffer object methods are: --- 453,459 ---- |BufFilePost| autocommands are launched. b.number Buffer number. Can be used as |python-buffers| key. Read-only. ! b.valid True or False. Buffer object becomes invalid when corresponding buffer is wiped out. The buffer object methods are: *************** *** 446,452 **** row, col (read-only) On-screen window position in display cells. First position is zero. tabpage (read-only) Window tab page. ! valid (read-write) True or False. Window object becames invalid when corresponding window is closed. The height attribute is writable only if the screen is split horizontally. --- 559,565 ---- row, col (read-only) On-screen window position in display cells. First position is zero. tabpage (read-only) Window tab page. ! valid (read-write) True or False. Window object becomes invalid when corresponding window is closed. The height attribute is writable only if the screen is split horizontally. *************** *** 471,477 **** windows Like |python-windows|, but for current tab page. vars The tab page |t:| variables. window Current tabpage window. ! valid True or False. Tab page object becames invalid when corresponding tab page is closed. TabPage object type is available using "TabPage" attribute of vim module. --- 584,590 ---- windows Like |python-windows|, but for current tab page. vars The tab page |t:| variables. window Current tabpage window. ! valid True or False. Tab page object becomes invalid when corresponding tab page is closed. TabPage object type is available using "TabPage" attribute of vim module. *** ../vim-7.3.1162/src/configure.in 2013-06-02 19:14:11.000000000 +0200 --- src/configure.in 2013-06-10 20:51:21.000000000 +0200 *************** *** 863,872 **** ${vi_cv_path_python} -c 'import sys; print sys.version[:3]'` ]]) ! dnl -- it must be at least version 2.2 ! AC_MSG_CHECKING(Python is 2.2 or better) if ${vi_cv_path_python} -c \ ! "import sys; sys.exit(${vi_cv_var_python_version} < 2.2)" then AC_MSG_RESULT(yep) --- 863,872 ---- ${vi_cv_path_python} -c 'import sys; print sys.version[:3]'` ]]) ! dnl -- it must be at least version 2.3 ! AC_MSG_CHECKING(Python is 2.3 or better) if ${vi_cv_path_python} -c \ ! "import sys; sys.exit(${vi_cv_var_python_version} < 2.3)" then AC_MSG_RESULT(yep) *** ../vim-7.3.1162/src/ex_cmds2.c 2013-06-10 20:10:40.000000000 +0200 --- src/ex_cmds2.c 2013-06-10 20:51:21.000000000 +0200 *************** *** 2737,2742 **** --- 2737,2746 ---- * When "all" is TRUE repeat for all matches, otherwise only the first one is * used. * Returns OK when at least one match found, FAIL otherwise. + * + * If "name" is NULL calls callback for each entry in runtimepath. Cookie is + * passed by reference in this case, setting it to NULL indicates that callback + * has done its job. */ int do_in_runtimepath(name, all, callback, cookie) *************** *** 2768,2774 **** buf = alloc(MAXPATHL); if (buf != NULL && rtp_copy != NULL) { ! if (p_verbose > 1) { verbose_enter(); smsg((char_u *)_("Searching for \"%s\" in \"%s\""), --- 2772,2778 ---- buf = alloc(MAXPATHL); if (buf != NULL && rtp_copy != NULL) { ! if (p_verbose > 1 && name != NULL) { verbose_enter(); smsg((char_u *)_("Searching for \"%s\" in \"%s\""), *************** *** 2782,2788 **** { /* Copy the path from 'runtimepath' to buf[]. */ copy_option_part(&rtp, buf, MAXPATHL, ","); ! if (STRLEN(buf) + STRLEN(name) + 2 < MAXPATHL) { add_pathsep(buf); tail = buf + STRLEN(buf); --- 2786,2798 ---- { /* Copy the path from 'runtimepath' to buf[]. */ copy_option_part(&rtp, buf, MAXPATHL, ","); ! if (name == NULL) ! { ! (*callback)(buf, (void *) &cookie); ! if (!did_one) ! did_one = (cookie == NULL); ! } ! else if (STRLEN(buf) + STRLEN(name) + 2 < MAXPATHL) { add_pathsep(buf); tail = buf + STRLEN(buf); *************** *** 2821,2827 **** } vim_free(buf); vim_free(rtp_copy); ! if (p_verbose > 0 && !did_one) { verbose_enter(); smsg((char_u *)_("not found in 'runtimepath': \"%s\""), name); --- 2831,2837 ---- } vim_free(buf); vim_free(rtp_copy); ! if (p_verbose > 0 && !did_one && name != NULL) { verbose_enter(); smsg((char_u *)_("not found in 'runtimepath': \"%s\""), name); *** ../vim-7.3.1162/src/if_py_both.h 2013-06-10 20:47:33.000000000 +0200 --- src/if_py_both.h 2013-06-10 20:55:17.000000000 +0200 *************** *** 24,29 **** --- 24,31 ---- #endif #define DOPY_FUNC "_vim_pydo" + static const char *vim_special_path = "_vim_path_"; + #define PyErr_SetVim(str) PyErr_SetString(VimError, str) #define RAISE_NO_EMPTY_KEYS PyErr_SetString(PyExc_ValueError, \ *************** *** 55,60 **** --- 57,64 ---- static PyObject *py_chdir; static PyObject *py_fchdir; static PyObject *py_getcwd; + static PyObject *vim_module; + static PyObject *vim_special_path_object; /* * obtain a lock on the Vim data structures *************** *** 779,797 **** return _VimChdir(py_fchdir, args, kwargs); } /* * Vim module - Definitions */ static struct PyMethodDef VimMethods[] = { ! /* name, function, calling, documentation */ ! {"command", VimCommand, METH_VARARGS, "Execute a Vim ex-mode command" }, ! {"eval", VimEval, METH_VARARGS, "Evaluate an expression using Vim evaluator" }, ! {"bindeval", VimEvalPy, METH_VARARGS, "Like eval(), but returns objects attached to vim ones"}, ! {"strwidth", VimStrwidth, METH_VARARGS, "Screen string width, counts as having width 1"}, ! {"chdir", (PyCFunction)VimChdir, METH_VARARGS|METH_KEYWORDS, "Change directory"}, ! {"fchdir", (PyCFunction)VimFchdir, METH_VARARGS|METH_KEYWORDS, "Change directory"}, ! { NULL, NULL, 0, NULL } }; /* --- 783,950 ---- return _VimChdir(py_fchdir, args, kwargs); } + typedef struct { + PyObject *callable; + PyObject *result; + } map_rtp_data; + + static void + map_rtp_callback(char_u *path, void *_data) + { + void **data = (void **) _data; + PyObject *pathObject; + map_rtp_data *mr_data = *((map_rtp_data **) data); + + if (!(pathObject = PyString_FromString((char *) path))) + { + *data = NULL; + return; + } + + mr_data->result = PyObject_CallFunctionObjArgs(mr_data->callable, + pathObject, NULL); + + Py_DECREF(pathObject); + + if (!mr_data->result || mr_data->result != Py_None) + *data = NULL; + else + { + Py_DECREF(mr_data->result); + mr_data->result = NULL; + } + } + + static PyObject * + VimForeachRTP(PyObject *self UNUSED, PyObject *args) + { + map_rtp_data data; + + if (!PyArg_ParseTuple(args, "O", &data.callable)) + return NULL; + + data.result = NULL; + + do_in_runtimepath(NULL, FALSE, &map_rtp_callback, &data); + + if (data.result == NULL) + { + if (PyErr_Occurred()) + return NULL; + else + { + Py_INCREF(Py_None); + return Py_None; + } + } + return data.result; + } + + /* + * _vim_runtimepath_ special path implementation. + */ + + static void + map_finder_callback(char_u *path, void *_data) + { + void **data = (void **) _data; + PyObject *list = *((PyObject **) data); + PyObject *pathObject1, *pathObject2; + char *pathbuf; + size_t pathlen; + + pathlen = STRLEN(path); + + #if PY_MAJOR_VERSION < 3 + # define PY_MAIN_DIR_STRING "python2" + #else + # define PY_MAIN_DIR_STRING "python3" + #endif + #define PY_ALTERNATE_DIR_STRING "pythonx" + + #define PYTHONX_STRING_LENGTH 7 /* STRLEN("pythonx") */ + if (!(pathbuf = PyMem_New(char, + pathlen + STRLEN(PATHSEPSTR) + PYTHONX_STRING_LENGTH + 1))) + { + PyErr_NoMemory(); + *data = NULL; + return; + } + + mch_memmove(pathbuf, path, pathlen + 1); + add_pathsep((char_u *) pathbuf); + + pathlen = STRLEN(pathbuf); + mch_memmove(pathbuf + pathlen, PY_MAIN_DIR_STRING, + PYTHONX_STRING_LENGTH + 1); + + if (!(pathObject1 = PyString_FromString(pathbuf))) + { + *data = NULL; + PyMem_Free(pathbuf); + return; + } + + mch_memmove(pathbuf + pathlen, PY_ALTERNATE_DIR_STRING, + PYTHONX_STRING_LENGTH + 1); + + if (!(pathObject2 = PyString_FromString(pathbuf))) + { + Py_DECREF(pathObject1); + PyMem_Free(pathbuf); + *data = NULL; + return; + } + + PyMem_Free(pathbuf); + + if (PyList_Append(list, pathObject1) + || PyList_Append(list, pathObject2)) + *data = NULL; + + Py_DECREF(pathObject1); + Py_DECREF(pathObject2); + } + + static PyObject * + Vim_GetPaths(PyObject *self UNUSED) + { + PyObject *r; + + if (!(r = PyList_New(0))) + return NULL; + + do_in_runtimepath(NULL, FALSE, &map_finder_callback, r); + + if (PyErr_Occurred()) + { + Py_DECREF(r); + return NULL; + } + + return r; + } + /* * Vim module - Definitions */ static struct PyMethodDef VimMethods[] = { ! /* name, function, calling, documentation */ ! {"command", VimCommand, METH_VARARGS, "Execute a Vim ex-mode command" }, ! {"eval", VimEval, METH_VARARGS, "Evaluate an expression using Vim evaluator" }, ! {"bindeval", VimEvalPy, METH_VARARGS, "Like eval(), but returns objects attached to vim ones"}, ! {"strwidth", VimStrwidth, METH_VARARGS, "Screen string width, counts as having width 1"}, ! {"chdir", (PyCFunction)VimChdir, METH_VARARGS|METH_KEYWORDS, "Change directory"}, ! {"fchdir", (PyCFunction)VimFchdir, METH_VARARGS|METH_KEYWORDS, "Change directory"}, ! {"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"}, ! { NULL, NULL, 0, NULL} }; /* *************** *** 5036,5041 **** --- 5189,5202 ---- } CurrentObject; static PyTypeObject CurrentType; + #if PY_MAJOR_VERSION >= 3 + typedef struct + { + PyObject_HEAD + } FinderObject; + static PyTypeObject FinderType; + #endif + static void init_structs(void) { *************** *** 5281,5286 **** --- 5442,5522 ---- PYTYPE_READY(FunctionType); PYTYPE_READY(OptionsType); PYTYPE_READY(OutputType); + #if PY_MAJOR_VERSION >= 3 + PYTYPE_READY(FinderType); + #endif + return 0; + } + + static int + init_sys_path() + { + PyObject *path; + PyObject *path_hook; + PyObject *path_hooks; + + if (!(path_hook = PyObject_GetAttrString(vim_module, "path_hook"))) + return -1; + + if (!(path_hooks = PySys_GetObject("path_hooks"))) + { + PyErr_Clear(); + path_hooks = PyList_New(1); + PyList_SET_ITEM(path_hooks, 0, path_hook); + if (PySys_SetObject("path_hooks", path_hooks)) + { + Py_DECREF(path_hooks); + return -1; + } + Py_DECREF(path_hooks); + } + else if (PyList_Check(path_hooks)) + { + if (PyList_Append(path_hooks, path_hook)) + { + Py_DECREF(path_hook); + return -1; + } + Py_DECREF(path_hook); + } + else + { + VimTryStart(); + EMSG(_("Failed to set path hook: sys.path_hooks is not a list\n" + "You should now do the following:\n" + "- append vim.path_hook to sys.path_hooks\n" + "- append vim.VIM_SPECIAL_PATH to sys.path\n")); + VimTryEnd(); /* Discard the error */ + Py_DECREF(path_hook); + return 0; + } + + if (!(path = PySys_GetObject("path"))) + { + PyErr_Clear(); + path = PyList_New(1); + Py_INCREF(vim_special_path_object); + PyList_SET_ITEM(path, 0, vim_special_path_object); + if (PySys_SetObject("path", path)) + { + Py_DECREF(path); + return -1; + } + Py_DECREF(path); + } + else if (PyList_Check(path)) + { + if (PyList_Append(path, vim_special_path_object)) + return -1; + } + else + { + VimTryStart(); + EMSG(_("Failed to set path: sys.path is not a list\n" + "You should now append vim.VIM_SPECIAL_PATH to sys.path")); + VimTryEnd(); /* Discard the error */ + } + return 0; } *************** *** 5332,5337 **** --- 5568,5576 ---- {"List", (PyObject *)&ListType}, {"Function", (PyObject *)&FunctionType}, {"Options", (PyObject *)&OptionsType}, + #if PY_MAJOR_VERSION >= 3 + {"Finder", (PyObject *)&FinderType}, + #endif }; typedef int (*object_adder)(PyObject *, const char *, PyObject *); *************** *** 5417,5421 **** --- 5656,5672 ---- else PyErr_Clear(); + if (!(vim_special_path_object = PyString_FromString(vim_special_path))) + return -1; + + ADD_OBJECT(m, "VIM_SPECIAL_PATH", vim_special_path_object); + + #if PY_MAJOR_VERSION >= 3 + ADD_OBJECT(m, "_PathFinder", path_finder); + ADD_CHECKED_OBJECT(m, "_find_module", + (py_find_module = PyObject_GetAttrString(path_finder, + "find_module"))); + #endif + return 0; } *** ../vim-7.3.1162/src/if_python.c 2013-06-10 20:47:33.000000000 +0200 --- src/if_python.c 2013-06-10 20:55:04.000000000 +0200 *************** *** 24,32 **** /* uncomment this if used with the debug version of python. * Checked on 2.7.4. */ /* #define Py_DEBUG */ ! /* Note: most of time you can add -DPy_DEBUG to CFLAGS in place of uncommenting */ ! /* uncomment this if used with the debug version of python, but without its * allocator */ /* #define Py_DEBUG_NO_PYMALLOC */ --- 24,32 ---- /* uncomment this if used with the debug version of python. * Checked on 2.7.4. */ /* #define Py_DEBUG */ ! /* Note: most of time you can add -DPy_DEBUG to CFLAGS in place of uncommenting */ ! /* uncomment this if used with the debug version of python, but without its * allocator */ /* #define Py_DEBUG_NO_PYMALLOC */ *************** *** 168,173 **** --- 168,174 ---- # define PyErr_SetNone dll_PyErr_SetNone # define PyErr_SetString dll_PyErr_SetString # define PyErr_SetObject dll_PyErr_SetObject + # define PyErr_ExceptionMatches dll_PyErr_ExceptionMatches # define PyEval_InitThreads dll_PyEval_InitThreads # define PyEval_RestoreThread dll_PyEval_RestoreThread # define PyEval_SaveThread dll_PyEval_SaveThread *************** *** 184,189 **** --- 185,191 ---- # define PyLong_Type (*dll_PyLong_Type) # define PyList_GetItem dll_PyList_GetItem # define PyList_Append dll_PyList_Append + # define PyList_Insert dll_PyList_Insert # define PyList_New dll_PyList_New # define PyList_SetItem dll_PyList_SetItem # define PyList_Size dll_PyList_Size *************** *** 233,238 **** --- 235,241 ---- # define PyFloat_Type (*dll_PyFloat_Type) # define PyImport_AddModule (*dll_PyImport_AddModule) # define PySys_SetObject dll_PySys_SetObject + # define PySys_GetObject dll_PySys_GetObject # define PySys_SetArgv dll_PySys_SetArgv # define PyType_Type (*dll_PyType_Type) # define PyType_Ready (*dll_PyType_Ready) *************** *** 305,310 **** --- 308,314 ---- static void(*dll_PyErr_SetNone)(PyObject *); static void(*dll_PyErr_SetString)(PyObject *, const char *); static void(*dll_PyErr_SetObject)(PyObject *, PyObject *); + static int(*dll_PyErr_ExceptionMatches)(PyObject *); static void(*dll_PyEval_InitThreads)(void); static void(*dll_PyEval_RestoreThread)(PyThreadState *); static PyThreadState*(*dll_PyEval_SaveThread)(void); *************** *** 320,326 **** static PyTypeObject* dll_PyInt_Type; static PyTypeObject* dll_PyLong_Type; static PyObject*(*dll_PyList_GetItem)(PyObject *, PyInt); ! static PyObject*(*dll_PyList_Append)(PyObject *, PyObject *); static PyObject*(*dll_PyList_New)(PyInt size); static int(*dll_PyList_SetItem)(PyObject *, PyInt, PyObject *); static PyInt(*dll_PyList_Size)(PyObject *); --- 324,331 ---- static PyTypeObject* dll_PyInt_Type; static PyTypeObject* dll_PyLong_Type; static PyObject*(*dll_PyList_GetItem)(PyObject *, PyInt); ! static int(*dll_PyList_Append)(PyObject *, PyObject *); ! static int(*dll_PyList_Insert)(PyObject *, int, PyObject *); static PyObject*(*dll_PyList_New)(PyInt size); static int(*dll_PyList_SetItem)(PyObject *, PyInt, PyObject *); static PyInt(*dll_PyList_Size)(PyObject *); *************** *** 366,371 **** --- 371,377 ---- static PyObject*(*dll_PyFloat_FromDouble)(double); static PyTypeObject* dll_PyFloat_Type; static int(*dll_PySys_SetObject)(char *, PyObject *); + static PyObject *(*dll_PySys_GetObject)(char *); static int(*dll_PySys_SetArgv)(int, char **); static PyTypeObject* dll_PyType_Type; static int (*dll_PyType_Ready)(PyTypeObject *type); *************** *** 431,436 **** --- 437,443 ---- static PyObject *imp_PyExc_TypeError; static PyObject *imp_PyExc_ValueError; static PyObject *imp_PyExc_RuntimeError; + static PyObject *imp_PyExc_ImportError; # define PyExc_AttributeError imp_PyExc_AttributeError # define PyExc_IndexError imp_PyExc_IndexError *************** *** 439,444 **** --- 446,452 ---- # define PyExc_TypeError imp_PyExc_TypeError # define PyExc_ValueError imp_PyExc_ValueError # define PyExc_RuntimeError imp_PyExc_RuntimeError + # define PyExc_ImportError imp_PyExc_ImportError /* * Table of name to function pointer of python. *************** *** 471,476 **** --- 479,485 ---- {"PyErr_SetNone", (PYTHON_PROC*)&dll_PyErr_SetNone}, {"PyErr_SetString", (PYTHON_PROC*)&dll_PyErr_SetString}, {"PyErr_SetObject", (PYTHON_PROC*)&dll_PyErr_SetObject}, + {"PyErr_ExceptionMatches", (PYTHON_PROC*)&dll_PyErr_ExceptionMatches}, {"PyEval_InitThreads", (PYTHON_PROC*)&dll_PyEval_InitThreads}, {"PyEval_RestoreThread", (PYTHON_PROC*)&dll_PyEval_RestoreThread}, {"PyEval_SaveThread", (PYTHON_PROC*)&dll_PyEval_SaveThread}, *************** *** 487,492 **** --- 496,502 ---- {"PyLong_Type", (PYTHON_PROC*)&dll_PyLong_Type}, {"PyList_GetItem", (PYTHON_PROC*)&dll_PyList_GetItem}, {"PyList_Append", (PYTHON_PROC*)&dll_PyList_Append}, + {"PyList_Insert", (PYTHON_PROC*)&dll_PyList_Insert}, {"PyList_New", (PYTHON_PROC*)&dll_PyList_New}, {"PyList_SetItem", (PYTHON_PROC*)&dll_PyList_SetItem}, {"PyList_Size", (PYTHON_PROC*)&dll_PyList_Size}, *************** *** 532,537 **** --- 542,548 ---- {"PyFloat_FromDouble", (PYTHON_PROC*)&dll_PyFloat_FromDouble}, {"PyImport_AddModule", (PYTHON_PROC*)&dll_PyImport_AddModule}, {"PySys_SetObject", (PYTHON_PROC*)&dll_PySys_SetObject}, + {"PySys_GetObject", (PYTHON_PROC*)&dll_PySys_GetObject}, {"PySys_SetArgv", (PYTHON_PROC*)&dll_PySys_SetArgv}, {"PyType_Type", (PYTHON_PROC*)&dll_PyType_Type}, {"PyType_Ready", (PYTHON_PROC*)&dll_PyType_Ready}, *************** *** 706,711 **** --- 717,723 ---- imp_PyExc_TypeError = PyDict_GetItemString(exdict, "TypeError"); imp_PyExc_ValueError = PyDict_GetItemString(exdict, "ValueError"); imp_PyExc_RuntimeError = PyDict_GetItemString(exdict, "RuntimeError"); + imp_PyExc_ImportError = PyDict_GetItemString(exdict, "ImportError"); Py_XINCREF(imp_PyExc_AttributeError); Py_XINCREF(imp_PyExc_IndexError); Py_XINCREF(imp_PyExc_KeyError); *************** *** 713,718 **** --- 725,731 ---- Py_XINCREF(imp_PyExc_TypeError); Py_XINCREF(imp_PyExc_ValueError); Py_XINCREF(imp_PyExc_RuntimeError); + Py_XINCREF(imp_PyExc_ImportError); Py_XDECREF(exmod); } #endif /* DYNAMIC_PYTHON */ *************** *** 735,740 **** --- 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 *************** *** 1359,1369 **** } #endif static int PythonMod_Init(void) { - PyObject *mod; - /* The special value is removed from sys.path in Python_Init(). */ static char *(argv[2]) = {"/must>not&exist/foo", NULL}; --- 1376,1487 ---- } #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 * + VimPathHook(PyObject *self UNUSED, PyObject *args) + { + char *path; + + if (PyArg_ParseTuple(args, "s", &path) + && STRCMP(path, vim_special_path) == 0) + { + Py_INCREF(vim_module); + return vim_module; + } + + PyErr_Clear(); + PyErr_SetNone(PyExc_ImportError); + return NULL; + } + static int PythonMod_Init(void) { /* The special value is removed from sys.path in Python_Init(). */ static char *(argv[2]) = {"/must>not&exist/foo", NULL}; *************** *** 1373,1382 **** /* Set sys.argv[] to avoid a crash in warn(). */ PySys_SetArgv(1, argv); ! mod = Py_InitModule4("vim", VimMethods, (char *)NULL, (PyObject *)NULL, ! PYTHON_API_VERSION); ! return populate_module(mod, PyModule_AddObject, PyObject_GetAttrString); } /************************************************************************* --- 1491,1507 ---- /* Set sys.argv[] to avoid a crash in warn(). */ PySys_SetArgv(1, argv); ! vim_module = Py_InitModule4("vim", VimMethods, (char *)NULL, ! (PyObject *)NULL, PYTHON_API_VERSION); ! ! if (populate_module(vim_module, PyModule_AddObject, ! PyObject_GetAttrString)) ! return -1; ! ! if (init_sys_path()) ! return -1; ! return 0; } /************************************************************************* *** ../vim-7.3.1162/src/if_python3.c 2013-06-10 18:36:20.000000000 +0200 --- src/if_python3.c 2013-06-10 20:55:44.000000000 +0200 *************** *** 134,139 **** --- 134,140 ---- # define PyErr_SetNone py3_PyErr_SetNone # define PyErr_SetString py3_PyErr_SetString # define PyErr_SetObject py3_PyErr_SetObject + # define PyErr_ExceptionMatches py3_PyErr_ExceptionMatches # define PyEval_InitThreads py3_PyEval_InitThreads # define PyEval_RestoreThread py3_PyEval_RestoreThread # define PyEval_SaveThread py3_PyEval_SaveThread *************** *** 143,148 **** --- 144,150 ---- # define PyLong_FromLong py3_PyLong_FromLong # define PyList_GetItem py3_PyList_GetItem # define PyList_Append py3_PyList_Append + # define PyList_Insert py3_PyList_Insert # define PyList_New py3_PyList_New # define PyList_SetItem py3_PyList_SetItem # define PyList_Size py3_PyList_Size *************** *** 177,182 **** --- 179,185 ---- # define PyEval_GetLocals py3_PyEval_GetLocals # define PyEval_GetGlobals py3_PyEval_GetGlobals # define PySys_SetObject py3_PySys_SetObject + # define PySys_GetObject py3_PySys_GetObject # define PySys_SetArgv py3_PySys_SetArgv # define PyType_Ready py3_PyType_Ready #undef Py_BuildValue *************** *** 268,274 **** static PyGILState_STATE (*py3_PyGILState_Ensure)(void); static void (*py3_PyGILState_Release)(PyGILState_STATE); static int (*py3_PySys_SetObject)(char *, PyObject *); ! static PyObject* (*py3_PyList_Append)(PyObject *, PyObject *); static Py_ssize_t (*py3_PyList_Size)(PyObject *); static int (*py3_PySequence_Check)(PyObject *); static Py_ssize_t (*py3_PySequence_Size)(PyObject *); --- 271,279 ---- static PyGILState_STATE (*py3_PyGILState_Ensure)(void); static void (*py3_PyGILState_Release)(PyGILState_STATE); static int (*py3_PySys_SetObject)(char *, PyObject *); ! static PyObject* (*py3_PySys_GetObject)(char *); ! static int (*py3_PyList_Append)(PyObject *, PyObject *); ! static int (*py3_PyList_Insert)(PyObject *, int, PyObject *); static Py_ssize_t (*py3_PyList_Size)(PyObject *); static int (*py3_PySequence_Check)(PyObject *); static Py_ssize_t (*py3_PySequence_Size)(PyObject *); *************** *** 284,289 **** --- 289,295 ---- static void (*py3_Py_Finalize)(void); static void (*py3_PyErr_SetString)(PyObject *, const char *); static void (*py3_PyErr_SetObject)(PyObject *, PyObject *); + static int (*py3_PyErr_ExceptionMatches)(PyObject *); static int (*py3_PyRun_SimpleString)(char *); static PyObject* (*py3_PyRun_String)(char *, int, PyObject *, PyObject *); static PyObject* (*py3_PyObject_GetAttrString)(PyObject *, const char *); *************** *** 393,398 **** --- 399,405 ---- static PyObject *p3imp_PyExc_TypeError; static PyObject *p3imp_PyExc_ValueError; static PyObject *p3imp_PyExc_RuntimeError; + static PyObject *p3imp_PyExc_ImportError; # define PyExc_AttributeError p3imp_PyExc_AttributeError # define PyExc_IndexError p3imp_PyExc_IndexError *************** *** 401,406 **** --- 408,414 ---- # define PyExc_TypeError p3imp_PyExc_TypeError # define PyExc_ValueError p3imp_PyExc_ValueError # define PyExc_RuntimeError p3imp_PyExc_RuntimeError + # define PyExc_ImportError p3imp_PyExc_ImportError /* * Table of name to function pointer of python. *************** *** 428,434 **** --- 436,444 ---- {"PyGILState_Ensure", (PYTHON_PROC*)&py3_PyGILState_Ensure}, {"PyGILState_Release", (PYTHON_PROC*)&py3_PyGILState_Release}, {"PySys_SetObject", (PYTHON_PROC*)&py3_PySys_SetObject}, + {"PySys_GetObject", (PYTHON_PROC*)&py3_PySys_GetObject}, {"PyList_Append", (PYTHON_PROC*)&py3_PyList_Append}, + {"PyList_Insert", (PYTHON_PROC*)&py3_PyList_Insert}, {"PyList_Size", (PYTHON_PROC*)&py3_PyList_Size}, {"PySequence_Check", (PYTHON_PROC*)&py3_PySequence_Check}, {"PySequence_Size", (PYTHON_PROC*)&py3_PySequence_Size}, *************** *** 441,446 **** --- 451,457 ---- {"Py_Finalize", (PYTHON_PROC*)&py3_Py_Finalize}, {"PyErr_SetString", (PYTHON_PROC*)&py3_PyErr_SetString}, {"PyErr_SetObject", (PYTHON_PROC*)&py3_PyErr_SetObject}, + {"PyErr_ExceptionMatches", (PYTHON_PROC*)&py3_PyErr_ExceptionMatches}, {"PyRun_SimpleString", (PYTHON_PROC*)&py3_PyRun_SimpleString}, {"PyRun_String", (PYTHON_PROC*)&py3_PyRun_String}, {"PyObject_GetAttrString", (PYTHON_PROC*)&py3_PyObject_GetAttrString}, *************** *** 664,669 **** --- 675,681 ---- p3imp_PyExc_TypeError = PyDict_GetItemString(exdict, "TypeError"); p3imp_PyExc_ValueError = PyDict_GetItemString(exdict, "ValueError"); p3imp_PyExc_RuntimeError = PyDict_GetItemString(exdict, "RuntimeError"); + p3imp_PyExc_ImportError = PyDict_GetItemString(exdict, "ImportError"); Py_XINCREF(p3imp_PyExc_AttributeError); Py_XINCREF(p3imp_PyExc_IndexError); Py_XINCREF(p3imp_PyExc_KeyError); *************** *** 671,676 **** --- 683,689 ---- Py_XINCREF(p3imp_PyExc_TypeError); Py_XINCREF(p3imp_PyExc_ValueError); Py_XINCREF(p3imp_PyExc_RuntimeError); + Py_XINCREF(p3imp_PyExc_ImportError); Py_XDECREF(exmod); } #endif /* DYNAMIC_PYTHON3 */ *************** *** 723,730 **** --- 736,748 ---- static int ListSetattro(PyObject *, PyObject *, PyObject *); static PyObject *FunctionGetattro(PyObject *, PyObject *); + static PyObject *VimPathHook(PyObject *, PyObject *); + static struct PyModuleDef vimmodule; + static PyObject *path_finder; + static PyObject *py_find_module = NULL; + #define PY_CAN_RECURSE /* *************** *** 1585,1596 **** #endif static PyObject * ! Py3Init_vim(void) { ! PyObject *mod; /* The special value is removed from sys.path in Python3_Init(). */ static wchar_t *(argv[2]) = {L"/must>not&exist/foo", NULL}; if (init_types()) return NULL; --- 1603,1672 ---- #endif static PyObject * ! VimPathHook(PyObject *self UNUSED, PyObject *args) { ! char *path; ! ! if (PyArg_ParseTuple(args, "s", &path) ! && STRCMP(path, vim_special_path) == 0) ! { ! Py_INCREF(&FinderType); ! return (PyObject *) &FinderType; ! } ! ! PyErr_Clear(); ! PyErr_SetNone(PyExc_ImportError); ! return NULL; ! } ! ! static PyObject * ! FinderFindModule(PyObject *cls UNUSED, PyObject *fullname) ! { ! PyObject *new_path; ! PyObject *r; ! ! if (!(new_path = Vim_GetPaths(NULL))) ! return NULL; ! ! /* call find_module of the super() class */ ! r = PyObject_CallFunctionObjArgs(py_find_module, fullname, new_path, NULL); ! ! Py_DECREF(new_path); ! ! return r; ! } + static struct PyMethodDef FinderMethods[] = { + {"find_module", FinderFindModule, METH_CLASS|METH_O, ""}, + {NULL, NULL, 0, NULL} + }; + + static PyObject * + Py3Init_vim(void) + { /* The special value is removed from sys.path in Python3_Init(). */ static wchar_t *(argv[2]) = {L"/must>not&exist/foo", NULL}; + PyObject *importlib_machinery; + + if (!(importlib_machinery = PyImport_ImportModule("importlib.machinery"))) + return NULL; + + if (!(path_finder = PyObject_GetAttrString(importlib_machinery, + "PathFinder"))) + { + Py_DECREF(importlib_machinery); + return NULL; + } + + Py_DECREF(importlib_machinery); + + vim_memset(&FinderType, 0, sizeof(FinderObject)); + FinderType.tp_name = "vim.Finder"; + FinderType.tp_basicsize = sizeof(FinderObject); + FinderType.tp_base = (PyTypeObject *) path_finder; + FinderType.tp_flags = Py_TPFLAGS_DEFAULT; + FinderType.tp_doc = "Vim finder class, for use with path hook"; + FinderType.tp_methods = FinderMethods; if (init_types()) return NULL; *************** *** 1598,1611 **** /* Set sys.argv[] to avoid a crash in warn(). */ PySys_SetArgv(1, argv); ! mod = PyModule_Create(&vimmodule); ! if (mod == NULL) return NULL; ! if (populate_module(mod, PyModule_AddObject, PyObject_GetAttrString)) return NULL; ! return mod; } /************************************************************************* --- 1674,1689 ---- /* Set sys.argv[] to avoid a crash in warn(). */ PySys_SetArgv(1, argv); ! if ((vim_module = PyModule_Create(&vimmodule)) == NULL) ! return NULL; ! ! if (populate_module(vim_module, PyModule_AddObject, PyObject_GetAttrString)) return NULL; ! if (init_sys_path()) return NULL; ! return vim_module; } /************************************************************************* *** ../vim-7.3.1162/src/testdir/test86.in 2013-06-02 18:54:16.000000000 +0200 --- src/testdir/test86.in 2013-06-10 21:05:44.000000000 +0200 *************** *** 1069,1074 **** --- 1069,1082 ---- ee('vim.current.xxx = True') EOF :" + :" Test import TODO: BROKEN + :"py << EOF + :"vim.options['rtp'] = os.getcwd().replace(',', '\\,').replace('\\', '\\\\') + :"from module import dir as d + :"from modulex import ddir + :"cb.append(d + ',' + ddir) + :"EOF + :" :" Test exceptions :fun Exe(e) : execute a:e *** ../vim-7.3.1162/src/testdir/test87.in 2013-06-02 18:54:16.000000000 +0200 --- src/testdir/test87.in 2013-06-10 21:06:37.000000000 +0200 *************** *** 1036,1041 **** --- 1036,1049 ---- ee('vim.current.xxx = True') EOF :" + :" Test import TODO: BROKEN + :"py3 << EOF + :"vim.options['rtp'] = os.getcwd().replace(',', '\\,').replace('\\', '\\\\') + :"from module import dir as d + :"from modulex import ddir + :"cb.append(d + ',' + ddir) + :"EOF + :" :" Test exceptions :fun Exe(e) : execute a:e *** ../vim-7.3.1162/src/auto/configure 2013-06-02 19:14:11.000000000 +0200 --- src/auto/configure 2013-06-10 21:22:52.000000000 +0200 *************** *** 5289,5298 **** { $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_var_python_version" >&5 $as_echo "$vi_cv_var_python_version" >&6; } ! { $as_echo "$as_me:${as_lineno-$LINENO}: checking Python is 2.2 or better" >&5 ! $as_echo_n "checking Python is 2.2 or better... " >&6; } if ${vi_cv_path_python} -c \ ! "import sys; sys.exit(${vi_cv_var_python_version} < 2.2)" then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yep" >&5 $as_echo "yep" >&6; } --- 5289,5298 ---- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $vi_cv_var_python_version" >&5 $as_echo "$vi_cv_var_python_version" >&6; } ! { $as_echo "$as_me:${as_lineno-$LINENO}: checking Python is 2.3 or better" >&5 ! $as_echo_n "checking Python is 2.3 or better... " >&6; } if ${vi_cv_path_python} -c \ ! "import sys; sys.exit(${vi_cv_var_python_version} < 2.3)" then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yep" >&5 $as_echo "yep" >&6; } *** ../vim-7.3.1162/src/version.c 2013-06-10 20:47:33.000000000 +0200 --- src/version.c 2013-06-10 20:53:23.000000000 +0200 *************** *** 730,731 **** --- 730,733 ---- { /* Add new patch number below this line */ + /**/ + 1163, /**/ -- The coffee just wasn't strong enough to defend itself -- Tom Waits /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///