# HG changeset patch # User Bram Moolenaar # Date 1369911958 -7200 # Node ID e4e48d4ee0409509d56f7d654b77a35133283bc7 # Parent 51d817361f04006a3eb539cc7d3edd3eb1e294e6 updated for version 7.3.1062 Problem: Python: List is not standard. Solution: Python patch 21: Add standard methods and fields. (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 @@ -1530,12 +1530,14 @@ typedef struct pylinkedlist_T ref; } ListObject; +#define NEW_LIST(list) ListNew(&ListType, list) + static PyObject * -ListNew(list_T *list) +ListNew(PyTypeObject *subtype, list_T *list) { ListObject *self; - self = PyObject_NEW(ListObject, &ListType); + self = (ListObject *) subtype->tp_alloc(subtype, 0); if (self == NULL) return NULL; self->list = list; @@ -1546,6 +1548,107 @@ ListNew(list_T *list) return (PyObject *)(self); } + static list_T * +py_list_alloc() +{ + list_T *r; + + if (!(r = list_alloc())) + { + PyErr_NoMemory(); + return NULL; + } + ++r->lv_refcount; + + return r; +} + + static int +list_py_concat(list_T *l, PyObject *obj, PyObject *lookup_dict) +{ + PyObject *iterator; + PyObject *item; + listitem_T *li; + + if (!(iterator = PyObject_GetIter(obj))) + return -1; + + while ((item = PyIter_Next(iterator))) + { + if (!(li = listitem_alloc())) + { + PyErr_NoMemory(); + Py_DECREF(item); + Py_DECREF(iterator); + return -1; + } + li->li_tv.v_lock = 0; + li->li_tv.v_type = VAR_UNKNOWN; + + if (_ConvertFromPyObject(item, &li->li_tv, lookup_dict) == -1) + { + Py_DECREF(item); + Py_DECREF(iterator); + listitem_free(li); + return -1; + } + + Py_DECREF(item); + + list_append(l, li); + } + + Py_DECREF(iterator); + + /* Iterator may have finished due to an exception */ + if (PyErr_Occurred()) + return -1; + + return 0; +} + + static PyObject * +ListConstructor(PyTypeObject *subtype, PyObject *args, PyObject *kwargs) +{ + list_T *list; + PyObject *obj = NULL; + + if (kwargs) + { + PyErr_SetString(PyExc_TypeError, + _("list constructor does not accept keyword arguments")); + return NULL; + } + + if (!PyArg_ParseTuple(args, "|O", &obj)) + return NULL; + + if (!(list = py_list_alloc())) + return NULL; + + if (obj) + { + PyObject *lookup_dict; + + if (!(lookup_dict = PyDict_New())) + { + list_unref(list); + return NULL; + } + + if (list_py_concat(list, obj, lookup_dict) == -1) + { + Py_DECREF(lookup_dict); + list_unref(list); + return NULL; + } + + Py_DECREF(lookup_dict); + } + + return ListNew(subtype, list); +} + static void ListDestructor(ListObject *self) { @@ -1555,35 +1658,6 @@ ListDestructor(ListObject *self) DESTRUCTOR_FINISH(self); } - static int -list_py_concat(list_T *l, PyObject *obj, PyObject *lookup_dict) -{ - Py_ssize_t i; - Py_ssize_t lsize = PySequence_Size(obj); - PyObject *litem; - listitem_T *li; - - for(i=0; ili_tv.v_lock = 0; - - litem = PySequence_GetItem(obj, i); - if (litem == NULL) - return -1; - if (_ConvertFromPyObject(litem, &li->li_tv, lookup_dict) == -1) - return -1; - - list_append(l, li); - } - return 0; -} - static PyInt ListLength(ListObject *self) { @@ -1747,7 +1821,7 @@ ListAssItem(ListObject *self, Py_ssize_t if (list_append_tv(l, &tv) == FAIL) { clear_tv(&tv); - PyErr_SetVim(_("Failed to add item to list")); + PyErr_SetVim(_("failed to add item to list")); return -1; } } @@ -1765,13 +1839,13 @@ ListAssItem(ListObject *self, Py_ssize_t ListAssSlice(ListObject *self, Py_ssize_t first, Py_ssize_t last, PyObject *obj) { PyInt size = ListLength(self); - Py_ssize_t i; - Py_ssize_t lsize; - PyObject *litem; + PyObject *iterator; + PyObject *item; listitem_T *li; listitem_T *next; typval_T v; list_T *l = self->list; + PyInt i; if (l->lv_lock) { @@ -1806,21 +1880,18 @@ ListAssSlice(ListObject *self, Py_ssize_ if (obj == NULL) return 0; - if (!PyList_Check(obj)) - { - PyErr_SetString(PyExc_TypeError, _("can only assign lists to slice")); + if (!(iterator = PyObject_GetIter(obj))) return -1; - } - - lsize = PyList_Size(obj); - - for(i=0; ilv_refcount; - - return r; -} - static int pyseq_to_tv(PyObject *obj, typval_T *tv, PyObject *lookup_dict) { @@ -4627,65 +4678,6 @@ pyseq_to_tv(PyObject *obj, typval_T *tv, return 0; } - static int -pyiter_to_tv(PyObject *obj, typval_T *tv, PyObject *lookup_dict) -{ - PyObject *iterator; - PyObject *item; - list_T *l; - listitem_T *li; - - if (!(l = py_list_alloc())) - return -1; - - tv->vval.v_list = l; - tv->v_type = VAR_LIST; - - if (!(iterator = PyObject_GetIter(obj))) - { - list_unref(l); - return -1; - } - - while ((item = PyIter_Next(iterator))) - { - li = listitem_alloc(); - if (li == NULL) - { - list_unref(l); - Py_DECREF(iterator); - PyErr_NoMemory(); - return -1; - } - li->li_tv.v_lock = 0; - - if (_ConvertFromPyObject(item, &li->li_tv, lookup_dict) == -1) - { - list_unref(l); - listitem_free(li); - Py_DECREF(item); - Py_DECREF(iterator); - return -1; - } - - list_append(l, li); - - Py_DECREF(item); - } - - Py_DECREF(iterator); - - /* Iterator may have finished due to an exception */ - if (PyErr_Occurred()) - { - list_unref(l); - return -1; - } - - --l->lv_refcount; - return 0; -} - typedef int (*pytotvfunc)(PyObject *, typval_T *, PyObject *); static int @@ -4866,9 +4858,7 @@ ConvertFromPyObject(PyObject *obj, typva tv->vval.v_float = (float_T) PyFloat_AsDouble(obj); } #endif - else if (PyIter_Check(obj)) - return convert_dl(obj, tv, pyiter_to_tv, lookup_dict); - else if (PySequence_Check(obj)) + else if (PyIter_Check(obj) || PySequence_Check(obj)) return convert_dl(obj, tv, pyseq_to_tv, lookup_dict); else if (PyMapping_Check(obj)) return convert_dl(obj, tv, pymap_to_tv, lookup_dict); @@ -4901,7 +4891,7 @@ ConvertToPyObject(typval_T *tv) return PyFloat_FromDouble((double) tv->vval.v_float); #endif case VAR_LIST: - return ListNew(tv->vval.v_list); + return NEW_LIST(tv->vval.v_list); case VAR_DICT: return NEW_DICTIONARY(tv->vval.v_dict); case VAR_FUNC: @@ -5096,10 +5086,12 @@ init_structs(void) ListType.tp_basicsize = sizeof(ListObject); ListType.tp_as_sequence = &ListAsSeq; ListType.tp_as_mapping = &ListAsMapping; - ListType.tp_flags = Py_TPFLAGS_DEFAULT; + ListType.tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE; ListType.tp_doc = "list pushing modifications to vim structure"; ListType.tp_methods = ListMethods; ListType.tp_iter = (getiterfunc)ListIter; + ListType.tp_new = (newfunc)ListConstructor; + ListType.tp_alloc = (allocfunc)PyType_GenericAlloc; #if PY_MAJOR_VERSION >= 3 ListType.tp_getattro = (getattrofunc)ListGetattro; ListType.tp_setattro = (setattrofunc)ListSetattro; diff --git a/src/testdir/test86.in b/src/testdir/test86.in --- a/src/testdir/test86.in +++ b/src/testdir/test86.in @@ -735,6 +735,8 @@ EOF :$put =string(pyeval('vim.Dictionary({})')) :$put =string(pyeval('vim.Dictionary(a=1)')) :$put =string(pyeval('vim.Dictionary(((''a'', 1),))')) +:$put =string(pyeval('vim.List()')) +:$put =string(pyeval('vim.List(iter(''abc''))')) :" :" Test stdout/stderr :redir => messages @@ -752,8 +754,18 @@ class DupDict(vim.Dictionary): super(DupDict, self).__setitem__('dup_' + key, value) dd = DupDict() dd['a'] = 'b' + +class DupList(vim.List): + def __getitem__(self, idx): + return [super(DupList, self).__getitem__(idx)] * 2 + +dl = DupList() +dl2 = DupList(iter('abc')) +dl.extend(dl2[0]) EOF :$put =string(sort(keys(pyeval('dd')))) +:$put =string(pyeval('dl')) +:$put =string(pyeval('dl2')) :" :" Test exceptions :fun Exe(e) diff --git a/src/testdir/test86.ok b/src/testdir/test86.ok --- a/src/testdir/test86.ok +++ b/src/testdir/test86.ok @@ -412,6 +412,8 @@ output:__dir__,__members__,flush,softspa {} {'a': 1} {'a': 1} +[] +['a', 'b', 'c'] ' abcdef line : @@ -420,6 +422,8 @@ abc line : abc' ['a', 'dup_a'] +['a', 'a'] +['a', 'b', 'c'] (, error('abc',)) (, error('def',)) (, error('ghi',)) diff --git a/src/testdir/test87.in b/src/testdir/test87.in --- a/src/testdir/test87.in +++ b/src/testdir/test87.in @@ -692,10 +692,12 @@ del name del o EOF :" -:" Test vim.Dictionary.__new__ +:" Test vim.*.__new__ :$put =string(py3eval('vim.Dictionary({})')) :$put =string(py3eval('vim.Dictionary(a=1)')) :$put =string(py3eval('vim.Dictionary(((''a'', 1),))')) +:$put =string(py3eval('vim.List()')) +:$put =string(py3eval('vim.List(iter(''abc''))')) :" :" Test stdout/stderr :redir => messages @@ -713,8 +715,18 @@ class DupDict(vim.Dictionary): super(DupDict, self).__setitem__('dup_' + key, value) dd = DupDict() dd['a'] = 'b' + +class DupList(vim.List): + def __getitem__(self, idx): + return [super(DupList, self).__getitem__(idx)] * 2 + +dl = DupList() +dl2 = DupList(iter('abc')) +dl.extend(dl2[0]) EOF :$put =string(sort(keys(py3eval('dd')))) +:$put =string(py3eval('dl')) +:$put =string(py3eval('dl2')) :" :" Test exceptions :fun Exe(e) diff --git a/src/testdir/test87.ok b/src/testdir/test87.ok --- a/src/testdir/test87.ok +++ b/src/testdir/test87.ok @@ -401,6 +401,8 @@ output:__dir__,flush,softspace,write,wri {} {'a': 1} {'a': 1} +[] +['a', 'b', 'c'] ' abcdef line : @@ -409,6 +411,8 @@ abc line : abc' ['a', 'dup_a'] +['a', 'a'] +['a', 'b', 'c'] (, error('abc',)) (, error('def',)) (, error('ghi',)) diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -729,6 +729,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1062, +/**/ 1061, /**/ 1060,