# HG changeset patch # User Bram Moolenaar # Date 1348228835 -7200 # Node ID fd6ef931aa77239804860b74ed2362b29c1a6d4a # Parent 72c860159c0f5c38d91c3d9492dcaaebd165828f updated for version 7.3.672 Problem: Not possible to lock/unlock lists in Python interface. Solution: Add .locked and .scope attributes. (ZyX) diff --git a/src/if_py_both.h b/src/if_py_both.h --- 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 } diff --git a/src/if_python.c b/src/if_python.c --- 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); } diff --git a/src/if_python3.c b/src/if_python3.c --- 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; diff --git a/src/testdir/test86.in b/src/testdir/test86.in --- 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: diff --git a/src/testdir/test86.ok b/src/testdir/test86.ok --- 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] diff --git a/src/testdir/test87.in b/src/testdir/test87.in --- 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]') diff --git a/src/testdir/test87.ok b/src/testdir/test87.ok --- 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] diff --git a/src/version.c b/src/version.c --- 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,