To: vim_dev@googlegroups.com
Subject: Patch 7.3.672
Fcc: outbox
From: Bram Moolenaar <Bram@moolenaar.net>
Mime-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
------------

Patch 7.3.672
Problem:    Not possible to lock/unlock lists in Python interface.
Solution:   Add .locked and .scope attributes. (ZyX)
Files:	    runtime/doc/if_pyth.txt, 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


*** ../vim-7.3.671/runtime/doc/if_pyth.txt	2012-06-29 12:54:32.000000000 +0200
--- runtime/doc/if_pyth.txt	2012-09-21 13:49:14.000000000 +0200
***************
*** 27,33 ****
  
  					*:python* *:py* *E205* *E263* *E264*
  :[range]py[thon] {stmt}
! 			Execute Python statement {stmt}.
  
  :[range]py[thon] << {endmarker}
  {script}
--- 27,35 ----
  
  					*:python* *:py* *E205* *E263* *E264*
  :[range]py[thon] {stmt}
! 			Execute Python statement {stmt}.  A simple check if
! 			the `:python` command is working: >
! 				:python print "Hello"
  
  :[range]py[thon] << {endmarker}
  {script}
***************
*** 157,162 ****
--- 159,184 ----
  	   vimlist or vimdictionary python type that are connected to original 
  	   list or dictionary. Thus modifications to these objects imply 
  	   modifications of the original.
+ 
+ 	   Additionally, vimlist and vimdictionary type have read-write 
+ 	   `.locked` attribute that returns
+ 	     Value           Meaning ~
+ 	     zero            Variable is not locked
+ 	     vim.VAR_LOCKED  Variable is locked, but can be unlocked
+ 	     vim.VAR_FIXED   Variable is locked and can’t be unlocked
+ 	   integer constants. If variable is not fixed, you can do 
+ 	   `var.locked=True` to lock it and `var.locked=False` to unlock. 
+ 	   There is no recursive locking like |:lockvar|! does. There is also 
+ 	   no way to lock a specific key or check whether it is locked (in any 
+ 	   case these locks are ignored by anything except |:let|: |extend()| 
+ 	   does not care, neither does python interface).
+ 
+ 	   Vimdictionary type also supports `.scope` attribute which is one of
+ 	     Value              Meaning ~
+ 	     zero               Dictionary is not a scope one
+ 	     vim.VAR_DEF_SCOPE  Function-local or global scope dictionary
+ 	     vim.VAR_SCOPE      Other scope dictionary
+ 
  	2. if expression evaluates to a function reference, then it returns 
  	   callable vimfunction object. Use self keyword argument to assign 
  	   |self| object for dictionary functions.
***************
*** 362,369 ****
  8. Python 3						*python3*
  
  							*:py3* *:python3*
! The |:py3| and |:python3| commands work similar to |:python|.
! 							*:py3file*
  The |:py3file| command works similar to |:pyfile|.
  
  
--- 384,393 ----
  8. Python 3						*python3*
  
  							*:py3* *:python3*
! The |:py3| and |:python3| commands work similar to |:python|.  A simple check
! if the `:py3` command is wrong: >
! 	:py3 print("Hello")
! <							*:py3file*
  The |:py3file| command works similar to |:pyfile|.
  
  
*** ../vim-7.3.671/src/if_py_both.h	2012-09-21 13:45:57.000000000 +0200
--- src/if_py_both.h	2012-09-21 13:49:14.000000000 +0200
***************
*** 808,813 ****
--- 808,851 ----
  }
  
      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,1276 ****
--- 1309,1352 ----
      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 }
*** ../vim-7.3.671/src/if_python.c	2012-09-21 13:45:57.000000000 +0200
--- src/if_python.c	2012-09-21 13:49:14.000000000 +0200
***************
*** 163,168 ****
--- 163,169 ----
  # 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,226 ****
--- 222,229 ----
  #  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,268 ****
--- 266,272 ----
  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,325 ****
--- 324,331 ----
  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,394 ****
--- 395,401 ----
      {"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,454 ****
--- 456,463 ----
      {"_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,1568 ****
--- 1572,1581 ----
      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,1635 ****
      (destructor)  DictionaryDestructor,
      (printfunc)   0,
      (getattrfunc) DictionaryGetattr,
!     (setattrfunc) 0,
      (cmpfunc)     0,
      (reprfunc)    0,
  
--- 1642,1648 ----
      (destructor)  DictionaryDestructor,
      (printfunc)   0,
      (getattrfunc) DictionaryGetattr,
!     (setattrfunc) DictionarySetattr,
      (cmpfunc)     0,
      (reprfunc)    0,
  
***************
*** 1656,1661 ****
--- 1669,1681 ----
      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,1693 ****
      (destructor)  ListDestructor,
      (printfunc)   0,
      (getattrfunc) ListGetattr,
!     (setattrfunc) 0,
      (cmpfunc)     0,
      (reprfunc)    0,
  
--- 1707,1713 ----
      (destructor)  ListDestructor,
      (printfunc)   0,
      (getattrfunc) ListGetattr,
!     (setattrfunc) ListSetattr,
      (cmpfunc)     0,
      (reprfunc)    0,
  
***************
*** 1714,1719 ****
--- 1734,1742 ----
      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);
  }
  
*** ../vim-7.3.671/src/if_python3.c	2012-09-21 13:45:57.000000000 +0200
--- src/if_python3.c	2012-09-21 13:49:14.000000000 +0200
***************
*** 161,167 ****
  # 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
--- 161,166 ----
***************
*** 170,175 ****
--- 169,176 ----
  # 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,191 ****
--- 185,194 ----
  # 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,251 ****
  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 *);
--- 248,253 ----
***************
*** 275,280 ****
--- 277,284 ----
  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,295 ****
--- 292,301 ----
  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,369 ****
      {"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},
--- 369,374 ----
***************
*** 386,391 ****
--- 391,398 ----
      {"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,407 ****
--- 407,416 ----
      {"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,1539 ****
--- 1543,1570 ----
      /* 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,1630 ****
--- 1656,1679 ----
      }
  }
  
+     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,1718 ****
--- 1762,1768 ----
  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,1749 ****
--- 1794,1809 ----
      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,1904 ****
--- 1959,1966 ----
      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,1914 ****
--- 1971,1978 ----
      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;
*** ../vim-7.3.671/src/testdir/test86.in	2012-09-05 19:17:37.000000000 +0200
--- src/testdir/test86.in	2012-09-21 13:49:14.000000000 +0200
***************
*** 211,216 ****
--- 211,251 ----
      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,245 ****
--- 275,281 ----
  :call garbagecollect(1)
  :"
  :/^start:/,$wq! test.out
+ :call getchar()
  ENDTEST
  
  start:
*** ../vim-7.3.671/src/testdir/test86.ok	2012-09-05 19:17:37.000000000 +0200
--- src/testdir/test86.ok	2012-09-21 13:49:14.000000000 +0200
***************
*** 44,49 ****
--- 44,59 ----
  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]
*** ../vim-7.3.671/src/testdir/test87.in	2012-09-05 19:17:37.000000000 +0200
--- src/testdir/test87.in	2012-09-21 13:49:14.000000000 +0200
***************
*** 211,216 ****
--- 211,251 ----
      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]')
*** ../vim-7.3.671/src/testdir/test87.ok	2012-09-05 19:17:37.000000000 +0200
--- src/testdir/test87.ok	2012-09-21 13:49:14.000000000 +0200
***************
*** 44,49 ****
--- 44,59 ----
  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]
*** ../vim-7.3.671/src/version.c	2012-09-21 13:45:57.000000000 +0200
--- src/version.c	2012-09-21 13:48:18.000000000 +0200
***************
*** 721,722 ****
--- 721,724 ----
  {   /* Add new patch number below this line */
+ /**/
+     672,
  /**/

-- 
Vi beats Emacs to death, and then again!
			http://linuxtoday.com/stories/5764.html

 /// 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    ///
