changeset 3828:fd6ef931aa77 v7.3.672

updated for version 7.3.672 Problem: Not possible to lock/unlock lists in Python interface. Solution: Add .locked and .scope attributes. (ZyX)
author Bram Moolenaar <bram@vim.org>
date Fri, 21 Sep 2012 14:00:35 +0200
parents 72c860159c0f
children 25f9e59741f9
files src/if_py_both.h src/if_python.c src/if_python3.c src/testdir/test86.in src/testdir/test86.ok src/testdir/test87.in src/testdir/test87.ok src/version.c
diffstat 8 files changed, 261 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/src/if_py_both.h
+++ b/src/if_py_both.h
@@ -808,6 +808,44 @@ pymap_to_tv(PyObject *obj, typval_T *tv,
 }
 
     static PyInt
+DictionarySetattr(DictionaryObject *self, char *name, PyObject *val)
+{
+    if (val == NULL)
+    {
+	PyErr_SetString(PyExc_AttributeError, _("Cannot delete DictionaryObject attributes"));
+	return -1;
+    }
+
+    if (strcmp(name, "locked") == 0)
+    {
+	if (self->dict->dv_lock == VAR_FIXED)
+	{
+	    PyErr_SetString(PyExc_TypeError, _("Cannot modify fixed dictionary"));
+	    return -1;
+	}
+	else
+	{
+	    if (!PyBool_Check(val))
+	    {
+		PyErr_SetString(PyExc_TypeError, _("Only boolean objects are allowed"));
+		return -1;
+	    }
+
+	    if (val == Py_True)
+		self->dict->dv_lock = VAR_LOCKED;
+	    else
+		self->dict->dv_lock = 0;
+	}
+	return 0;
+    }
+    else
+    {
+	PyErr_SetString(PyExc_AttributeError, _("Cannot set this attribute"));
+	return -1;
+    }
+}
+
+    static PyInt
 DictionaryLength(PyObject *self)
 {
     return ((PyInt) ((((DictionaryObject *)(self))->dict->dv_hashtab.ht_used)));
@@ -1271,6 +1309,44 @@ ListConcatInPlace(PyObject *self, PyObje
     return self;
 }
 
+    static int
+ListSetattr(ListObject *self, char *name, PyObject *val)
+{
+    if (val == NULL)
+    {
+	PyErr_SetString(PyExc_AttributeError, _("Cannot delete DictionaryObject attributes"));
+	return -1;
+    }
+
+    if (strcmp(name, "locked") == 0)
+    {
+	if (self->list->lv_lock == VAR_FIXED)
+	{
+	    PyErr_SetString(PyExc_TypeError, _("Cannot modify fixed list"));
+	    return -1;
+	}
+	else
+	{
+	    if (!PyBool_Check(val))
+	    {
+		PyErr_SetString(PyExc_TypeError, _("Only boolean objects are allowed"));
+		return -1;
+	    }
+
+	    if (val == Py_True)
+		self->list->lv_lock = VAR_LOCKED;
+	    else
+		self->list->lv_lock = 0;
+	}
+	return 0;
+    }
+    else
+    {
+	PyErr_SetString(PyExc_AttributeError, _("Cannot set this attribute"));
+	return -1;
+    }
+}
+
 static struct PyMethodDef ListMethods[] = {
     {"extend", (PyCFunction)ListConcatInPlace, METH_O, ""},
     { NULL,	    NULL,		0,	    NULL }
--- a/src/if_python.c
+++ b/src/if_python.c
@@ -163,6 +163,7 @@ struct PyMethodDef { Py_ssize_t a; };
 # define PyInt_FromLong dll_PyInt_FromLong
 # define PyLong_AsLong dll_PyLong_AsLong
 # define PyLong_FromLong dll_PyLong_FromLong
+# define PyBool_Type (*dll_PyBool_Type)
 # define PyInt_Type (*dll_PyInt_Type)
 # define PyLong_Type (*dll_PyLong_Type)
 # define PyList_GetItem dll_PyList_GetItem
@@ -221,6 +222,8 @@ struct PyMethodDef { Py_ssize_t a; };
 #  define _PyObject_NextNotImplemented (*dll__PyObject_NextNotImplemented)
 # endif
 # define _Py_NoneStruct (*dll__Py_NoneStruct)
+# define _Py_ZeroStruct (*dll__Py_ZeroStruct)
+# define _Py_TrueStruct (*dll__Py_TrueStruct)
 # define PyObject_Init dll__PyObject_Init
 # define PyObject_GetIter dll_PyObject_GetIter
 # if defined(PY_VERSION_HEX) && PY_VERSION_HEX >= 0x02020000
@@ -263,6 +266,7 @@ static long(*dll_PyInt_AsLong)(PyObject 
 static PyObject*(*dll_PyInt_FromLong)(long);
 static long(*dll_PyLong_AsLong)(PyObject *);
 static PyObject*(*dll_PyLong_FromLong)(long);
+static PyTypeObject* dll_PyBool_Type;
 static PyTypeObject* dll_PyInt_Type;
 static PyTypeObject* dll_PyLong_Type;
 static PyObject*(*dll_PyList_GetItem)(PyObject *, PyInt);
@@ -320,6 +324,8 @@ static PyObject* (*dll_PyObject_GetIter)
 static iternextfunc dll__PyObject_NextNotImplemented;
 # endif
 static PyObject* dll__Py_NoneStruct;
+static PyObject* _Py_ZeroStruct;
+static PyObject* dll__Py_TrueStruct;
 # if defined(PY_VERSION_HEX) && PY_VERSION_HEX >= 0x02020000
 static int (*dll_PyType_IsSubtype)(PyTypeObject *, PyTypeObject *);
 # endif
@@ -389,6 +395,7 @@ static struct
     {"PyInt_FromLong", (PYTHON_PROC*)&dll_PyInt_FromLong},
     {"PyLong_AsLong", (PYTHON_PROC*)&dll_PyLong_AsLong},
     {"PyLong_FromLong", (PYTHON_PROC*)&dll_PyLong_FromLong},
+    {"PyBool_Type", (PYTHON_PROC*)&dll_PyBool_Type},
     {"PyInt_Type", (PYTHON_PROC*)&dll_PyInt_Type},
     {"PyLong_Type", (PYTHON_PROC*)&dll_PyLong_Type},
     {"PyList_GetItem", (PYTHON_PROC*)&dll_PyList_GetItem},
@@ -449,6 +456,8 @@ static struct
     {"_PyObject_NextNotImplemented", (PYTHON_PROC*)&dll__PyObject_NextNotImplemented},
 # endif
     {"_Py_NoneStruct", (PYTHON_PROC*)&dll__Py_NoneStruct},
+    {"_Py_ZeroStruct", (PYTHON_PROC*)&dll__Py_ZeroStruct},
+    {"_Py_TrueStruct", (PYTHON_PROC*)&dll__Py_TrueStruct},
 # if defined(PY_VERSION_HEX) && PY_VERSION_HEX >= 0x02020000
     {"PyType_IsSubtype", (PYTHON_PROC*)&dll_PyType_IsSubtype},
 # endif
@@ -1563,6 +1572,10 @@ PythonMod_Init(void)
     PyDict_SetItemString(dict, "buffers", (PyObject *)(void *)&TheBufferList);
     PyDict_SetItemString(dict, "current", (PyObject *)(void *)&TheCurrent);
     PyDict_SetItemString(dict, "windows", (PyObject *)(void *)&TheWindowList);
+    PyDict_SetItemString(dict, "VAR_LOCKED",    PyInt_FromLong(VAR_LOCKED));
+    PyDict_SetItemString(dict, "VAR_FIXED",     PyInt_FromLong(VAR_FIXED));
+    PyDict_SetItemString(dict, "VAR_SCOPE",     PyInt_FromLong(VAR_SCOPE));
+    PyDict_SetItemString(dict, "VAR_DEF_SCOPE", PyInt_FromLong(VAR_DEF_SCOPE));
 
     if (PyErr_Occurred())
 	return -1;
@@ -1629,7 +1642,7 @@ static PyTypeObject DictionaryType = {
     (destructor)  DictionaryDestructor,
     (printfunc)   0,
     (getattrfunc) DictionaryGetattr,
-    (setattrfunc) 0,
+    (setattrfunc) DictionarySetattr,
     (cmpfunc)     0,
     (reprfunc)    0,
 
@@ -1656,6 +1669,13 @@ DictionaryDestructor(PyObject *self)
     static PyObject *
 DictionaryGetattr(PyObject *self, char *name)
 {
+    DictionaryObject	*this = ((DictionaryObject *) (self));
+
+    if (strcmp(name, "locked") == 0)
+	return PyInt_FromLong(this->dict->dv_lock);
+    else if (strcmp(name, "scope") == 0)
+	return PyInt_FromLong(this->dict->dv_scope);
+
     return Py_FindMethod(DictionaryMethods, self, name);
 }
 
@@ -1687,7 +1707,7 @@ static PyTypeObject ListType = {
     (destructor)  ListDestructor,
     (printfunc)   0,
     (getattrfunc) ListGetattr,
-    (setattrfunc) 0,
+    (setattrfunc) ListSetattr,
     (cmpfunc)     0,
     (reprfunc)    0,
 
@@ -1714,6 +1734,9 @@ ListDestructor(PyObject *self)
     static PyObject *
 ListGetattr(PyObject *self, char *name)
 {
+    if (strcmp(name, "locked") == 0)
+	return PyInt_FromLong(((ListObject *)(self))->list->lv_lock);
+
     return Py_FindMethod(ListMethods, self, name);
 }
 
--- a/src/if_python3.c
+++ b/src/if_python3.c
@@ -161,7 +161,6 @@ static void init_structs(void);
 # define PyRun_String py3_PyRun_String
 # define PySys_SetObject py3_PySys_SetObject
 # define PySys_SetArgv py3_PySys_SetArgv
-# define PyType_Type (*py3_PyType_Type)
 # define PyType_Ready py3_PyType_Ready
 #undef Py_BuildValue
 # define Py_BuildValue py3_Py_BuildValue
@@ -170,6 +169,8 @@ static void init_structs(void);
 # define Py_Finalize py3_Py_Finalize
 # define Py_IsInitialized py3_Py_IsInitialized
 # define _Py_NoneStruct (*py3__Py_NoneStruct)
+# define _Py_FalseStruct (*py3__Py_FalseStruct)
+# define _Py_TrueStruct (*py3__Py_TrueStruct)
 # define _PyObject_NextNotImplemented (*py3__PyObject_NextNotImplemented)
 # define PyModule_AddObject py3_PyModule_AddObject
 # define PyImport_AppendInittab py3_PyImport_AppendInittab
@@ -184,8 +185,10 @@ static void init_structs(void);
 # define PyFloat_FromDouble py3_PyFloat_FromDouble
 # define PyFloat_AsDouble py3_PyFloat_AsDouble
 # define PyObject_GenericGetAttr py3_PyObject_GenericGetAttr
+# define PyType_Type (*py3_PyType_Type)
 # define PySlice_Type (*py3_PySlice_Type)
 # define PyFloat_Type (*py3_PyFloat_Type)
+# define PyBool_Type (*py3_PyBool_Type)
 # define PyErr_NewException py3_PyErr_NewException
 # ifdef Py_DEBUG
 #  define _Py_NegativeRefcount py3__Py_NegativeRefcount
@@ -245,7 +248,6 @@ static PyObject* (*py3_PyList_GetItem)(P
 static PyObject* (*py3_PyImport_ImportModule)(const char *);
 static PyObject* (*py3_PyImport_AddModule)(const char *);
 static int (*py3_PyErr_BadArgument)(void);
-static PyTypeObject* py3_PyType_Type;
 static PyObject* (*py3_PyErr_Occurred)(void);
 static PyObject* (*py3_PyModule_GetDict)(PyObject *);
 static int (*py3_PyList_SetItem)(PyObject *, Py_ssize_t, PyObject *);
@@ -275,6 +277,8 @@ static void (*py3_PyErr_Clear)(void);
 static PyObject*(*py3__PyObject_Init)(PyObject *, PyTypeObject *);
 static iternextfunc py3__PyObject_NextNotImplemented;
 static PyObject* py3__Py_NoneStruct;
+static PyObject* py3__Py_FalseStruct;
+static PyObject* py3__Py_TrueStruct;
 static int (*py3_PyModule_AddObject)(PyObject *m, const char *name, PyObject *o);
 static int (*py3_PyImport_AppendInittab)(const char *name, PyObject* (*initfunc)(void));
 static char* (*py3__PyUnicode_AsString)(PyObject *unicode);
@@ -288,8 +292,10 @@ static PyObject* (*py3_PyObject_GenericG
 static PyObject* (*py3_PyModule_Create2)(struct PyModuleDef* module, int module_api_version);
 static PyObject* (*py3_PyType_GenericAlloc)(PyTypeObject *type, Py_ssize_t nitems);
 static PyObject* (*py3_PyType_GenericNew)(PyTypeObject *type, PyObject *args, PyObject *kwds);
+static PyTypeObject* py3_PyType_Type;
 static PyTypeObject* py3_PySlice_Type;
 static PyTypeObject* py3_PyFloat_Type;
+static PyTypeObject* py3_PyBool_Type;
 static PyObject* (*py3_PyErr_NewException)(char *name, PyObject *base, PyObject *dict);
 static PyObject* (*py3_PyCapsule_New)(void *, char *, PyCapsule_Destructor);
 static void* (*py3_PyCapsule_GetPointer)(PyObject *, char *);
@@ -363,7 +369,6 @@ static struct
     {"PyImport_ImportModule", (PYTHON_PROC*)&py3_PyImport_ImportModule},
     {"PyImport_AddModule", (PYTHON_PROC*)&py3_PyImport_AddModule},
     {"PyErr_BadArgument", (PYTHON_PROC*)&py3_PyErr_BadArgument},
-    {"PyType_Type", (PYTHON_PROC*)&py3_PyType_Type},
     {"PyErr_Occurred", (PYTHON_PROC*)&py3_PyErr_Occurred},
     {"PyModule_GetDict", (PYTHON_PROC*)&py3_PyModule_GetDict},
     {"PyList_SetItem", (PYTHON_PROC*)&py3_PyList_SetItem},
@@ -386,6 +391,8 @@ static struct
     {"Py_IsInitialized", (PYTHON_PROC*)&py3_Py_IsInitialized},
     {"_PyObject_NextNotImplemented", (PYTHON_PROC*)&py3__PyObject_NextNotImplemented},
     {"_Py_NoneStruct", (PYTHON_PROC*)&py3__Py_NoneStruct},
+    {"_Py_FalseStruct", (PYTHON_PROC*)&py3__Py_FalseStruct},
+    {"_Py_TrueStruct", (PYTHON_PROC*)&py3__Py_TrueStruct},
     {"PyErr_Clear", (PYTHON_PROC*)&py3_PyErr_Clear},
     {"PyObject_Init", (PYTHON_PROC*)&py3__PyObject_Init},
     {"PyModule_AddObject", (PYTHON_PROC*)&py3_PyModule_AddObject},
@@ -400,8 +407,10 @@ static struct
     {"PyModule_Create2", (PYTHON_PROC*)&py3_PyModule_Create2},
     {"PyType_GenericAlloc", (PYTHON_PROC*)&py3_PyType_GenericAlloc},
     {"PyType_GenericNew", (PYTHON_PROC*)&py3_PyType_GenericNew},
+    {"PyType_Type", (PYTHON_PROC*)&py3_PyType_Type},
     {"PySlice_Type", (PYTHON_PROC*)&py3_PySlice_Type},
     {"PyFloat_Type", (PYTHON_PROC*)&py3_PyFloat_Type},
+    {"PyBool_Type", (PYTHON_PROC*)&py3_PyBool_Type},
     {"PyErr_NewException", (PYTHON_PROC*)&py3_PyErr_NewException},
 # ifdef Py_DEBUG
     {"_Py_NegativeRefcount", (PYTHON_PROC*)&py3__Py_NegativeRefcount},
@@ -1534,6 +1543,28 @@ static PyMappingMethods DictionaryAsMapp
     /* mp_ass_subscript */ (objobjargproc) DictionaryAssItem,
 };
 
+    static PyObject *
+DictionaryGetattro(PyObject *self, PyObject *nameobj)
+{
+    DictionaryObject	*this = ((DictionaryObject *) (self));
+
+    GET_ATTR_STRING(name, nameobj);
+
+    if (strcmp(name, "locked") == 0)
+	return PyLong_FromLong(this->dict->dv_lock);
+    else if (strcmp(name, "scope") == 0)
+	return PyLong_FromLong(this->dict->dv_scope);
+
+    return PyObject_GenericGetAttr(self, nameobj);
+}
+
+    static int
+DictionarySetattro(PyObject *self, PyObject *nameobj, PyObject *val)
+{
+    GET_ATTR_STRING(name, nameobj);
+    return DictionarySetattr((DictionaryObject *) self, name, val);
+}
+
 static PyTypeObject DictionaryType;
 
     static void
@@ -1625,6 +1656,24 @@ ListAsSubscript(PyObject *self, PyObject
     }
 }
 
+    static PyObject *
+ListGetattro(PyObject *self, PyObject *nameobj)
+{
+    GET_ATTR_STRING(name, nameobj);
+
+    if (strcmp(name, "locked") == 0)
+	return PyLong_FromLong(((ListObject *) (self))->list->lv_lock);
+
+    return PyObject_GenericGetAttr(self, nameobj);
+}
+
+    static int
+ListSetattro(PyObject *self, PyObject *nameobj, PyObject *val)
+{
+    GET_ATTR_STRING(name, nameobj);
+    return ListSetattr((ListObject *) self, name, val);
+}
+
     static void
 ListDestructor(PyObject *self)
 {
@@ -1713,6 +1762,7 @@ static struct PyModuleDef vimmodule;
 PyMODINIT_FUNC Py3Init_vim(void)
 {
     PyObject *mod;
+    PyObject *tmp;
     /* The special value is removed from sys.path in Python3_Init(). */
     static wchar_t *(argv[2]) = {L"/must>not&exist/foo", NULL};
 
@@ -1744,6 +1794,16 @@ PyMODINIT_FUNC Py3Init_vim(void)
     Py_INCREF((PyObject *)(void *)&TheWindowList);
     PyModule_AddObject(mod, "windows", (PyObject *)(void *)&TheWindowList);
 
+#define ADD_INT_CONSTANT(name, value) \
+    tmp = PyLong_FromLong(value); \
+    Py_INCREF(tmp); \
+    PyModule_AddObject(mod, name, tmp)
+
+    ADD_INT_CONSTANT("VAR_LOCKED",     VAR_LOCKED);
+    ADD_INT_CONSTANT("VAR_FIXED",      VAR_FIXED);
+    ADD_INT_CONSTANT("VAR_SCOPE",      VAR_SCOPE);
+    ADD_INT_CONSTANT("VAR_DEF_SCOPE",  VAR_DEF_SCOPE);
+
     if (PyErr_Occurred())
 	return NULL;
 
@@ -1899,6 +1959,8 @@ init_structs(void)
     vim_memset(&DictionaryType, 0, sizeof(DictionaryType));
     DictionaryType.tp_name = "vim.dictionary";
     DictionaryType.tp_basicsize = sizeof(DictionaryObject);
+    DictionaryType.tp_getattro = DictionaryGetattro;
+    DictionaryType.tp_setattro = DictionarySetattro;
     DictionaryType.tp_dealloc = DictionaryDestructor;
     DictionaryType.tp_as_mapping = &DictionaryAsMapping;
     DictionaryType.tp_flags = Py_TPFLAGS_DEFAULT;
@@ -1909,6 +1971,8 @@ init_structs(void)
     ListType.tp_name = "vim.list";
     ListType.tp_dealloc = ListDestructor;
     ListType.tp_basicsize = sizeof(ListObject);
+    ListType.tp_getattro = ListGetattro;
+    ListType.tp_setattro = ListSetattro;
     ListType.tp_as_sequence = &ListAsSeq;
     ListType.tp_as_mapping = &ListAsMapping;
     ListType.tp_flags = Py_TPFLAGS_DEFAULT;
--- a/src/testdir/test86.in
+++ b/src/testdir/test86.in
@@ -211,6 +211,41 @@ except Exception as e:
     m.extend([e.__class__.__name__])
 EOF
 :$put =messages
+:unlet messages
+:" locked and scope attributes
+:let d={} | let dl={} | lockvar dl
+:for s in split("d dl v: g:")
+:    let name=tr(s, ':', 's')
+:    execute 'py '.name.'=vim.bindeval("'.s.'")'
+:    let toput=s.' : '.join(map(['locked', 'scope'], 'v:val.":".pyeval(name.".".v:val)'), ';')
+:    $put =toput
+:endfor
+:silent! let d.abc=1
+:silent! let dl.abc=1
+:py d.locked=True
+:py dl.locked=False
+:silent! let d.def=1
+:silent! let dl.def=1
+:put ='d:'.string(d)
+:put ='dl:'.string(dl)
+:unlet d dl
+:
+:let l=[] | let ll=[] | lockvar ll
+:for s in split("l ll")
+:    let name=tr(s, ':', 's')
+:    execute 'py '.name.'=vim.bindeval("'.s.'")'
+:    let toput=s.' : locked:'.pyeval(name.'.locked')
+:    $put =toput
+:endfor
+:silent! call extend(l, [0])
+:silent! call extend(ll, [0])
+:py l.locked=True
+:py ll.locked=False
+:silent! call extend(l, [1])
+:silent! call extend(ll, [1])
+:put ='l:'.string(l)
+:put ='ll:'.string(ll)
+:unlet l ll
 :"
 :" pyeval()
 :let l=pyeval('range(3)')
@@ -240,6 +275,7 @@ EOF
 :call garbagecollect(1)
 :"
 :/^start:/,$wq! test.out
+:call getchar()
 ENDTEST
 
 start:
--- a/src/testdir/test86.ok
+++ b/src/testdir/test86.ok
@@ -44,6 +44,16 @@ TypeError
 ValueError
 TypeError
 TypeError
+d : locked:0;scope:0
+dl : locked:1;scope:0
+v: : locked:2;scope:1
+g: : locked:0;scope:2
+d:{'abc': 1}
+dl:{'def': 1}
+l : locked:0
+ll : locked:1
+l:[0]
+ll:[1]
 [0, 1, 2]
 ['a', 'b']
 ['c', 1]
--- a/src/testdir/test87.in
+++ b/src/testdir/test87.in
@@ -211,6 +211,41 @@ except Exception as e:
     m.extend([e.__class__.__name__])
 EOF
 :$put =messages
+:unlet messages
+:" locked and scope attributes
+:let d={} | let dl={} | lockvar dl
+:for s in split("d dl v: g:")
+:    let name=tr(s, ':', 's')
+:    execute 'py3 '.name.'=vim.bindeval("'.s.'")'
+:    let toput=s.' : '.join(map(['locked', 'scope'], 'v:val.":".py3eval(name.".".v:val)'), ';')
+:    $put =toput
+:endfor
+:silent! let d.abc=1
+:silent! let dl.abc=1
+:py3 d.locked=True
+:py3 dl.locked=False
+:silent! let d.def=1
+:silent! let dl.def=1
+:put ='d:'.string(d)
+:put ='dl:'.string(dl)
+:unlet d dl
+:
+:let l=[] | let ll=[] | lockvar ll
+:for s in split("l ll")
+:    let name=tr(s, ':', 's')
+:    execute 'py3 '.name.'=vim.bindeval("'.s.'")'
+:    let toput=s.' : locked:'.py3eval(name.'.locked')
+:    $put =toput
+:endfor
+:silent! call extend(l, [0])
+:silent! call extend(ll, [0])
+:py3 l.locked=True
+:py3 ll.locked=False
+:silent! call extend(l, [1])
+:silent! call extend(ll, [1])
+:put ='l:'.string(l)
+:put ='ll:'.string(ll)
+:unlet l ll
 :"
 :" py3eval()
 :let l=py3eval('[0, 1, 2]')
--- a/src/testdir/test87.ok
+++ b/src/testdir/test87.ok
@@ -44,6 +44,16 @@ TypeError
 ValueError
 TypeError
 TypeError
+d : locked:0;scope:0
+dl : locked:1;scope:0
+v: : locked:2;scope:1
+g: : locked:0;scope:2
+d:{'abc': 1}
+dl:{'def': 1}
+l : locked:0
+ll : locked:1
+l:[0]
+ll:[1]
 [0, 1, 2]
 ['a', 'b']
 ['c', 1]
--- a/src/version.c
+++ b/src/version.c
@@ -720,6 +720,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    672,
+/**/
     671,
 /**/
     670,