IDProperty python module update
authorCampbell Barton <ideasman42@gmail.com>
Fri, 17 Jun 2011 05:45:46 +0000 (05:45 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Fri, 17 Jun 2011 05:45:46 +0000 (05:45 +0000)
- add support for IDProp array slicing, but not resizing.
- rename array attribute type to typecode and use chars 'f', 'd', 'i' which match pythons array module. (was using int's which only have a meaning internally).
- rename function 'convert_to_pyobject' to 'to_dict' and 'to_list' for IDProp group and array types respectively.
- remove 'len' array attribute, calling len(array) is fine.

release/scripts/modules/rna_prop_ui.py
source/blender/python/generic/IDProp.c
source/blender/python/generic/IDProp.h
source/blender/python/generic/py_capi_utils.c
source/blender/python/generic/py_capi_utils.h
source/blender/python/intern/bpy_props.c
source/blender/python/intern/bpy_util.c

index 9311987..b0fb3b6 100644 (file)
@@ -111,12 +111,16 @@ def draw(layout, context, context_member, property_type, use_edit=True):
             continue
 
         row = layout.row()
-        convert_to_pyobject = getattr(val, "convert_to_pyobject", None)
+        to_dict = getattr(val, "to_dict", None)
+        to_list = getattr(val, "to_list", None)
 
         val_orig = val
-        if convert_to_pyobject:
-            val_draw = val = val.convert_to_pyobject()
-            val_draw = str(val_draw)
+        if to_dict:
+            val = to_dict()
+            val_draw = str(val)
+        elif to_list:
+            val = to_list()
+            val_draw = str(val)
         else:
             val_draw = val
 
@@ -131,7 +135,7 @@ def draw(layout, context, context_member, property_type, use_edit=True):
         row.label(text=key)
 
         # explicit exception for arrays
-        if convert_to_pyobject and not hasattr(val_orig, "len"):
+        if to_dict or to_list:
             row.label(text=val_draw)
         else:
             if key in rna_properties:
index a807624..f6eb467 100644 (file)
 #include "py_capi_utils.h"
 #endif
 
-extern PyTypeObject IDArray_Type;
-extern PyTypeObject IDGroup_Iter_Type;
+extern PyTypeObject BPy_IDArray_Type;
+extern PyTypeObject BPy_IDGroup_Iter_Type;
+extern PyTypeObject BPy_IDGroup_Type;
 
 /*********************** ID Property Main Wrapper Stuff ***************/
 
-static PyObject *IDGroup_repr( BPy_IDProperty *self )
+/* use for both array and group */
+static long BPy_IDGroup_hash(BPy_IDProperty *self)
 {
-       return PyUnicode_FromFormat( "<bpy ID property from \"%s\">", self->id->name);
+       return _Py_HashPointer(self->prop);
 }
 
-extern PyTypeObject IDGroup_Type;
+static PyObject *BPy_IDGroup_repr(BPy_IDProperty *self)
+{
+       return PyUnicode_FromFormat( "<bpy id property from \"%s\">", self->id->name);
+}
 
 PyObject *BPy_IDGroup_WrapData( ID *id, IDProperty *prop )
 {
        switch ( prop->type ) {
                case IDP_STRING:
 #ifdef USE_STRING_COERCE
-                       return PyC_UnicodeFromByte(prop->data.pointer);
+                       return PyC_UnicodeFromByte(IDP_Array(prop));
 #else
-                       return PyUnicode_FromString(prop->data.pointer);
+                       return PyUnicode_FromString(IDP_Array(prop));
 #endif
                case IDP_INT:
                        return PyLong_FromLong( (long)prop->data.val );
@@ -75,14 +80,14 @@ PyObject *BPy_IDGroup_WrapData( ID *id, IDProperty *prop )
                case IDP_GROUP:
                        /*blegh*/
                        {
-                               BPy_IDProperty *group = PyObject_New(BPy_IDProperty, &IDGroup_Type);
+                               BPy_IDProperty *group = PyObject_New(BPy_IDProperty, &BPy_IDGroup_Type);
                                group->id = id;
                                group->prop = prop;
                                return (PyObject*) group;
                        }
                case IDP_ARRAY:
                        {
-                               BPy_IDProperty *array = PyObject_New(BPy_IDProperty, &IDArray_Type);
+                               BPy_IDProperty *array = PyObject_New(BPy_IDProperty, &BPy_IDArray_Type);
                                array->id = id;
                                array->prop = prop;
                                return (PyObject*) array;
@@ -135,13 +140,13 @@ static int BPy_IDGroup_SetData(BPy_IDProperty *self, IDProperty *prop, PyObject
 
                                st = _PyUnicode_AsString(value);
                                IDP_ResizeArray(prop, alloc_len);
-                               memcpy(prop->data.pointer, st, alloc_len);
+                               memcpy(IDP_Array(prop), st, alloc_len);
                                Py_XDECREF(value_coerce);
                        }
 #else
                        st = _PyUnicode_AsString(value);
                        IDP_ResizeArray(prop, strlen(st)+1);
-                       strcpy(prop->data.pointer, st);
+                       strcpy(IDP_Array(prop), st);
 #endif
 
                        return 0;
@@ -344,7 +349,7 @@ const char *BPy_IDProperty_Map_ValidateAndCreate(const char *name, IDProperty *g
                        prop = IDP_New(IDP_ARRAY, val, name);
                        for (i=0; i<val.array.len; i++) {
                                item = PySequence_GetItem(ob, i);
-                               ((double*)prop->data.pointer)[i] = (float)PyFloat_AsDouble(item);
+                               ((double*)IDP_Array(prop))[i] = (float)PyFloat_AsDouble(item);
                                Py_DECREF(item);
                        }
                        break;
@@ -352,7 +357,7 @@ const char *BPy_IDProperty_Map_ValidateAndCreate(const char *name, IDProperty *g
                        prop = IDP_New(IDP_ARRAY, val, name);
                        for (i=0; i<val.array.len; i++) {
                                item = PySequence_GetItem(ob, i);
-                               ((int*)prop->data.pointer)[i] = (int)PyLong_AsSsize_t(item);
+                               ((int*)IDP_Array(prop))[i] = (int)PyLong_AsSsize_t(item);
                                Py_DECREF(item);
                        }
                        break;
@@ -465,9 +470,9 @@ static int BPy_IDGroup_Map_SetItem(BPy_IDProperty *self, PyObject *key, PyObject
        return BPy_Wrap_SetMapItem(self->prop, key, val);
 }
 
-static PyObject *BPy_IDGroup_SpawnIterator(BPy_IDProperty *self)
+static PyObject *BPy_IDGroup_iter(BPy_IDProperty *self)
 {
-       BPy_IDGroup_Iter *iter = PyObject_New(BPy_IDGroup_Iter, &IDGroup_Iter_Type);
+       BPy_IDGroup_Iter *iter = PyObject_New(BPy_IDGroup_Iter, &BPy_IDGroup_Iter_Type);
        iter->group = self;
        iter->mode = IDPROP_ITER_KEYS;
        iter->cur = self->prop->data.group.first;
@@ -480,9 +485,9 @@ static PyObject *BPy_IDGroup_MapDataToPy(IDProperty *prop)
        switch (prop->type) {
                case IDP_STRING:
 #ifdef USE_STRING_COERCE
-                       return PyC_UnicodeFromByte(prop->data.pointer);
+                       return PyC_UnicodeFromByte(IDP_Array(prop));
 #else
-                       return PyUnicode_FromString(prop->data.pointer);
+                       return PyUnicode_FromString(IDP_Array(prop));
 #endif
                        break;
                case IDP_FLOAT:
@@ -504,20 +509,37 @@ static PyObject *BPy_IDGroup_MapDataToPy(IDProperty *prop)
                                return NULL;
                        }
 
-                       for (i=0; i<prop->len; i++) {
-                               if (prop->subtype == IDP_FLOAT) {
-                                       PyList_SET_ITEM(seq, i,
-                                                       PyFloat_FromDouble(((float*)prop->data.pointer)[i]));
+                       switch(prop->subtype) {
+                               case IDP_FLOAT:
+                               {
+                                       float *array= (float*)IDP_Array(prop);
+                                       for (i=0; i<prop->len; i++) {
+                                               PyList_SET_ITEM(seq, i, PyFloat_FromDouble(array[i]));
+                                       }
+                                       break;
                                }
-                               else if (prop->subtype == IDP_DOUBLE) {
-                                       PyList_SET_ITEM(seq, i,
-                                                       PyFloat_FromDouble(((double*)prop->data.pointer)[i]));
+                               case IDP_DOUBLE:
+                               {
+                                       double *array= (double*)IDP_Array(prop);
+                                       for (i=0; i<prop->len; i++) {
+                                               PyList_SET_ITEM(seq, i, PyFloat_FromDouble(array[i]));
+                                       }
+                                       break;
                                }
-                               else    {
-                                       PyList_SET_ITEM(seq, i,
-                                                       PyLong_FromLong(((int*)prop->data.pointer)[i]));
+                               case IDP_INT:
+                               {
+                                       int *array= (int*)IDP_Array(prop);
+                                       for (i=0; i<prop->len; i++) {
+                                               PyList_SET_ITEM(seq, i, PyLong_FromLong(array[i]));
+                                       }
+                                       break;
                                }
+                               default:
+                                       PyErr_SetString(PyExc_RuntimeError, "invalid/corrupt array type!");
+                                       Py_DECREF(seq);
+                                       return NULL;
                        }
+
                        return seq;
                }
                case IDP_IDPARRAY:
@@ -595,7 +617,7 @@ static PyObject *BPy_IDGroup_Pop(BPy_IDProperty *self, PyObject *value)
 
 static PyObject *BPy_IDGroup_IterItems(BPy_IDProperty *self)
 {
-       BPy_IDGroup_Iter *iter = PyObject_New(BPy_IDGroup_Iter, &IDGroup_Iter_Type);
+       BPy_IDGroup_Iter *iter = PyObject_New(BPy_IDGroup_Iter, &BPy_IDGroup_Iter_Type);
        iter->group = self;
        iter->mode = IDPROP_ITER_ITEMS;
        iter->cur = self->prop->data.group.first;
@@ -731,7 +753,7 @@ static PyObject *BPy_IDGroup_Update(BPy_IDProperty *self, PyObject *value)
        Py_RETURN_NONE;
 }
 
-static PyObject *BPy_IDGroup_ConvertToPy(BPy_IDProperty *self)
+static PyObject *BPy_IDGroup_to_dict(BPy_IDProperty *self)
 {
        return BPy_IDGroup_MapDataToPy(self->prop);
 }
@@ -773,7 +795,7 @@ static struct PyMethodDef BPy_IDGroup_methods[] = {
                "updates the values in the group with the values of another or a dict"},
        {"get", (PyCFunction)BPy_IDGroup_Get, METH_VARARGS,
                "idprop.get(k[,d]) -> idprop[k] if k in idprop, else d.  d defaults to None"},
-       {"convert_to_pyobject", (PyCFunction)BPy_IDGroup_ConvertToPy, METH_NOARGS,
+       {"to_dict", (PyCFunction)BPy_IDGroup_to_dict, METH_NOARGS,
                "return a purely python version of the group"},
        {NULL, NULL, 0, NULL}
 };
@@ -792,16 +814,16 @@ static PySequenceMethods BPy_IDGroup_Seq = {
 };
 
 static PyMappingMethods BPy_IDGroup_Mapping = {
-       (lenfunc)BPy_IDGroup_Map_Len,                   /*inquiry mp_length */
-       (binaryfunc)BPy_IDGroup_Map_GetItem,            /*binaryfunc mp_subscript */
+       (lenfunc)BPy_IDGroup_Map_Len,           /*inquiry mp_length */
+       (binaryfunc)BPy_IDGroup_Map_GetItem,/*binaryfunc mp_subscript */
        (objobjargproc)BPy_IDGroup_Map_SetItem, /*objobjargproc mp_ass_subscript */
 };
 
-PyTypeObject IDGroup_Type = {
+PyTypeObject BPy_IDGroup_Type = {
        PyVarObject_HEAD_INIT(NULL, 0)
        /*  For printing, in format "<module>.<name>" */
-       "Blender IDProperty",           /* char *tp_name; */
-       sizeof( BPy_IDProperty ),       /* int tp_basicsize; */
+       "Blender IDProperty",           /* char *tp_name; */
+       sizeof(BPy_IDProperty),         /* int tp_basicsize; */
        0,                          /* tp_itemsize;  For allocation */
 
        /* Methods to implement standard operations */
@@ -811,7 +833,7 @@ PyTypeObject IDGroup_Type = {
        NULL,     /* getattrfunc tp_getattr; */
        NULL,     /* setattrfunc tp_setattr; */
        NULL,                       /* cmpfunc tp_compare; */
-       ( reprfunc ) IDGroup_repr,     /* reprfunc tp_repr; */
+       (reprfunc)BPy_IDGroup_repr,     /* reprfunc tp_repr; */
 
        /* Method suites for standard classes */
 
@@ -821,7 +843,7 @@ PyTypeObject IDGroup_Type = {
 
        /* More standard operations (here for binary compatibility) */
 
-       NULL,                       /* hashfunc tp_hash; */
+       (hashfunc)BPy_IDGroup_hash, /* hashfunc tp_hash; */
        NULL,                       /* ternaryfunc tp_call; */
        NULL,                       /* reprfunc tp_str; */
        NULL,                       /* getattrofunc tp_getattro; */
@@ -850,7 +872,7 @@ PyTypeObject IDGroup_Type = {
 
   /*** Added in release 2.2 ***/
        /*   Iterators */
-       (getiterfunc)BPy_IDGroup_SpawnIterator, /* getiterfunc tp_iter; */
+       (getiterfunc)BPy_IDGroup_iter, /* getiterfunc tp_iter; */
        NULL,                       /* iternextfunc tp_iternext; */
   /*** Attribute descriptor and subclassing stuff ***/
        BPy_IDGroup_methods,        /* struct PyMethodDef *tp_methods; */
@@ -861,7 +883,7 @@ PyTypeObject IDGroup_Type = {
 /*********** Main external wrapping function *******/
 PyObject *BPy_Wrap_IDProperty(ID *id, IDProperty *prop, IDProperty *parent)
 {
-       BPy_IDProperty *wrap = PyObject_New(BPy_IDProperty, &IDGroup_Type);
+       BPy_IDProperty *wrap = PyObject_New(BPy_IDProperty, &BPy_IDGroup_Type);
        wrap->prop = prop;
        wrap->parent = parent;
        wrap->id = id;
@@ -872,36 +894,58 @@ PyObject *BPy_Wrap_IDProperty(ID *id, IDProperty *prop, IDProperty *parent)
 
 /********Array Wrapper********/
 
-static PyObject *IDArray_repr(BPy_IDArray *self)
+static PyTypeObject *idp_array_py_type(BPy_IDArray *self, short *is_double)
 {
-       return PyUnicode_FromFormat("(ID Array [%d])", self->prop->len);
-}
+       switch (self->prop->subtype) {
+               case IDP_FLOAT:
+                       *is_double= 0;
+                       return &PyFloat_Type;
+               case IDP_DOUBLE:
+                       *is_double= 1;
+                       return &PyFloat_Type;
+               case IDP_INT:
+                       *is_double= 0;
+                       return &PyLong_Type;
+       }
 
+       *is_double= 0;
+       return NULL;
+}
 
-static PyObject *BPy_IDArray_GetType(BPy_IDArray *self)
+static PyObject *BPy_IDArray_repr(BPy_IDArray *self)
 {
-       return PyLong_FromSsize_t( self->prop->subtype );
+       return PyUnicode_FromFormat("<bpy id property array [%d]>", self->prop->len);
 }
 
-static PyObject *BPy_IDArray_GetLen(BPy_IDArray *self)
+static PyObject *BPy_IDArray_GetType(BPy_IDArray *self)
 {
-       return PyLong_FromSsize_t( self->prop->len );
+       switch(self->prop->subtype) {
+       case IDP_FLOAT:
+               return PyUnicode_FromString("f");
+       case IDP_DOUBLE:
+               return PyUnicode_FromString("d");
+       case IDP_INT:
+               return PyUnicode_FromString("i");
+       }
+
+       PyErr_SetString(PyExc_RuntimeError, "invalid/corrupt array type!");
+       return NULL;
 }
 
 static PyGetSetDef BPy_IDArray_getseters[] = {
-       {(char *)"len", (getter)BPy_IDArray_GetLen, (setter)NULL, (char *)"The length of the array, can also be gotten with len(array).", NULL},
-       {(char *)"type", (getter)BPy_IDArray_GetType, (setter)NULL, (char *)"The type of the data in the array, is an ant.", NULL},
+    /* matches pythons array.typecode */
+       {(char *)"typecode", (getter)BPy_IDArray_GetType, (setter)NULL, (char *)"The type of the data in the array, is an int.", NULL},
        {NULL, NULL, NULL, NULL, NULL},
 };
 
-static PyObject *BPy_IDArray_ConvertToPy(BPy_IDArray *self)
+static PyObject *BPy_IDArray_to_list(BPy_IDArray *self)
 {
        return BPy_IDGroup_MapDataToPy(self->prop);
 }
 
 static PyMethodDef BPy_IDArray_methods[] = {
-       {"convert_to_pyobject", (PyCFunction)BPy_IDArray_ConvertToPy, METH_NOARGS,
-               "return a purely python version of the group"},
+       {"to_list", (PyCFunction)BPy_IDArray_to_list, METH_NOARGS,
+               "return the array as a list"},
        {NULL, NULL, 0, NULL}
 };
 
@@ -919,14 +963,11 @@ static PyObject *BPy_IDArray_GetItem(BPy_IDArray *self, int index)
 
        switch (self->prop->subtype) {
                case IDP_FLOAT:
-                       return PyFloat_FromDouble( (double)(((float*)self->prop->data.pointer)[index]));
-                       break;
+                       return PyFloat_FromDouble(((float*)IDP_Array(self->prop))[index]);
                case IDP_DOUBLE:
-                       return PyFloat_FromDouble( (((double*)self->prop->data.pointer)[index]));
-                       break;
+                       return PyFloat_FromDouble(((double*)IDP_Array(self->prop))[index]);
                case IDP_INT:
-                       return PyLong_FromLong( (long)((int*)self->prop->data.pointer)[index] );
-                       break;
+                       return PyLong_FromLong((long)((int*)IDP_Array(self->prop))[index]);
        }
 
        PyErr_SetString(PyExc_RuntimeError, "invalid/corrupt array type!");
@@ -951,7 +992,7 @@ static int BPy_IDArray_SetItem(BPy_IDArray *self, int index, PyObject *value)
                                PyErr_SetString(PyExc_TypeError, "expected a float");
                                return -1;
                        }
-                       ((float*)self->prop->data.pointer)[index] = f;
+                       ((float*)IDP_Array(self->prop))[index] = f;
                        break;
                case IDP_DOUBLE:
                        d= PyFloat_AsDouble(value);
@@ -959,7 +1000,7 @@ static int BPy_IDArray_SetItem(BPy_IDArray *self, int index, PyObject *value)
                                PyErr_SetString(PyExc_TypeError, "expected a float");
                                return -1;
                        }
-                       ((double*)self->prop->data.pointer)[index] = d;
+                       ((double*)IDP_Array(self->prop))[index] = d;
                        break;
                case IDP_INT:
                        i= PyLong_AsSsize_t(value);
@@ -968,7 +1009,7 @@ static int BPy_IDArray_SetItem(BPy_IDArray *self, int index, PyObject *value)
                                return -1;
                        }
 
-                       ((int*)self->prop->data.pointer)[index] = i;
+                       ((int*)IDP_Array(self->prop))[index] = i;
                        break;
        }
        return 0;
@@ -988,11 +1029,156 @@ static PySequenceMethods BPy_IDArray_Seq = {
        NULL,                                                           /* intargfunc sq_inplace_repeat */
 };
 
-PyTypeObject IDArray_Type = {
+
+
+/* sequence slice (get): idparr[a:b] */
+static PyObject *BPy_IDArray_slice(BPy_IDArray *self, int begin, int end)
+{
+       IDProperty *prop= self->prop;
+       PyObject *tuple;
+       int count;
+
+       CLAMP(begin, 0, prop->len);
+       if (end<0) end= prop->len+end+1;
+       CLAMP(end, 0, prop->len);
+       begin= MIN2(begin, end);
+
+       tuple= PyTuple_New(end - begin);
+
+       switch (prop->subtype) {
+               case IDP_FLOAT:
+               {
+                       float *array= (float*)IDP_Array(prop);
+                       for(count = begin; count < end; count++) {
+                               PyTuple_SET_ITEM(tuple, count - begin, PyFloat_FromDouble(array[count]));
+                       }
+                       break;
+               }
+               case IDP_DOUBLE:
+               {
+                       double *array= (double*)IDP_Array(prop);
+                       for(count = begin; count < end; count++) {
+                               PyTuple_SET_ITEM(tuple, count - begin, PyFloat_FromDouble(array[count]));
+                       }
+                       break;
+               }
+               case IDP_INT:
+               {
+                       int *array= (int*)IDP_Array(prop);
+                       for(count = begin; count < end; count++) {
+                               PyTuple_SET_ITEM(tuple, count - begin, PyLong_FromLong(array[count]));
+                       }
+                       break;
+               }
+       }
+
+       return tuple;
+}
+/* sequence slice (set): idparr[a:b] = value */
+static int BPy_IDArray_ass_slice(BPy_IDArray *self, int begin, int end, PyObject *seq)
+{
+       IDProperty *prop= self->prop;
+       short is_double= 0;
+       const PyTypeObject *py_type= idp_array_py_type(self, &is_double);
+       const size_t elem_size= is_double ? sizeof(double) : sizeof(float);
+       size_t alloc_len;
+       size_t size;
+       void *vec;
+
+       CLAMP(begin, 0, prop->len);
+       CLAMP(end, 0, prop->len);
+       begin = MIN2(begin, end);
+
+       size = (end - begin);
+       alloc_len= size * elem_size;
+
+       vec= MEM_mallocN(alloc_len, "array assignment"); /* NOTE: we count on int/float being the same size here */
+       if(PyC_AsArray(vec, seq, size, py_type, is_double, "slice assignment: ") == -1) {
+               MEM_freeN(vec);
+               return -1;
+       }
+
+       memcpy((void *)(((char *)IDP_Array(prop)) + (begin * elem_size)), vec, alloc_len);
+
+       MEM_freeN(vec);
+       return 0;
+}
+
+static PyObject *BPy_IDArray_subscript(BPy_IDArray* self, PyObject* item)
+{
+       if (PyIndex_Check(item)) {
+               Py_ssize_t i;
+               i = PyNumber_AsSsize_t(item, PyExc_IndexError);
+               if (i == -1 && PyErr_Occurred())
+                       return NULL;
+               if (i < 0)
+                       i += self->prop->len;
+               return BPy_IDArray_GetItem(self, i);
+       }
+       else if (PySlice_Check(item)) {
+               Py_ssize_t start, stop, step, slicelength;
+
+               if (PySlice_GetIndicesEx((void *)item, self->prop->len, &start, &stop, &step, &slicelength) < 0)
+                       return NULL;
+
+               if (slicelength <= 0) {
+                       return PyTuple_New(0);
+               }
+               else if (step == 1) {
+                       return BPy_IDArray_slice(self, start, stop);
+               }
+               else {
+                       PyErr_SetString(PyExc_TypeError, "slice steps not supported with vectors");
+                       return NULL;
+               }
+       }
+       else {
+               PyErr_Format(PyExc_TypeError, "vector indices must be integers, not %.200s", Py_TYPE(item)->tp_name);
+               return NULL;
+       }
+}
+
+static int BPy_IDArray_ass_subscript(BPy_IDArray* self, PyObject* item, PyObject* value)
+{
+       if (PyIndex_Check(item)) {
+               Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
+               if (i == -1 && PyErr_Occurred())
+                       return -1;
+               if (i < 0)
+                       i += self->prop->len;
+               return BPy_IDArray_SetItem(self, i, value);
+       }
+       else if (PySlice_Check(item)) {
+               Py_ssize_t start, stop, step, slicelength;
+
+               if (PySlice_GetIndicesEx((void *)item, self->prop->len, &start, &stop, &step, &slicelength) < 0)
+                       return -1;
+
+               if (step == 1)
+                       return BPy_IDArray_ass_slice(self, start, stop, value);
+               else {
+                       PyErr_SetString(PyExc_TypeError, "slice steps not supported with vectors");
+                       return -1;
+               }
+       }
+       else {
+               PyErr_Format(PyExc_TypeError, "vector indices must be integers, not %.200s", Py_TYPE(item)->tp_name);
+               return -1;
+       }
+}
+
+static PyMappingMethods BPy_IDArray_AsMapping = {
+       (lenfunc)BPy_IDArray_Len,
+       (binaryfunc)BPy_IDArray_subscript,
+       (objobjargproc)BPy_IDArray_ass_subscript
+};
+
+
+PyTypeObject BPy_IDArray_Type = {
        PyVarObject_HEAD_INIT(NULL, 0)
        /*  For printing, in format "<module>.<name>" */
        "Blender IDArray",           /* char *tp_name; */
-       sizeof( BPy_IDArray ),       /* int tp_basicsize; */
+       sizeof(BPy_IDArray),       /* int tp_basicsize; */
        0,                          /* tp_itemsize;  For allocation */
 
        /* Methods to implement standard operations */
@@ -1002,17 +1188,17 @@ PyTypeObject IDArray_Type = {
        NULL,     /* getattrfunc tp_getattr; */
        NULL,     /* setattrfunc tp_setattr; */
        NULL,                       /* cmpfunc tp_compare; */
-       ( reprfunc ) IDArray_repr,     /* reprfunc tp_repr; */
+       (reprfunc)BPy_IDArray_repr,     /* reprfunc tp_repr; */
 
        /* Method suites for standard classes */
 
        NULL,                       /* PyNumberMethods *tp_as_number; */
-       &BPy_IDArray_Seq,                       /* PySequenceMethods *tp_as_sequence; */
-       NULL,                       /* PyMappingMethods *tp_as_mapping; */
+       &BPy_IDArray_Seq,               /* PySequenceMethods *tp_as_sequence; */
+       &BPy_IDArray_AsMapping,     /* PyMappingMethods *tp_as_mapping; */
 
        /* More standard operations (here for binary compatibility) */
 
-       NULL,                       /* hashfunc tp_hash; */
+       NULL,                                           /* hashfunc tp_hash; */
        NULL,                       /* ternaryfunc tp_call; */
        NULL,                       /* reprfunc tp_str; */
        NULL,                       /* getattrofunc tp_getattro; */
@@ -1106,7 +1292,7 @@ static PyObject *BPy_Group_Iter_Next(BPy_IDGroup_Iter *self)
        }
 }
 
-PyTypeObject IDGroup_Iter_Type = {
+PyTypeObject BPy_IDGroup_Iter_Type = {
        PyVarObject_HEAD_INIT(NULL, 0)
        /*  For printing, in format "<module>.<name>" */
        "Blender IDGroup_Iter",           /* char *tp_name; */
@@ -1165,7 +1351,7 @@ PyTypeObject IDGroup_Iter_Type = {
 
 void IDProp_Init_Types(void)
 {
-       PyType_Ready( &IDGroup_Type );
-       PyType_Ready( &IDGroup_Iter_Type );
-       PyType_Ready( &IDArray_Type );
+       PyType_Ready(&BPy_IDGroup_Type);
+       PyType_Ready(&BPy_IDGroup_Iter_Type);
+       PyType_Ready(&BPy_IDArray_Type);
 }
index 0ca8af8..aca5c01 100644 (file)
@@ -37,14 +37,15 @@ struct BPy_IDGroup_Iter;
 typedef struct BPy_IDProperty {
        PyObject_VAR_HEAD
        struct ID *id;
-       struct IDProperty *prop, *parent;
+       struct IDProperty *prop; /* must be second member */
+       struct IDProperty *parent;
        PyObject *data_wrap;
 } BPy_IDProperty;
 
 typedef struct BPy_IDArray {
        PyObject_VAR_HEAD
        struct ID *id;
-       struct IDProperty *prop;
+       struct IDProperty *prop;  /* must be second member */
 } BPy_IDArray;
 
 typedef struct BPy_IDGroup_Iter {
index ec774f4..801e44b 100644 (file)
 
 #define PYC_INTERPRETER_ACTIVE (((PyThreadState*)_Py_atomic_load_relaxed(&_PyThreadState_Current)) != NULL)
 
+/* array utility function */
+int PyC_AsArray(void *array, PyObject *value, const int length, const PyTypeObject *type, const short is_double, const char *error_prefix)
+{
+       PyObject *value_fast;
+       int value_len;
+       int i;
+
+       if(!(value_fast=PySequence_Fast(value, error_prefix))) {
+               return -1;
+       }
+
+       value_len= PySequence_Fast_GET_SIZE(value_fast);
+
+       if(value_len != length) {
+               Py_DECREF(value);
+               PyErr_Format(PyExc_TypeError,
+                            "%.200s: invalid sequence length. expected %d, got %d",
+                            error_prefix, length, value_len);
+               return -1;
+       }
+
+       /* for each type */
+       if(type == &PyFloat_Type) {
+               if(is_double) {
+                       double *array_double= array;
+                       for(i=0; i<length; i++) {
+                               array_double[i]= PyFloat_AsDouble(PySequence_Fast_GET_ITEM(value_fast, i));
+                       }
+               }
+               else {
+                       float *array_float= array;
+                       for(i=0; i<length; i++) {
+                               array_float[i]= PyFloat_AsDouble(PySequence_Fast_GET_ITEM(value_fast, i));
+                       }
+               }
+       }
+       else if(type == &PyLong_Type) {
+               /* could use is_double for 'long int' but no use now */
+               int *array_int= array;
+               for(i=0; i<length; i++) {
+                       array_int[i]= PyLong_AsSsize_t(PySequence_Fast_GET_ITEM(value_fast, i));
+               }
+       }
+       else if(type == &PyBool_Type) {
+               int *array_bool= array;
+               for(i=0; i<length; i++) {
+                       array_bool[i]= (PyLong_AsSsize_t(PySequence_Fast_GET_ITEM(value_fast, i)) != 0);
+               }
+       }
+       else {
+               Py_DECREF(value_fast);
+               PyErr_Format(PyExc_TypeError,
+                            "%s: internal error %s is invalid",
+                            error_prefix, type->tp_name);
+               return -1;
+       }
+
+       Py_DECREF(value_fast);
+
+       if(PyErr_Occurred()) {
+               PyErr_Format(PyExc_TypeError,
+                            "%s: one or more items could not be used as a %s",
+                            error_prefix, type->tp_name);
+               return -1;
+       }
+
+       return 0;
+}
+
+
 /* for debugging */
 void PyC_ObSpit(const char *name, PyObject *var) {
        fprintf(stderr, "<%s> : ", name);
index 1730ad7..bf2eb17 100644 (file)
@@ -35,7 +35,7 @@ void                  PyC_LineSpit(void);
 PyObject *             PyC_ExceptionBuffer(void);
 PyObject *             PyC_Object_GetAttrStringArgs(PyObject *o, Py_ssize_t n, ...);
 void                   PyC_FileAndNum(const char **filename, int *lineno);
-int                            PyC_AsArray(void *array, PyObject *value, int length, PyTypeObject *type, const char *error_prefix);
+int                            PyC_AsArray(void *array, PyObject *value, const int length, const PyTypeObject *type, const short is_double, const char *error_prefix);
 
 /* follow http://www.python.org/dev/peps/pep-0383/ */
 PyObject *             PyC_UnicodeFromByte(const char *str);
index 8ed4e41..0ba80bf 100644 (file)
@@ -459,7 +459,7 @@ static PyObject *BPy_BoolVectorProperty(PyObject *self, PyObject *args, PyObject
                        return NULL;
                }
 
-               if(pydef && PyC_AsArray(def, pydef, size, &PyBool_Type, "BoolVectorProperty(default=sequence)") < 0)
+               if(pydef && PyC_AsArray(def, pydef, size, &PyBool_Type, FALSE, "BoolVectorProperty(default=sequence)") < 0)
                        return NULL;
 
                if (bpy_prop_callback_check(update_cb, 2) == -1) {
@@ -603,7 +603,7 @@ static PyObject *BPy_IntVectorProperty(PyObject *self, PyObject *args, PyObject
                        return NULL;
                }
 
-               if(pydef && PyC_AsArray(def, pydef, size, &PyLong_Type, "IntVectorProperty(default=sequence)") < 0)
+               if(pydef && PyC_AsArray(def, pydef, size, &PyLong_Type, FALSE, "IntVectorProperty(default=sequence)") < 0)
                        return NULL;
 
                if (bpy_prop_callback_check(update_cb, 2) == -1) {
@@ -759,7 +759,7 @@ static PyObject *BPy_FloatVectorProperty(PyObject *self, PyObject *args, PyObjec
                        return NULL;
                }
 
-               if(pydef && PyC_AsArray(def, pydef, size, &PyFloat_Type, "FloatVectorProperty(default=sequence)") < 0)
+               if(pydef && PyC_AsArray(def, pydef, size, &PyFloat_Type, FALSE, "FloatVectorProperty(default=sequence)") < 0)
                        return NULL;
 
                if (bpy_prop_callback_check(update_cb, 2) == -1) {
index 6e32101..1450621 100644 (file)
@@ -122,63 +122,3 @@ short BPy_errors_to_report(ReportList *reports)
        Py_DECREF(pystring_format); // workaround
        return 1;
 }
-
-/* array utility function */
-int PyC_AsArray(void *array, PyObject *value, int length, PyTypeObject *type, const char *error_prefix)
-{
-       PyObject *value_fast;
-       int value_len;
-       int i;
-
-       if(!(value_fast=PySequence_Fast(value, error_prefix))) {
-               return -1;
-       }
-
-       value_len= PySequence_Fast_GET_SIZE(value_fast);
-
-       if(value_len != length) {
-               Py_DECREF(value);
-               PyErr_Format(PyExc_TypeError,
-                            "%.200s: invalid sequence length. expected %d, got %d",
-                            error_prefix, length, value_len);
-               return -1;
-       }
-
-       /* for each type */
-       if(type == &PyFloat_Type) {
-               float *array_float= array;
-               for(i=0; i<length; i++) {
-                       array_float[i]= PyFloat_AsDouble(PySequence_Fast_GET_ITEM(value_fast, i));
-               }
-       }
-       else if(type == &PyLong_Type) {
-               int *array_int= array;
-               for(i=0; i<length; i++) {
-                       array_int[i]= PyLong_AsSsize_t(PySequence_Fast_GET_ITEM(value_fast, i));
-               }
-       }
-       else if(type == &PyBool_Type) {
-               int *array_bool= array;
-               for(i=0; i<length; i++) {
-                       array_bool[i]= (PyLong_AsSsize_t(PySequence_Fast_GET_ITEM(value_fast, i)) != 0);
-               }
-       }
-       else {
-               Py_DECREF(value_fast);
-               PyErr_Format(PyExc_TypeError,
-                            "%s: internal error %s is invalid",
-                            error_prefix, type->tp_name);
-               return -1;
-       }
-
-       Py_DECREF(value_fast);
-
-       if(PyErr_Occurred()) {
-               PyErr_Format(PyExc_TypeError,
-                            "%s: one or more items could not be used as a %s",
-                            error_prefix, type->tp_name);
-               return -1;
-       }
-
-       return 0;
-}