1
0
forked from aniani/vim

updated for version 7.3.1163

Problem:    Not easy to load Python modules.
Solution:   Search "python2", "python3" and "pythonx" directories in
            'runtimepath' for Python modules. (ZyX)
This commit is contained in:
Bram Moolenaar 2013-06-10 21:27:29 +02:00
parent f9c9b32bd1
commit c09a6d6c0c
10 changed files with 627 additions and 32 deletions

View File

@ -180,6 +180,12 @@ vim.strwidth(str) *python-strwidth*
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,6 +306,113 @@ Output from Python *python-output*
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*

6
src/auto/configure vendored
View File

@ -5289,10 +5289,10 @@ fi
{ $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; }
{ $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.2)"
"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; }

View File

@ -863,10 +863,10 @@ if test "$enable_pythoninterp" = "yes" -o "$enable_pythoninterp" = "dynamic"; th
${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)
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.2)"
"import sys; sys.exit(${vi_cv_var_python_version} < 2.3)"
then
AC_MSG_RESULT(yep)

View File

@ -2737,6 +2737,10 @@ source_runtime(name, all)
* 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,7 +2772,7 @@ do_in_runtimepath(name, all, callback, cookie)
buf = alloc(MAXPATHL);
if (buf != NULL && rtp_copy != NULL)
{
if (p_verbose > 1)
if (p_verbose > 1 && name != NULL)
{
verbose_enter();
smsg((char_u *)_("Searching for \"%s\" in \"%s\""),
@ -2782,7 +2786,13 @@ do_in_runtimepath(name, all, callback, cookie)
{
/* Copy the path from 'runtimepath' to buf[]. */
copy_option_part(&rtp, buf, MAXPATHL, ",");
if (STRLEN(buf) + STRLEN(name) + 2 < 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,7 +2831,7 @@ do_in_runtimepath(name, all, callback, cookie)
}
vim_free(buf);
vim_free(rtp_copy);
if (p_verbose > 0 && !did_one)
if (p_verbose > 0 && !did_one && name != NULL)
{
verbose_enter();
smsg((char_u *)_("not found in 'runtimepath': \"%s\""), name);

View File

@ -24,6 +24,8 @@ typedef int Py_ssize_t; /* Python 2.4 and earlier don't have this type. */
#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,6 +57,8 @@ static PyObject *globals;
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,19 +783,168 @@ VimFchdir(PyObject *self UNUSED, PyObject *args, PyObject *kwargs)
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 <Tab> 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 }
/* 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 <Tab> 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,6 +5189,14 @@ typedef struct
} CurrentObject;
static PyTypeObject CurrentType;
#if PY_MAJOR_VERSION >= 3
typedef struct
{
PyObject_HEAD
} FinderObject;
static PyTypeObject FinderType;
#endif
static void
init_structs(void)
{
@ -5281,6 +5442,81 @@ init_types()
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,6 +5568,9 @@ static struct object_constant {
{"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,5 +5656,17 @@ populate_module(PyObject *m, object_adder add_object, attr_getter get_attr)
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;
}

View File

@ -24,9 +24,9 @@
/* 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
/* 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
/* uncomment this if used with the debug version of python, but without its
* allocator */
/* #define Py_DEBUG_NO_PYMALLOC */
@ -168,6 +168,7 @@ struct PyMethodDef { Py_ssize_t a; };
# 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,6 +185,7 @@ struct PyMethodDef { Py_ssize_t a; };
# 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,6 +235,7 @@ struct PyMethodDef { Py_ssize_t a; };
# 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,6 +308,7 @@ static PyObject*(*dll_PyErr_Occurred)(void);
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,7 +324,8 @@ static PyTypeObject* dll_PyBool_Type;
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 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,6 +371,7 @@ static double(*dll_PyFloat_AsDouble)(PyObject *);
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,6 +437,7 @@ static PyObject *imp_PyExc_KeyboardInterrupt;
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,6 +446,7 @@ static PyObject *imp_PyExc_RuntimeError;
# 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,6 +479,7 @@ static struct
{"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,6 +496,7 @@ static struct
{"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,6 +542,7 @@ static struct
{"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,6 +717,7 @@ get_exceptions(void)
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,6 +725,7 @@ get_exceptions(void)
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,6 +748,10 @@ static PyObject *DictionaryGetattr(PyObject *, char*);
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,11 +1376,112 @@ python_tabpage_free(tabpage_T *tab)
}
#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)
{
PyObject *mod;
/* The special value is removed from sys.path in Python_Init(). */
static char *(argv[2]) = {"/must>not&exist/foo", NULL};
@ -1373,10 +1491,17 @@ PythonMod_Init(void)
/* 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);
vim_module = Py_InitModule4("vim", VimMethods, (char *)NULL,
(PyObject *)NULL, PYTHON_API_VERSION);
return populate_module(mod, PyModule_AddObject, PyObject_GetAttrString);
if (populate_module(vim_module, PyModule_AddObject,
PyObject_GetAttrString))
return -1;
if (init_sys_path())
return -1;
return 0;
}
/*************************************************************************

View File

@ -134,6 +134,7 @@
# 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,6 +144,7 @@
# 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,6 +179,7 @@
# 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,7 +271,9 @@ static PyObject* (*py3_PyList_New)(Py_ssize_t size);
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 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,6 +289,7 @@ static PyObject* (*py3_PyErr_NoMemory)(void);
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,6 +399,7 @@ static PyObject *p3imp_PyExc_KeyboardInterrupt;
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,6 +408,7 @@ static PyObject *p3imp_PyExc_RuntimeError;
# 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,7 +436,9 @@ static struct
{"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,6 +451,7 @@ static struct
{"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,6 +675,7 @@ get_py3_exceptions()
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,6 +683,7 @@ get_py3_exceptions()
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,8 +736,13 @@ static PyObject *ListGetattro(PyObject *, PyObject *);
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
/*
@ -1584,13 +1602,71 @@ python3_tabpage_free(tabpage_T *tab)
}
#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)
{
PyObject *mod;
/* 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,14 +1674,16 @@ Py3Init_vim(void)
/* Set sys.argv[] to avoid a crash in warn(). */
PySys_SetArgv(1, argv);
mod = PyModule_Create(&vimmodule);
if (mod == NULL)
if ((vim_module = PyModule_Create(&vimmodule)) == NULL)
return NULL;
if (populate_module(mod, PyModule_AddObject, PyObject_GetAttrString))
if (populate_module(vim_module, PyModule_AddObject, PyObject_GetAttrString))
return NULL;
return mod;
if (init_sys_path())
return NULL;
return vim_module;
}
/*************************************************************************

View File

@ -1069,6 +1069,14 @@ ee('vim.current.tabpage = True')
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

View File

@ -1036,6 +1036,14 @@ ee('vim.current.tabpage = True')
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

View File

@ -728,6 +728,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
1163,
/**/
1162,
/**/