]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
updated for version 7.3.1061 v7.3.1061
authorBram Moolenaar <Bram@vim.org>
Thu, 30 May 2013 11:01:18 +0000 (13:01 +0200)
committerBram Moolenaar <Bram@vim.org>
Thu, 30 May 2013 11:01:18 +0000 (13:01 +0200)
Problem:    Python: Dictionary is not standard.
Solution:   Python patch 20: Add standard methods and fields. (ZyX)

runtime/doc/if_pyth.txt
src/eval.c
src/if_py_both.h
src/if_python.c
src/if_python3.c
src/proto/eval.pro
src/testdir/test86.in
src/testdir/test86.ok
src/testdir/test87.in
src/testdir/test87.ok
src/version.c

index e9f339579312b94f1dd60a27df3e3ce3a9e99e95..5a0418e8b1cc473ff61b22beba409bc721f75304 100644 (file)
@@ -12,9 +12,10 @@ The Python Interface to Vim                          *python* *Python*
 4. Range objects                               |python-range|
 5. Window objects                              |python-window|
 6. Tab page objects                            |python-tabpage|
-7. pyeval(), py3eval() Vim functions           |python-pyeval|
-8. Dynamic loading                             |python-dynamic|
-9. Python 3                                    |python3|
+7. vim.bindeval objects                                |python-bindeval-objects|
+8. pyeval(), py3eval() Vim functions           |python-pyeval|
+9. Dynamic loading                             |python-dynamic|
+10. Python 3                                   |python3|
 
 {Vi does not have any of these commands}
 
@@ -171,47 +172,9 @@ vim.eval(str)                                              *python-eval*
        'eval_expr', 'kind': 'f', 'filename': './src/eval.c'}]
 
 vim.bindeval(str)                                      *python-bindeval*
-       Like |python-eval|, but
-       1. if expression evaluates to |List| or |Dictionary| it is returned as 
-          vimlist or vimdictionary python type that are connected to original 
-          list or dictionary. Thus modifications to these objects imply 
-          modifications of the original.
-
-          Additionally, vim.List and vim.Dictionary 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).
-
-          vim.Dictionary 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 vim.Function object. Use self keyword argument to assign 
-          |self| object for dictionary functions.
-
-       Note: this function has the same behavior as |lua-eval| (except that 
-             lua does not support running vim functions), |python-eval| is 
-             kept for backwards compatibility in order not to make scripts 
-             relying on outputs of vim.eval() being a copy of original or 
-             vim.eval("1") returning a string.
-
-       You can use "List", "Dictionary" and "Function" vim module attributes 
-       to test whether object has given type. These types are currently not 
-       subclassable, neither they contain constructors, so you can use them 
-       only for checks like `isinstance(obj, vim.List)`.
-
+       Like |python-eval|, but returns special objects described in 
+       |python-bindeval-objects|. These python objects let you modify (|List| 
+       or |Dictionary|) or call (|Funcref|) vim objecs.
 
 Error object of the "vim" module
 
@@ -497,13 +460,90 @@ Tab page attributes are:
 TabPage object type is available using "TabPage" attribute of vim module.
 
 ==============================================================================
-7. pyeval() and py3eval() Vim functions                        *python-pyeval*
+7. vim.bindeval objects                                *python-bindeval-objects*
+
+vim.Dictionary object                          *python-Dictionary*
+    Dictionary-like object providing access to vim |Dictionary| type.
+    Attributes:
+        Attribute  Description ~
+        locked     One of                       *python-.locked*
+                    Value           Description ~
+                    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
+                   Read-write. You can unlock locked variable by assigning 
+                   `True` or `False` to this attribute. No recursive locking 
+                   is supported.
+        scope      One of
+                    Value              Description ~
+                    zero               Dictionary is not a scope one
+                    vim.VAR_DEF_SCOPE  |g:| or |l:| dictionary
+                    vim.VAR_SCOPE      Other scope dictionary,
+                                       see |internal-variables|
+    Methods:
+        Method      Description ~
+        keys()      Returns a list with dictionary keys.
+        values()    Returns a list with dictionary values.
+        items()     Returns a list of 2-tuples with dictionary contents.
+        update(iterable)
+        update(dictionary)
+        update(**kwargs)
+                    Adds keys to dictionary.
+    Examples: >
+        py d = vim.bindeval('{}')
+        d['a'] = 'b'                           # Item assignment
+        print d['a']                           # getting item
+        d.update({'c': 'd'})                   # .update(dictionary)
+        d.update(e='f')                                # .update(**kwargs)
+        d.update((('g', 'h'), ('i', 'j')))     # .update(iterable)
+        for key in d.keys():                   # .keys()
+        for val in d.values():                 # .values()
+        for key, val in d.items():             # .items()
+        print isinstance(d, vim.Dictionary)    # True
+        for key in d:                          # Iteration over keys
+<
+    Note: when iterating over keys you should not modify dictionary.
+
+vim.List object                                        *python-List*
+    Sequence-like object providing access to vim |List| type.
+    Supports `.locked` attribute, see |python-.locked|. Also supports the 
+    following methods:
+        Method          Description ~
+        extend(item)    Add items to the list.
+    Examples: >
+        l = vim.bindeval('[]')
+        l.extend(['abc', 'def'])       # .extend() method
+        print l[1:]                    # slicing
+        l[:0] = ['ghi', 'jkl']         # slice assignment
+        print l[0]                     # getting item
+        l[0] = 'mno'                   # assignment
+        for i in l:                    # iteration
+        print isinstance(l, vim.List)  # True
+
+vim.Function object                            *python-Function*
+    Function-like object, acting like vim |Funcref| object. Supports `.name` 
+    attribute and is callable. Accepts special keyword argument `self`, see 
+    |Dictionary-function|.
+    Examples: >
+        f = vim.bindeval('function("tr")')
+        print f('abc', 'a', 'b')               # Calls tr('abc', 'a', 'b')
+        vim.command('''
+            function DictFun() dict
+                return self
+            endfunction
+        ''')
+        f = vim.bindeval('function("DictFun")')
+        print f(self={})                       # Like call('DictFun', [], {})
+        print isinstance(f, vim.Function)      # True
+
+==============================================================================
+8. pyeval() and py3eval() Vim functions                        *python-pyeval*
 
 To facilitate bi-directional interface, you can use |pyeval()| and |py3eval()| 
 functions to evaluate Python expressions and pass their values to VimL.
 
 ==============================================================================
-8. Dynamic loading                                     *python-dynamic*
+9. Dynamic loading                                     *python-dynamic*
 
 On MS-Windows the Python library can be loaded dynamically.  The |:version|
 output then includes |+python/dyn|.
@@ -520,7 +560,7 @@ Currently the name is "python24.dll".  That is for Python 2.4.  To know for
 sure edit "gvim.exe" and search for "python\d*.dll\c".
 
 ==============================================================================
-9. Python 3                                            *python3*
+10. Python 3                                           *python3*
 
                                                        *:py3* *:python3*
 The `:py3` and `:python3` commands work similar to `:python`.  A simple check
index 8db2a155a2564af10cbf0a8da0448ccdc360e493..25785b777669eb3217cb8dcf8780c832e800c4ff 100644 (file)
@@ -10156,6 +10156,62 @@ f_expand(argvars, rettv)
     }
 }
 
+/*
+ * Go over all entries in "d2" and add them to "d1".
+ * When "action" is "error" then a duplicate key is an error.
+ * When "action" is "force" then a duplicate key is overwritten.
+ * Otherwise duplicate keys are ignored ("action" is "keep").
+ */
+    void
+dict_extend(d1, d2, action)
+    dict_T     *d1;
+    dict_T     *d2;
+    char_u     *action;
+{
+    dictitem_T *di1;
+    hashitem_T *hi2;
+    int                todo;
+
+    todo = (int)d2->dv_hashtab.ht_used;
+    for (hi2 = d2->dv_hashtab.ht_array; todo > 0; ++hi2)
+    {
+       if (!HASHITEM_EMPTY(hi2))
+       {
+           --todo;
+           di1 = dict_find(d1, hi2->hi_key, -1);
+           if (d1->dv_scope != 0)
+           {
+               /* Disallow replacing a builtin function in l: and g:.
+                * Check the key to be valid when adding to any
+                * scope. */
+               if (d1->dv_scope == VAR_DEF_SCOPE
+                       && HI2DI(hi2)->di_tv.v_type == VAR_FUNC
+                       && var_check_func_name(hi2->hi_key,
+                                                        di1 == NULL))
+                   break;
+               if (!valid_varname(hi2->hi_key))
+                   break;
+           }
+           if (di1 == NULL)
+           {
+               di1 = dictitem_copy(HI2DI(hi2));
+               if (di1 != NULL && dict_add(d1, di1) == FAIL)
+                   dictitem_free(di1);
+           }
+           else if (*action == 'e')
+           {
+               EMSG2(_("E737: Key already exists: %s"), hi2->hi_key);
+               break;
+           }
+           else if (*action == 'f' && HI2DI(hi2) != di1)
+           {
+               clear_tv(&di1->di_tv);
+               copy_tv(&HI2DI(hi2)->di_tv, &di1->di_tv);
+           }
+       }
+    }
+}
+
 /*
  * "extend(list, list [, idx])" function
  * "extend(dict, dict [, action])" function
@@ -10206,12 +10262,9 @@ f_extend(argvars, rettv)
     }
     else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT)
     {
-       dict_T          *d1, *d2;
-       dictitem_T      *di1;
-       char_u          *action;
-       int             i;
-       hashitem_T      *hi2;
-       int             todo;
+       dict_T  *d1, *d2;
+       char_u  *action;
+       int     i;
 
        d1 = argvars[0].vval.v_dict;
        d2 = argvars[1].vval.v_dict;
@@ -10238,46 +10291,7 @@ f_extend(argvars, rettv)
            else
                action = (char_u *)"force";
 
-           /* Go over all entries in the second dict and add them to the
-            * first dict. */
-           todo = (int)d2->dv_hashtab.ht_used;
-           for (hi2 = d2->dv_hashtab.ht_array; todo > 0; ++hi2)
-           {
-               if (!HASHITEM_EMPTY(hi2))
-               {
-                   --todo;
-                   di1 = dict_find(d1, hi2->hi_key, -1);
-                   if (d1->dv_scope != 0)
-                   {
-                       /* Disallow replacing a builtin function in l: and g:.
-                        * Check the key to be valid when adding to any
-                        * scope. */
-                       if (d1->dv_scope == VAR_DEF_SCOPE
-                               && HI2DI(hi2)->di_tv.v_type == VAR_FUNC
-                               && var_check_func_name(hi2->hi_key,
-                                                                di1 == NULL))
-                           break;
-                       if (!valid_varname(hi2->hi_key))
-                           break;
-                   }
-                   if (di1 == NULL)
-                   {
-                       di1 = dictitem_copy(HI2DI(hi2));
-                       if (di1 != NULL && dict_add(d1, di1) == FAIL)
-                           dictitem_free(di1);
-                   }
-                   else if (*action == 'e')
-                   {
-                       EMSG2(_("E737: Key already exists: %s"), hi2->hi_key);
-                       break;
-                   }
-                   else if (*action == 'f' && HI2DI(hi2) != di1)
-                   {
-                       clear_tv(&di1->di_tv);
-                       copy_tv(&HI2DI(hi2)->di_tv, &di1->di_tv);
-                   }
-               }
-           }
+           dict_extend(d1, d2, action);
 
            copy_tv(&argvars[0], rettv);
        }
index edae12bef0b569e88f6c33afd50b4f1f59e5d345..e669d84099a16ab5b85a31b3623b291389a14e1b 100644 (file)
@@ -31,7 +31,7 @@ typedef int Py_ssize_t;  /* Python 2.4 and earlier don't have this type. */
 #define INVALID_TABPAGE_VALUE ((tabpage_T *)(-1))
 
 #define DICTKEY_DECL \
-    PyObject   *dictkey_todecref;
+    PyObject   *dictkey_todecref = NULL;
 #define DICTKEY_CHECK_EMPTY(err) \
     if (*key == NUL) \
     { \
@@ -63,6 +63,7 @@ typedef void (*runner)(const char *, void *
 
 static int ConvertFromPyObject(PyObject *, typval_T *);
 static int _ConvertFromPyObject(PyObject *, typval_T *, PyObject *);
+static int ConvertFromPyMapping(PyObject *, typval_T *);
 static PyObject *WindowNew(win_T *, tabpage_T *);
 static PyObject *BufferNew (buf_T *);
 static PyObject *LineToString(const char *);
@@ -877,12 +878,16 @@ typedef struct
     pylinkedlist_T     ref;
 } DictionaryObject;
 
+static PyObject *DictionaryUpdate(DictionaryObject *, PyObject *, PyObject *);
+
+#define NEW_DICTIONARY(dict) DictionaryNew(&DictionaryType, dict)
+
     static PyObject *
-DictionaryNew(dict_T *dict)
+DictionaryNew(PyTypeObject *subtype, dict_T *dict)
 {
     DictionaryObject   *self;
 
-    self = PyObject_NEW(DictionaryObject, &DictionaryType);
+    self = (DictionaryObject *) subtype->tp_alloc(subtype, 0);
     if (self == NULL)
        return NULL;
     self->dict = dict;
@@ -890,6 +895,49 @@ DictionaryNew(dict_T *dict)
 
     pyll_add((PyObject *)(self), &self->ref, &lastdict);
 
+    return (PyObject *)(self);
+}
+
+    static dict_T *
+py_dict_alloc()
+{
+    dict_T     *r;
+
+    if (!(r = dict_alloc()))
+    {
+       PyErr_NoMemory();
+       return NULL;
+    }
+    ++r->dv_refcount;
+
+    return r;
+}
+
+    static PyObject *
+DictionaryConstructor(PyTypeObject *subtype, PyObject *args, PyObject *kwargs)
+{
+    DictionaryObject   *self;
+    dict_T     *dict;
+
+    if (!(dict = py_dict_alloc()))
+       return NULL;
+
+    self = (DictionaryObject *) DictionaryNew(subtype, dict);
+
+    --dict->dv_refcount;
+
+    if (kwargs || PyTuple_Size(args))
+    {
+       PyObject        *tmp;
+       if (!(tmp = DictionaryUpdate(self, args, kwargs)))
+       {
+           Py_DECREF(self);
+           return NULL;
+       }
+
+       Py_DECREF(tmp);
+    }
+
     return (PyObject *)(self);
 }
 
@@ -918,7 +966,8 @@ DictionarySetattr(DictionaryObject *self, char *name, PyObject *val)
 {
     if (val == NULL)
     {
-       PyErr_SetString(PyExc_AttributeError, _("Cannot delete DictionaryObject attributes"));
+       PyErr_SetString(PyExc_AttributeError,
+               _("cannot delete vim.Dictionary attributes"));
        return -1;
     }
 
@@ -926,7 +975,7 @@ DictionarySetattr(DictionaryObject *self, char *name, PyObject *val)
     {
        if (self->dict->dv_lock == VAR_FIXED)
        {
-           PyErr_SetString(PyExc_TypeError, _("Cannot modify fixed dictionary"));
+           PyErr_SetString(PyExc_TypeError, _("cannot modify fixed dictionary"));
            return -1;
        }
        else
@@ -943,7 +992,7 @@ DictionarySetattr(DictionaryObject *self, char *name, PyObject *val)
     }
     else
     {
-       PyErr_SetString(PyExc_AttributeError, _("Cannot set this attribute"));
+       PyErr_SetString(PyExc_AttributeError, _("cannot set this attribute"));
        return -1;
     }
 }
@@ -954,26 +1003,170 @@ DictionaryLength(DictionaryObject *self)
     return ((PyInt) (self->dict->dv_hashtab.ht_used));
 }
 
+#define DICT_FLAG_HAS_DEFAULT  0x01
+#define DICT_FLAG_POP          0x02
+#define DICT_FLAG_NONE_DEFAULT 0x04
+#define DICT_FLAG_RETURN_BOOL  0x08 /* Incompatible with DICT_FLAG_POP */
+#define DICT_FLAG_RETURN_PAIR  0x10
+
     static PyObject *
-DictionaryItem(DictionaryObject *self, PyObject *keyObject)
+_DictionaryItem(DictionaryObject *self, PyObject *args, int flags)
 {
+    PyObject   *keyObject;
+    PyObject   *defObject = ((flags & DICT_FLAG_NONE_DEFAULT)? Py_None : NULL);
+    PyObject   *r;
     char_u     *key;
     dictitem_T *di;
+    dict_T     *dict = self->dict;
+    hashitem_T *hi;
+
     DICTKEY_DECL
 
+    if (flags & DICT_FLAG_HAS_DEFAULT)
+    {
+       if (!PyArg_ParseTuple(args, "O|O", &keyObject, &defObject))
+           return NULL;
+    }
+    else
+       keyObject = args;
+
+    if (flags & DICT_FLAG_RETURN_BOOL)
+       defObject = Py_False;
+
     DICTKEY_GET(NULL, 0)
 
-    di = dict_find(self->dict, key, -1);
+    hi = hash_find(&dict->dv_hashtab, key);
 
     DICTKEY_UNREF
 
-    if (di == NULL)
+    if (HASHITEM_EMPTY(hi))
     {
-       PyErr_SetObject(PyExc_KeyError, keyObject);
+       if (defObject)
+       {
+           Py_INCREF(defObject);
+           return defObject;
+       }
+       else
+       {
+           PyErr_SetObject(PyExc_KeyError, keyObject);
+           return NULL;
+       }
+    }
+    else if (flags & DICT_FLAG_RETURN_BOOL)
+    {
+       Py_INCREF(Py_True);
+       return Py_True;
+    }
+
+    di = dict_lookup(hi);
+
+    if (!(r = ConvertToPyObject(&di->di_tv)))
        return NULL;
+
+    if (flags & DICT_FLAG_POP)
+    {
+       if (dict->dv_lock)
+       {
+           PyErr_SetVim(_("dict is locked"));
+           Py_DECREF(r);
+           return NULL;
+       }
+
+       hash_remove(&dict->dv_hashtab, hi);
+       dictitem_free(di);
     }
 
-    return ConvertToPyObject(&di->di_tv);
+    if (flags & DICT_FLAG_RETURN_PAIR)
+    {
+       PyObject        *tmp = r;
+
+       if (!(r = Py_BuildValue("(" Py_bytes_fmt "O)", hi->hi_key, tmp)))
+       {
+           Py_DECREF(tmp);
+           return NULL;
+       }
+    }
+
+    return r;
+}
+
+    static PyObject *
+DictionaryItem(DictionaryObject *self, PyObject *keyObject)
+{
+    return _DictionaryItem(self, keyObject, 0);
+}
+
+    static int
+DictionaryContains(DictionaryObject *self, PyObject *keyObject)
+{
+    PyObject   *rObj = _DictionaryItem(self, keyObject, DICT_FLAG_RETURN_BOOL);
+    int                r;
+
+    r = (rObj == Py_True);
+
+    Py_DECREF(Py_True);
+
+    return r;
+}
+
+typedef struct
+{
+    hashitem_T *ht_array;
+    long_u     ht_used;
+    hashtab_T  *ht;
+    hashitem_T *hi;
+    int                todo;
+} dictiterinfo_T;
+
+    static PyObject *
+DictionaryIterNext(dictiterinfo_T **dii)
+{
+    PyObject   *r;
+
+    if (!(*dii)->todo)
+       return NULL;
+
+    if ((*dii)->ht->ht_array != (*dii)->ht_array ||
+           (*dii)->ht->ht_used != (*dii)->ht_used)
+    {
+       PyErr_SetString(PyExc_RuntimeError,
+               _("hashtab changed during iteration"));
+       return NULL;
+    }
+
+    while (((*dii)->todo) && HASHITEM_EMPTY((*dii)->hi))
+       ++((*dii)->hi);
+
+    --((*dii)->todo);
+
+    if (!(r = PyBytes_FromString((char *) (*dii)->hi->hi_key)))
+       return NULL;
+
+    return r;
+}
+
+    static PyObject *
+DictionaryIter(DictionaryObject *self)
+{
+    dictiterinfo_T     *dii;
+    hashtab_T          *ht;
+
+    if (!(dii = PyMem_New(dictiterinfo_T, 1)))
+    {
+       PyErr_NoMemory();
+       return NULL;
+    }
+
+    ht = &self->dict->dv_hashtab;
+    dii->ht_array = ht->ht_array;
+    dii->ht_used = ht->ht_used;
+    dii->ht = ht;
+    dii->hi = dii->ht_array;
+    dii->todo = dii->ht_used;
+
+    return IterNew(dii,
+           (destructorfun) PyMem_Free, (nextfun) DictionaryIterNext,
+           NULL, NULL);
 }
 
     static PyInt
@@ -1016,18 +1209,19 @@ DictionaryAssItem(DictionaryObject *self, PyObject *keyObject, PyObject *valObje
 
     if (di == NULL)
     {
-       di = dictitem_alloc(key);
-       if (di == NULL)
+       if (!(di = dictitem_alloc(key)))
        {
            PyErr_NoMemory();
            return -1;
        }
        di->di_tv.v_lock = 0;
+       di->di_tv.v_type = VAR_UNKNOWN;
 
        if (dict_add(dict, di) == FAIL)
        {
            DICTKEY_UNREF
            vim_free(di);
+           dictitem_free(di);
            PyErr_SetVim(_("failed to add key to dictionary"));
            return -1;
        }
@@ -1042,21 +1236,34 @@ DictionaryAssItem(DictionaryObject *self, PyObject *keyObject, PyObject *valObje
     return 0;
 }
 
+typedef PyObject *(*hi_to_py)(hashitem_T *);
+
     static PyObject *
-DictionaryListKeys(DictionaryObject *self)
+DictionaryListObjects(DictionaryObject *self, hi_to_py hiconvert)
 {
     dict_T     *dict = self->dict;
     long_u     todo = dict->dv_hashtab.ht_used;
     Py_ssize_t i = 0;
     PyObject   *r;
     hashitem_T *hi;
+    PyObject   *newObj;
 
     r = PyList_New(todo);
     for (hi = dict->dv_hashtab.ht_array; todo > 0; ++hi)
     {
        if (!HASHITEM_EMPTY(hi))
        {
-           PyList_SetItem(r, i, PyBytes_FromString((char *)(hi->hi_key)));
+           if (!(newObj = hiconvert(hi)))
+           {
+               Py_DECREF(r);
+               return NULL;
+           }
+           if (PyList_SetItem(r, i, newObj))
+           {
+               Py_DECREF(r);
+               Py_DECREF(newObj);
+               return NULL;
+           }
            --todo;
            ++i;
        }
@@ -1064,6 +1271,235 @@ DictionaryListKeys(DictionaryObject *self)
     return r;
 }
 
+    static PyObject *
+dict_key(hashitem_T *hi)
+{
+    return PyBytes_FromString((char *)(hi->hi_key));
+}
+
+    static PyObject *
+DictionaryListKeys(DictionaryObject *self)
+{
+    return DictionaryListObjects(self, dict_key);
+}
+
+    static PyObject *
+dict_val(hashitem_T *hi)
+{
+    dictitem_T *di;
+
+    di = dict_lookup(hi);
+    return ConvertToPyObject(&di->di_tv);
+}
+
+    static PyObject *
+DictionaryListValues(DictionaryObject *self)
+{
+    return DictionaryListObjects(self, dict_val);
+}
+
+    static PyObject *
+dict_item(hashitem_T *hi)
+{
+    PyObject   *keyObject;
+    PyObject   *valObject;
+    PyObject   *r;
+
+    if (!(keyObject = dict_key(hi)))
+       return NULL;
+
+    if (!(valObject = dict_val(hi)))
+    {
+       Py_DECREF(keyObject);
+       return NULL;
+    }
+
+    r = Py_BuildValue("(OO)", keyObject, valObject);
+
+    Py_DECREF(keyObject);
+    Py_DECREF(valObject);
+
+    return r;
+}
+
+    static PyObject *
+DictionaryListItems(DictionaryObject *self)
+{
+    return DictionaryListObjects(self, dict_item);
+}
+
+    static PyObject *
+DictionaryUpdate(DictionaryObject *self, PyObject *args, PyObject *kwargs)
+{
+    dict_T     *dict = self->dict;
+
+    if (dict->dv_lock)
+    {
+       PyErr_SetVim(_("dict is locked"));
+       return NULL;
+    }
+
+    if (kwargs)
+    {
+       typval_T        tv;
+
+       if (ConvertFromPyMapping(kwargs, &tv) == -1)
+           return NULL;
+
+       VimTryStart();
+       dict_extend(self->dict, tv.vval.v_dict, (char_u *) "force");
+       clear_tv(&tv);
+       if (VimTryEnd())
+           return NULL;
+    }
+    else
+    {
+       PyObject        *object;
+
+       if (!PyArg_Parse(args, "(O)", &object))
+           return NULL;
+
+       if (PyObject_HasAttrString(object, "keys"))
+           return DictionaryUpdate(self, NULL, object);
+       else
+       {
+           PyObject    *iterator;
+           PyObject    *item;
+
+           if (!(iterator = PyObject_GetIter(object)))
+               return NULL;
+
+           while ((item = PyIter_Next(iterator)))
+           {
+               PyObject        *fast;
+               PyObject        *keyObject;
+               PyObject        *valObject;
+               PyObject        *todecref;
+               char_u          *key;
+               dictitem_T      *di;
+
+               if (!(fast = PySequence_Fast(item, "")))
+               {
+                   Py_DECREF(iterator);
+                   Py_DECREF(item);
+                   return NULL;
+               }
+
+               Py_DECREF(item);
+
+               if (PySequence_Fast_GET_SIZE(fast) != 2)
+               {
+                   Py_DECREF(iterator);
+                   Py_DECREF(fast);
+                   PyErr_SetString(PyExc_ValueError,
+                           _("expected sequence element of size 2"));
+                   return NULL;
+               }
+
+               keyObject = PySequence_Fast_GET_ITEM(fast, 0);
+
+               if (!(key = StringToChars(keyObject, &todecref)))
+               {
+                   Py_DECREF(iterator);
+                   Py_DECREF(fast);
+                   return NULL;
+               }
+
+               di = dictitem_alloc(key);
+
+               Py_XDECREF(todecref);
+
+               if (di == NULL)
+               {
+                   Py_DECREF(fast);
+                   Py_DECREF(iterator);
+                   PyErr_NoMemory();
+                   return NULL;
+               }
+               di->di_tv.v_lock = 0;
+               di->di_tv.v_type = VAR_UNKNOWN;
+
+               valObject = PySequence_Fast_GET_ITEM(fast, 1);
+
+               if (ConvertFromPyObject(valObject, &di->di_tv) == -1)
+               {
+                   Py_DECREF(iterator);
+                   Py_DECREF(fast);
+                   dictitem_free(di);
+                   return NULL;
+               }
+
+               Py_DECREF(fast);
+
+               if (dict_add(dict, di) == FAIL)
+               {
+                   Py_DECREF(iterator);
+                   dictitem_free(di);
+                   PyErr_SetVim(_("failed to add key to dictionary"));
+                   return NULL;
+               }
+           }
+
+           Py_DECREF(iterator);
+
+           /* Iterator may have finished due to an exception */
+           if (PyErr_Occurred())
+               return NULL;
+       }
+    }
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+    static PyObject *
+DictionaryGet(DictionaryObject *self, PyObject *args)
+{
+    return _DictionaryItem(self, args,
+                           DICT_FLAG_HAS_DEFAULT|DICT_FLAG_NONE_DEFAULT);
+}
+
+    static PyObject *
+DictionaryPop(DictionaryObject *self, PyObject *args)
+{
+    return _DictionaryItem(self, args, DICT_FLAG_HAS_DEFAULT|DICT_FLAG_POP);
+}
+
+    static PyObject *
+DictionaryPopItem(DictionaryObject *self, PyObject *args)
+{
+    PyObject   *keyObject;
+
+    if (!PyArg_ParseTuple(args, "O", &keyObject))
+       return NULL;
+
+    return _DictionaryItem(self, keyObject,
+                           DICT_FLAG_POP|DICT_FLAG_RETURN_PAIR);
+}
+
+    static PyObject *
+DictionaryHasKey(DictionaryObject *self, PyObject *args)
+{
+    PyObject   *keyObject;
+
+    if (!PyArg_ParseTuple(args, "O", &keyObject))
+       return NULL;
+
+    return _DictionaryItem(self, keyObject, DICT_FLAG_RETURN_BOOL);
+}
+
+static PySequenceMethods DictionaryAsSeq = {
+    0,                                 /* sq_length */
+    0,                                 /* sq_concat */
+    0,                                 /* sq_repeat */
+    0,                                 /* sq_item */
+    0,                                 /* sq_slice */
+    0,                                 /* sq_ass_item */
+    0,                                 /* sq_ass_slice */
+    (objobjproc) DictionaryContains,   /* sq_contains */
+    0,                                 /* sq_inplace_concat */
+    0,                                 /* sq_inplace_repeat */
+};
+
 static PyMappingMethods DictionaryAsMapping = {
     (lenfunc)       DictionaryLength,
     (binaryfunc)    DictionaryItem,
@@ -1072,6 +1508,13 @@ static PyMappingMethods DictionaryAsMapping = {
 
 static struct PyMethodDef DictionaryMethods[] = {
     {"keys",   (PyCFunction)DictionaryListKeys,        METH_NOARGS,    ""},
+    {"values", (PyCFunction)DictionaryListValues,      METH_NOARGS,    ""},
+    {"items",  (PyCFunction)DictionaryListItems,       METH_NOARGS,    ""},
+    {"update", (PyCFunction)DictionaryUpdate,          METH_VARARGS|METH_KEYWORDS, ""},
+    {"get",    (PyCFunction)DictionaryGet,             METH_VARARGS,   ""},
+    {"pop",    (PyCFunction)DictionaryPop,             METH_VARARGS,   ""},
+    {"popitem",        (PyCFunction)DictionaryPopItem,         METH_VARARGS,   ""},
+    {"has_key",        (PyCFunction)DictionaryHasKey,          METH_VARARGS,   ""},
     {"__dir__",        (PyCFunction)DictionaryDir,             METH_NOARGS,    ""},
     { NULL,    NULL,                                   0,              NULL}
 };
@@ -1541,14 +1984,7 @@ FunctionCall(FunctionObject *self, PyObject *argsObject, PyObject *kwargs)
        selfdictObject = PyDict_GetItemString(kwargs, "self");
        if (selfdictObject != NULL)
        {
-           if (!PyMapping_Check(selfdictObject))
-           {
-               PyErr_SetString(PyExc_TypeError,
-                                  _("'self' argument must be a dictionary"));
-               clear_tv(&args);
-               return NULL;
-           }
-           if (ConvertFromPyObject(selfdictObject, &selfdicttv) == -1)
+           if (ConvertFromPyMapping(selfdictObject, &selfdicttv) == -1)
            {
                clear_tv(&args);
                return NULL;
@@ -1994,7 +2430,7 @@ TabPageAttr(TabPageObject *self, char *name)
     else if (strcmp(name, "number") == 0)
        return PyLong_FromLong((long) get_tab_number(self->tab));
     else if (strcmp(name, "vars") == 0)
-       return DictionaryNew(self->tab->tp_vars);
+       return NEW_DICTIONARY(self->tab->tp_vars);
     else if (strcmp(name, "window") == 0)
     {
        /* For current tab window.c does not bother to set or update tp_curwin
@@ -2225,7 +2661,7 @@ WindowAttr(WindowObject *self, char *name)
        return PyLong_FromLong((long)(W_WINCOL(self->win)));
 #endif
     else if (strcmp(name, "vars") == 0)
-       return DictionaryNew(self->win->w_vars);
+       return NEW_DICTIONARY(self->win->w_vars);
     else if (strcmp(name, "options") == 0)
        return OptionsNew(SREQ_WIN, self->win, (checkfun) CheckWindow,
                        (PyObject *) self);
@@ -3402,7 +3838,7 @@ BufferAttr(BufferObject *self, char *name)
     else if (strcmp(name, "number") == 0)
        return Py_BuildValue(Py_ssize_t_fmt, self->buf->b_fnum);
     else if (strcmp(name, "vars") == 0)
-       return DictionaryNew(self->buf->b_vars);
+       return NEW_DICTIONARY(self->buf->b_vars);
     else if (strcmp(name, "options") == 0)
        return OptionsNew(SREQ_BUF, self->buf, (checkfun) CheckBuffer,
                        (PyObject *) self);
@@ -4306,6 +4742,36 @@ convert_dl(PyObject *obj, typval_T *tv,
     return 0;
 }
 
+    static int
+ConvertFromPyMapping(PyObject *obj, typval_T *tv)
+{
+    PyObject   *lookup_dict;
+    int                r;
+
+    if (!(lookup_dict = PyDict_New()))
+       return -1;
+
+    if (PyType_IsSubtype(obj->ob_type, &DictionaryType))
+    {
+       tv->v_type = VAR_DICT;
+       tv->vval.v_dict = (((DictionaryObject *)(obj))->dict);
+       ++tv->vval.v_dict->dv_refcount;
+       r = 0;
+    }
+    else if (PyDict_Check(obj))
+       r = convert_dl(obj, tv, pydict_to_tv, lookup_dict);
+    else if (PyMapping_Check(obj))
+       r = convert_dl(obj, tv, pymap_to_tv, lookup_dict);
+    else
+    {
+       PyErr_SetString(PyExc_TypeError,
+               _("unable to convert object to vim dictionary"));
+       r = -1;
+    }
+    Py_DECREF(lookup_dict);
+    return r;
+}
+
     static int
 ConvertFromPyObject(PyObject *obj, typval_T *tv)
 {
@@ -4322,7 +4788,7 @@ ConvertFromPyObject(PyObject *obj, typval_T *tv)
     static int
 _ConvertFromPyObject(PyObject *obj, typval_T *tv, PyObject *lookup_dict)
 {
-    if (obj->ob_type == &DictionaryType)
+    if (PyType_IsSubtype(obj->ob_type, &DictionaryType))
     {
        tv->v_type = VAR_DICT;
        tv->vval.v_dict = (((DictionaryObject *)(obj))->dict);
@@ -4437,7 +4903,7 @@ ConvertToPyObject(typval_T *tv)
        case VAR_LIST:
            return ListNew(tv->vval.v_list);
        case VAR_DICT:
-           return DictionaryNew(tv->vval.v_dict);
+           return NEW_DICTIONARY(tv->vval.v_dict);
        case VAR_FUNC:
            return FunctionNew(tv->vval.v_string == NULL
                                          ? (char_u *)"" : tv->vval.v_string);
@@ -4608,10 +5074,14 @@ init_structs(void)
     DictionaryType.tp_name = "vim.dictionary";
     DictionaryType.tp_basicsize = sizeof(DictionaryObject);
     DictionaryType.tp_dealloc = (destructor)DictionaryDestructor;
+    DictionaryType.tp_as_sequence = &DictionaryAsSeq;
     DictionaryType.tp_as_mapping = &DictionaryAsMapping;
-    DictionaryType.tp_flags = Py_TPFLAGS_DEFAULT;
+    DictionaryType.tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE;
     DictionaryType.tp_doc = "dictionary pushing modifications to vim structure";
     DictionaryType.tp_methods = DictionaryMethods;
+    DictionaryType.tp_iter = (getiterfunc)DictionaryIter;
+    DictionaryType.tp_new = (newfunc)DictionaryConstructor;
+    DictionaryType.tp_alloc = (allocfunc)PyType_GenericAlloc;
 #if PY_MAJOR_VERSION >= 3
     DictionaryType.tp_getattro = (getattrofunc)DictionaryGetattro;
     DictionaryType.tp_setattro = (setattrofunc)DictionarySetattro;
@@ -4786,8 +5256,8 @@ populate_module(PyObject *m, object_adder add_object)
        return -1;
     ADD_OBJECT(m, "error", VimError);
 
-    ADD_CHECKED_OBJECT(m, "vars",  DictionaryNew(&globvardict));
-    ADD_CHECKED_OBJECT(m, "vvars", DictionaryNew(&vimvardict));
+    ADD_CHECKED_OBJECT(m, "vars",  NEW_DICTIONARY(&globvardict));
+    ADD_CHECKED_OBJECT(m, "vvars", NEW_DICTIONARY(&vimvardict));
     ADD_CHECKED_OBJECT(m, "options",
            OptionsNew(SREQ_GLOBAL, NULL, dummy_check, NULL));
     return 0;
index 16874e8557b0eb841f25799d6cf1736eb12deea2..188e1a2c7ac27c201959c14158da7c65215baacf 100644 (file)
@@ -103,6 +103,7 @@ struct PyMethodDef { Py_ssize_t a; };
 # define PyIntIntObjArgProc intintobjargproc
 # define Py_ssize_t_fmt "i"
 #endif
+#define Py_bytes_fmt "s"
 
 /* Parser flags */
 #define single_input   256
@@ -187,6 +188,7 @@ struct PyMethodDef { Py_ssize_t a; };
 # define PySequence_Check dll_PySequence_Check
 # define PySequence_Size dll_PySequence_Size
 # define PySequence_GetItem dll_PySequence_GetItem
+# define PySequence_Fast dll_PySequence_Fast
 # define PyTuple_Size dll_PyTuple_Size
 # define PyTuple_GetItem dll_PyTuple_GetItem
 # define PyTuple_Type (*dll_PyTuple_Type)
@@ -207,6 +209,7 @@ struct PyMethodDef { Py_ssize_t a; };
 # define PyRun_SimpleString dll_PyRun_SimpleString
 # define PyRun_String dll_PyRun_String
 # define PyObject_GetAttrString dll_PyObject_GetAttrString
+# define PyObject_HasAttrString dll_PyObject_HasAttrString
 # define PyObject_SetAttrString dll_PyObject_SetAttrString
 # define PyObject_CallFunctionObjArgs dll_PyObject_CallFunctionObjArgs
 # define PyString_AsString dll_PyString_AsString
@@ -227,6 +230,7 @@ struct PyMethodDef { Py_ssize_t a; };
 # define PySys_SetArgv dll_PySys_SetArgv
 # define PyType_Type (*dll_PyType_Type)
 # define PyType_Ready (*dll_PyType_Ready)
+# define PyType_GenericAlloc dll_PyType_GenericAlloc
 # define Py_BuildValue dll_Py_BuildValue
 # define Py_FindMethod dll_Py_FindMethod
 # define Py_InitModule4 dll_Py_InitModule4
@@ -318,6 +322,7 @@ static PyTypeObject* dll_PyList_Type;
 static int (*dll_PySequence_Check)(PyObject *);
 static PyInt(*dll_PySequence_Size)(PyObject *);
 static PyObject*(*dll_PySequence_GetItem)(PyObject *, PyInt);
+static PyObject*(*dll_PySequence_Fast)(PyObject *, const char *);
 static PyInt(*dll_PyTuple_Size)(PyObject *);
 static PyObject*(*dll_PyTuple_GetItem)(PyObject *, PyInt);
 static PyTypeObject* dll_PyTuple_Type;
@@ -336,6 +341,7 @@ static PyObject*(*dll_PyModule_GetDict)(PyObject *);
 static int(*dll_PyRun_SimpleString)(char *);
 static PyObject *(*dll_PyRun_String)(char *, int, PyObject *, PyObject *);
 static PyObject* (*dll_PyObject_GetAttrString)(PyObject *, const char *);
+static int (*dll_PyObject_HasAttrString)(PyObject *, const char *);
 static PyObject* (*dll_PyObject_SetAttrString)(PyObject *, const char *, PyObject *);
 static PyObject* (*dll_PyObject_CallFunctionObjArgs)(PyObject *, ...);
 static char*(*dll_PyString_AsString)(PyObject *);
@@ -354,6 +360,7 @@ static int(*dll_PySys_SetObject)(char *, PyObject *);
 static int(*dll_PySys_SetArgv)(int, char **);
 static PyTypeObject* dll_PyType_Type;
 static int (*dll_PyType_Ready)(PyTypeObject *type);
+static PyObject* (*dll_PyType_GenericAlloc)(PyTypeObject *type, PyInt nitems);
 static PyObject*(*dll_Py_BuildValue)(char *, ...);
 static PyObject*(*dll_Py_FindMethod)(struct PyMethodDef[], PyObject *, char *);
 static PyObject*(*dll_Py_InitModule4)(char *, struct PyMethodDef *, char *, PyObject *, int);
@@ -475,9 +482,10 @@ static struct
     {"PyList_SetItem", (PYTHON_PROC*)&dll_PyList_SetItem},
     {"PyList_Size", (PYTHON_PROC*)&dll_PyList_Size},
     {"PyList_Type", (PYTHON_PROC*)&dll_PyList_Type},
-    {"PySequence_GetItem", (PYTHON_PROC*)&dll_PySequence_GetItem},
     {"PySequence_Size", (PYTHON_PROC*)&dll_PySequence_Size},
     {"PySequence_Check", (PYTHON_PROC*)&dll_PySequence_Check},
+    {"PySequence_GetItem", (PYTHON_PROC*)&dll_PySequence_GetItem},
+    {"PySequence_Fast", (PYTHON_PROC*)&dll_PySequence_Fast},
     {"PyTuple_GetItem", (PYTHON_PROC*)&dll_PyTuple_GetItem},
     {"PyTuple_Size", (PYTHON_PROC*)&dll_PyTuple_Size},
     {"PyTuple_Type", (PYTHON_PROC*)&dll_PyTuple_Type},
@@ -496,6 +504,7 @@ static struct
     {"PyRun_SimpleString", (PYTHON_PROC*)&dll_PyRun_SimpleString},
     {"PyRun_String", (PYTHON_PROC*)&dll_PyRun_String},
     {"PyObject_GetAttrString", (PYTHON_PROC*)&dll_PyObject_GetAttrString},
+    {"PyObject_HasAttrString", (PYTHON_PROC*)&dll_PyObject_HasAttrString},
     {"PyObject_SetAttrString", (PYTHON_PROC*)&dll_PyObject_SetAttrString},
     {"PyObject_CallFunctionObjArgs", (PYTHON_PROC*)&dll_PyObject_CallFunctionObjArgs},
     {"PyString_AsString", (PYTHON_PROC*)&dll_PyString_AsString},
@@ -514,6 +523,7 @@ static struct
     {"PySys_SetArgv", (PYTHON_PROC*)&dll_PySys_SetArgv},
     {"PyType_Type", (PYTHON_PROC*)&dll_PyType_Type},
     {"PyType_Ready", (PYTHON_PROC*)&dll_PyType_Ready},
+    {"PyType_GenericAlloc", (PYTHON_PROC*)&dll_PyType_GenericAlloc},
     {"Py_FindMethod", (PYTHON_PROC*)&dll_Py_FindMethod},
     {"Py_SetPythonHome", (PYTHON_PROC*)&dll_Py_SetPythonHome},
     {"Py_Initialize", (PYTHON_PROC*)&dll_Py_Initialize},
@@ -1116,10 +1126,8 @@ static PySequenceMethods BufferAsSeq = {
     (PyIntObjArgProc)  BufferAssItem,      /* sq_ass_item,  x[i]=v   */
     (PyIntIntObjArgProc) BufferAssSlice,    /* sq_ass_slice, x[i:j]=v */
     (objobjproc)       0,
-#if PY_MAJOR_VERSION >= 2
     (binaryfunc)       0,
     0,
-#endif
 };
 
 /* Buffer object - Implementation
index 5d87fa384e20811dea84d3af933bfe924ad623c1..4f6809de958cd8f3040d90ad1c3cb745217e9041 100644 (file)
@@ -96,6 +96,7 @@
 #define PyInt_FromLong(i) PyLong_FromLong(i)
 #define PyInt_AsLong(obj) PyLong_AsLong(obj)
 #define Py_ssize_t_fmt "n"
+#define Py_bytes_fmt "y"
 
 #if defined(DYNAMIC_PYTHON3) || defined(PROTO)
 
 # define PySequence_Check py3_PySequence_Check
 # define PySequence_Size py3_PySequence_Size
 # define PySequence_GetItem py3_PySequence_GetItem
+# define PySequence_Fast py3_PySequence_Fast
 # define PyTuple_Size py3_PyTuple_Size
 # define PyTuple_GetItem py3_PyTuple_GetItem
 # define PySlice_GetIndicesEx py3_PySlice_GetIndicesEx
 #undef PyRun_String
 # define PyRun_String py3_PyRun_String
 # define PyObject_GetAttrString py3_PyObject_GetAttrString
+# define PyObject_HasAttrString py3_PyObject_HasAttrString
 # define PyObject_SetAttrString py3_PyObject_SetAttrString
 # define PyObject_CallFunctionObjArgs py3_PyObject_CallFunctionObjArgs
 # define PyEval_GetLocals py3_PyEval_GetLocals
@@ -269,6 +272,7 @@ static Py_ssize_t (*py3_PyList_Size)(PyObject *);
 static int (*py3_PySequence_Check)(PyObject *);
 static Py_ssize_t (*py3_PySequence_Size)(PyObject *);
 static PyObject* (*py3_PySequence_GetItem)(PyObject *, Py_ssize_t);
+static PyObject* (*py3_PySequence_Fast)(PyObject *, const char *);
 static Py_ssize_t (*py3_PyTuple_Size)(PyObject *);
 static PyObject* (*py3_PyTuple_GetItem)(PyObject *, Py_ssize_t);
 static int (*py3_PyMapping_Check)(PyObject *);
@@ -282,6 +286,7 @@ static void (*py3_PyErr_SetObject)(PyObject *, PyObject *);
 static int (*py3_PyRun_SimpleString)(char *);
 static PyObject* (*py3_PyRun_String)(char *, int, PyObject *, PyObject *);
 static PyObject* (*py3_PyObject_GetAttrString)(PyObject *, const char *);
+static int (*py3_PyObject_HasAttrString)(PyObject *, const char *);
 static PyObject* (*py3_PyObject_SetAttrString)(PyObject *, const char *, PyObject *);
 static PyObject* (*py3_PyObject_CallFunctionObjArgs)(PyObject *, ...);
 static PyObject* (*py3_PyEval_GetGlobals)();
@@ -425,6 +430,7 @@ static struct
     {"PySequence_Check", (PYTHON_PROC*)&py3_PySequence_Check},
     {"PySequence_Size", (PYTHON_PROC*)&py3_PySequence_Size},
     {"PySequence_GetItem", (PYTHON_PROC*)&py3_PySequence_GetItem},
+    {"PySequence_Fast", (PYTHON_PROC*)&py3_PySequence_Fast},
     {"PyTuple_Size", (PYTHON_PROC*)&py3_PyTuple_Size},
     {"PyTuple_GetItem", (PYTHON_PROC*)&py3_PyTuple_GetItem},
     {"PySlice_GetIndicesEx", (PYTHON_PROC*)&py3_PySlice_GetIndicesEx},
@@ -435,6 +441,7 @@ static struct
     {"PyRun_SimpleString", (PYTHON_PROC*)&py3_PyRun_SimpleString},
     {"PyRun_String", (PYTHON_PROC*)&py3_PyRun_String},
     {"PyObject_GetAttrString", (PYTHON_PROC*)&py3_PyObject_GetAttrString},
+    {"PyObject_HasAttrString", (PYTHON_PROC*)&py3_PyObject_HasAttrString},
     {"PyObject_SetAttrString", (PYTHON_PROC*)&py3_PyObject_SetAttrString},
     {"PyObject_CallFunctionObjArgs", (PYTHON_PROC*)&py3_PyObject_CallFunctionObjArgs},
     {"PyEval_GetGlobals", (PYTHON_PROC*)&py3_PyEval_GetGlobals},
index 7c3f7a13b1103b3af38870cae56452c944d722fb..8cb0dd6b952532a89c6bb98634da6f7d481d62ef 100644 (file)
@@ -75,6 +75,7 @@ int dict_add_list __ARGS((dict_T *d, char *key, list_T *list));
 dictitem_T *dict_find __ARGS((dict_T *d, char_u *key, int len));
 char_u *get_dict_string __ARGS((dict_T *d, char_u *key, int save));
 long get_dict_number __ARGS((dict_T *d, char_u *key));
+void dict_extend __ARGS((dict_T *d1, dict_T *d2, char_u *action));
 char_u *get_function_name __ARGS((expand_T *xp, int idx));
 char_u *get_expr_name __ARGS((expand_T *xp, int idx));
 char_u *get_expanded_name __ARGS((char_u *name, int check));
index cf97686220728125a5f2949f7e9c13b74d398d72..28adb709d6e9c941e7d38e939a1240261311f3e9 100644 (file)
@@ -31,16 +31,22 @@ STARTTEST
 :"
 :" Extending Dictionary directly with different types
 :let d = {}
-:py d=vim.bindeval('d')
-:py d['1']='asd'
-:py d['b']=[1, 2, f]
-:py d['-1']={'a': 1}
-:let dkeys = []
-:py dk=vim.bindeval('dkeys')
-:py dkeys=d.keys()
-:py dkeys.sort()
-:py dk.extend(dkeys)
-:$put =string(dkeys)
+py << EOF
+d=vim.bindeval('d')
+d['1']='asd'
+d.update(b=[1, 2, f])
+d.update((('-1', {'a': 1}),))
+d.update({'0': -1})
+dk = d.keys()
+dv = d.values()
+di = d.items()
+dk.sort(key=repr)
+dv.sort(key=repr)
+di.sort(key=repr)
+EOF
+:$put =pyeval('repr(dk)')
+:$put =substitute(pyeval('repr(dv)'),'0x\x\+','','g')
+:$put =substitute(pyeval('repr(di)'),'0x\x\+','','g')
 :for [key, val] in sort(items(d))
 :  $put =string(key) . ' : ' . string(val)
 :  unlet key val
@@ -60,7 +66,20 @@ STARTTEST
 :$put =string(l)
 :"
 :py del d['-1']
+:$put =string(pyeval('d.get(''b'', 1)'))
+:$put =string(pyeval('d.pop(''b'')'))
+:$put =string(pyeval('d.get(''b'', 1)'))
+:$put =string(pyeval('d.pop(''1'', 2)'))
+:$put =string(pyeval('d.pop(''1'', 2)'))
+:$put =pyeval('repr(d.has_key(''0''))')
+:$put =pyeval('repr(d.has_key(''1''))')
+:$put =pyeval('repr(''0'' in d)')
+:$put =pyeval('repr(''1'' in d)')
+:$put =pyeval('repr(list(iter(d)))')
 :$put =string(d)
+:$put =pyeval('repr(d.popitem(''0''))')
+:$put =pyeval('repr(d.get(''0''))')
+:$put =pyeval('repr(list(iter(d)))')
 :"
 :" removing items out of range: silently skip items that don't exist
 :let l = [0, 1, 2, 3]
@@ -198,6 +217,9 @@ em('d["abc"]=vim')
 em('d[""]=1')
 em('d["a\\0b"]=1')
 em('d[u"a\\0b"]=1')
+
+em('d.pop("abc")')
+em('d.popitem("abc")')
 EOF
 :$put =messages
 :unlet messages
@@ -709,6 +731,10 @@ del name
 del o
 EOF
 :"
+:" Test vim.*.__new__
+:$put =string(pyeval('vim.Dictionary({})'))
+:$put =string(pyeval('vim.Dictionary(a=1)'))
+:$put =string(pyeval('vim.Dictionary(((''a'', 1),))'))
 :"
 :" Test stdout/stderr
 :redir => messages
@@ -718,6 +744,16 @@ EOF
 :py sys.stderr.writelines(iter('abc'))
 :redir END
 :$put =string(substitute(messages, '\d\+', '', 'g'))
+:" Test subclassing
+py << EOF
+class DupDict(vim.Dictionary):
+    def __setitem__(self, key, value):
+        super(DupDict, self).__setitem__(key, value)
+        super(DupDict, self).__setitem__('dup_' + key, value)
+dd = DupDict()
+dd['a'] = 'b'
+EOF
+:$put =string(sort(keys(pyeval('dd'))))
 :"
 :" Test exceptions
 :fun Exe(e)
index fb94c3af106a8dffe0ffc062f4b215e2566c16a9..200af0489fa4e9aeebd938c565031464e6ac930c 100644 (file)
@@ -4,13 +4,29 @@ start:
 Vim(put):E684:
 [0, 'as''d', [1, 2, function('strlen'), {'a': 1}]]
 [0, function('strlen'), [1, 2, function('strlen'), {'a': 1}]]
-['-1', '1', 'b']
+['-1', '0', '1', 'b']
+['asd', -1L, <vim.dictionary object at >, <vim.list object at >]
+[('-1', <vim.dictionary object at >), ('0', -1L), ('1', 'asd'), ('b', <vim.list object at >)]
 '-1' : {'a': 1}
+'0' : -1
 '1' : 'asd'
 'b' : [1, 2, function('strlen')]
 [0, function('strlen')]
 [3]
-{'1': 'asd', 'b': [1, 2, function('strlen')]}
+[1, 2, function('strlen')]
+[1, 2, function('strlen')]
+1
+'asd'
+2
+True
+False
+True
+False
+['0']
+{'0': -1}
+('', -1L)
+None
+[]
 [0, 1, 2, 3]
 [0, 1, 2, 3]
 [0, 1, 3]
@@ -44,6 +60,8 @@ TypeError
 ValueError
 TypeError
 TypeError
+KeyError
+KeyError
 d : locked:0;scope:0
 dl : locked:1;scope:0
 v: : locked:2;scope:1
@@ -387,10 +405,13 @@ buffer:__dir__,__members__,append,mark,name,number,options,range,valid,vars
 window:__dir__,__members__,buffer,col,cursor,height,number,options,row,tabpage,valid,vars
 tabpage:__dir__,__members__,number,valid,vars,window,windows
 range:__dir__,__members__,append,end,start
-dictionary:__dir__,__members__,keys,locked,scope
+dictionary:__dir__,__members__,get,has_key,items,keys,locked,pop,popitem,scope,update,values
 list:__dir__,__members__,extend,locked
 function:__call__,__dir__,__members__,softspace
 output:__dir__,__members__,flush,softspace,write,writelines
+{}
+{'a': 1}
+{'a': 1}
 '
 abcdef
 line  :
@@ -398,6 +419,7 @@ abcdef
 abc
 line  :
 abc'
+['a', 'dup_a']
 (<class 'vim.error'>, error('abc',))
 (<class 'vim.error'>, error('def',))
 (<class 'vim.error'>, error('ghi',))
index b1763edc72c784f5e24699338b9d77432f3c8733..20f616fdb8b5a1f7b819d28ac93d4e123655d89c 100644 (file)
@@ -26,16 +26,22 @@ STARTTEST
 :"
 :" Extending Dictionary directly with different types
 :let d = {}
-:py3 d=vim.bindeval('d')
-:py3 d['1']='asd'
-:py3 d['b']=[1, 2, f]
-:py3 d['-1']={'a': 1}
-:let dkeys = []
-:py3 dk=vim.bindeval('dkeys')
-:py3 dkeys=d.keys()
-:py3 dkeys.sort()
-:py3 dk+=dkeys
-:$put =string(dkeys)
+py3 << EOF
+d=vim.bindeval('d')
+d['1']='asd'
+d.update(b=[1, 2, f])
+d.update((('-1', {'a': 1}),))
+d.update({'0': -1})
+dk = d.keys()
+dv = d.values()
+di = d.items()
+dk.sort(key=repr)
+dv.sort(key=repr)
+di.sort(key=repr)
+EOF
+:$put =py3eval('repr(dk)')
+:$put =substitute(py3eval('repr(dv)'),'0x\x\+','','g')
+:$put =substitute(py3eval('repr(di)'),'0x\x\+','','g')
 :for [key, val] in sort(items(d))
 :  $put =string(key) . ' : ' . string(val)
 :  unlet key val
@@ -55,7 +61,20 @@ STARTTEST
 :$put =string(l)
 :"
 :py3 del d['-1']
+:$put =string(py3eval('d.get(''b'', 1)'))
+:$put =string(py3eval('d.pop(''b'')'))
+:$put =string(py3eval('d.get(''b'', 1)'))
+:$put =string(py3eval('d.pop(''1'', 2)'))
+:$put =string(py3eval('d.pop(''1'', 2)'))
+:$put =py3eval('repr(d.has_key(''0''))')
+:$put =py3eval('repr(d.has_key(''1''))')
+:$put =py3eval('repr(''0'' in d)')
+:$put =py3eval('repr(''1'' in d)')
+:$put =py3eval('repr(list(iter(d)))')
 :$put =string(d)
+:$put =py3eval('repr(d.popitem(''0''))')
+:$put =py3eval('repr(d.get(''0''))')
+:$put =py3eval('repr(list(iter(d)))')
 :"
 :" removing items out of range: silently skip items that don't exist
 :let l = [0, 1, 2, 3]
@@ -181,35 +200,21 @@ STARTTEST
 :py3 <<EOF
 d=vim.bindeval('{}')
 m=vim.bindeval('messages')
-try:
-    d['abc']
-except Exception as e:
-    m.extend([e.__class__.__name__])
-
-try:
-    d['abc']="\0"
-except Exception as e:
-    m.extend([e.__class__.__name__])
-
-try:
-    d['abc']=vim
-except Exception as e:
-    m.extend([e.__class__.__name__])
-
-try:
-    d['']=1
-except Exception as e:
-    m.extend([e.__class__.__name__])
+def em(expr, g=globals(), l=locals()):
+    try:
+        exec(expr, g, l)
+    except Exception as e:
+        m.extend([e.__class__.__name__])
 
-try:
-    d['a\0b']=1
-except Exception as e:
-    m.extend([e.__class__.__name__])
+em('d["abc"]')
+em('d["abc"]="\\0"')
+em('d["abc"]=vim')
+em('d[""]=1')
+em('d["a\\0b"]=1')
+em('d[b"a\\0b"]=1')
 
-try:
-    d[b'a\0b']=1
-except Exception as e:
-    m.extend([e.__class__.__name__])
+em('d.pop("abc")')
+em('d.popitem("abc")')
 EOF
 :$put =messages
 :unlet messages
@@ -687,6 +692,10 @@ del name
 del o
 EOF
 :"
+:" Test vim.Dictionary.__new__
+:$put =string(py3eval('vim.Dictionary({})'))
+:$put =string(py3eval('vim.Dictionary(a=1)'))
+:$put =string(py3eval('vim.Dictionary(((''a'', 1),))'))
 :"
 :" Test stdout/stderr
 :redir => messages
@@ -696,6 +705,16 @@ EOF
 :py sys.stderr.writelines(iter('abc'))
 :redir END
 :$put =string(substitute(messages, '\d\+', '', 'g'))
+:" Test subclassing
+py3 << EOF
+class DupDict(vim.Dictionary):
+    def __setitem__(self, key, value):
+        super(DupDict, self).__setitem__(key, value)
+        super(DupDict, self).__setitem__('dup_' + key, value)
+dd = DupDict()
+dd['a'] = 'b'
+EOF
+:$put =string(sort(keys(py3eval('dd'))))
 :"
 :" Test exceptions
 :fun Exe(e)
index 8ae7a8cb65ec679f5547f250c6ee9619c9a8b8a0..b92d65cfff0c96dc145304a3ca5da2fc7df76519 100644 (file)
@@ -4,13 +4,29 @@ start:
 Vim(put):E684:
 [0, 'as''d', [1, 2, function('strlen'), {'a': 1}]]
 [0, function('strlen'), [1, 2, function('strlen'), {'a': 1}]]
-['-1', '1', 'b']
+[b'-1', b'0', b'1', b'b']
+[-1, <vim.dictionary object at >, <vim.list object at >, b'asd']
+[(b'-1', <vim.dictionary object at >), (b'0', -1), (b'1', b'asd'), (b'b', <vim.list object at >)]
 '-1' : {'a': 1}
+'0' : -1
 '1' : 'asd'
 'b' : [1, 2, function('strlen')]
 [0, function('strlen')]
 [3]
-{'1': 'asd', 'b': [1, 2, function('strlen')]}
+[1, 2, function('strlen')]
+[1, 2, function('strlen')]
+1
+'asd'
+2
+True
+False
+True
+False
+[b'0']
+{'0': -1}
+(b'', -1)
+None
+[]
 [0, 1, 2, 3]
 [0, 1, 2, 3]
 [0, 1, 3]
@@ -44,6 +60,8 @@ TypeError
 ValueError
 TypeError
 TypeError
+KeyError
+KeyError
 d : locked:0;scope:0
 dl : locked:1;scope:0
 v: : locked:2;scope:1
@@ -376,10 +394,13 @@ buffer:__dir__,append,mark,name,number,options,range,valid,vars
 window:__dir__,buffer,col,cursor,height,number,options,row,tabpage,valid,vars
 tabpage:__dir__,number,valid,vars,window,windows
 range:__dir__,append,end,start
-dictionary:__dir__,keys,locked,scope
+dictionary:__dir__,get,has_key,items,keys,locked,pop,popitem,scope,update,values
 list:__dir__,extend,locked
 function:__call__,__dir__,softspace
 output:__dir__,flush,softspace,write,writelines
+{}
+{'a': 1}
+{'a': 1}
 '
 abcdef
 line  :
@@ -387,6 +408,7 @@ abcdef
 abc
 line  :
 abc'
+['a', 'dup_a']
 (<class 'vim.error'>, error('abc',))
 (<class 'vim.error'>, error('def',))
 (<class 'vim.error'>, error('ghi',))
index ec01993babc9624db864040b529ad74ed944b7ea..0a20a72a11d2296c7c40c30d4e5c6636eef4489a 100644 (file)
@@ -728,6 +728,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1061,
 /**/
     1060,
 /**/