Merge from 2.5 r21160 through r21285
[blender.git] / source / blender / python / intern / bpy_rna.c
index 90876b36ee05ef05973bfba685e7e273d6658ebf..c5c56aeb5b08c73ce0fbf8e4123f2c86bfb65841 100644 (file)
@@ -204,13 +204,13 @@ static long pyrna_struct_hash( BPy_StructRNA * self )
 /* use our own dealloc so we can free a property if we use one */
 static void pyrna_struct_dealloc( BPy_StructRNA * self )
 {
-       /* Note!! for some weired reason calling PyObject_DEL() directly crashes blender! */
        if (self->freeptr && self->ptr.data) {
                IDP_FreeProperty(self->ptr.data);
                MEM_freeN(self->ptr.data);
                self->ptr.data= NULL;
        }
 
+       /* Note, for subclassed PyObjects we cant just call PyObject_DEL() directly or it will crash */
        Py_TYPE(self)->tp_free(self);
        return;
 }
@@ -269,6 +269,8 @@ PyObject * pyrna_prop_to_py(PointerRNA *ptr, PropertyRNA *prop)
                                        ret= quat_cb; /* return the matrix instead */
                                }
                                break;
+                       default:
+                               break;
                        }
                }
 
@@ -677,6 +679,10 @@ int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyObject *v
                        int seq_len, i;
                        PyObject *item;
                        PointerRNA itemptr;
+                       ListBase *lb;
+                       CollectionPointerLink *link;
+
+                       lb= (data)? (ListBase*)data: NULL;
                        
                        /* convert a sequence of dict's into a collection */
                        if(!PySequence_Check(value)) {
@@ -692,8 +698,15 @@ int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyObject *v
                                        Py_XDECREF(item);
                                        return -1;
                                }
-                               
-                               RNA_property_collection_add(ptr, prop, &itemptr);
+
+                               if(lb) {
+                                       link= MEM_callocN(sizeof(CollectionPointerLink), "PyCollectionPointerLink");
+                                       link->ptr= itemptr;
+                                       BLI_addtail(lb, link);
+                               }
+                               else
+                                       RNA_property_collection_add(ptr, prop, &itemptr);
+
                                if(pyrna_pydict_to_props(&itemptr, item, "Converting a python list to an RNA collection")==-1) {
                                        Py_DECREF(item);
                                        return -1;
@@ -1117,7 +1130,7 @@ static int pyrna_struct_setattro( BPy_StructRNA * self, PyObject *pyname, PyObje
        return pyrna_py_to_prop(&self->ptr, prop, NULL, value);
 }
 
-PyObject *pyrna_prop_keys(BPy_PropertyRNA *self)
+static PyObject *pyrna_prop_keys(BPy_PropertyRNA *self)
 {
        PyObject *ret;
        if (RNA_property_type(self->prop) != PROP_COLLECTION) {
@@ -1149,7 +1162,7 @@ PyObject *pyrna_prop_keys(BPy_PropertyRNA *self)
        return ret;
 }
 
-PyObject *pyrna_prop_items(BPy_PropertyRNA *self)
+static PyObject *pyrna_prop_items(BPy_PropertyRNA *self)
 {
        PyObject *ret;
        if (RNA_property_type(self->prop) != PROP_COLLECTION) {
@@ -1190,7 +1203,7 @@ PyObject *pyrna_prop_items(BPy_PropertyRNA *self)
 }
 
 
-PyObject *pyrna_prop_values(BPy_PropertyRNA *self)
+static PyObject *pyrna_prop_values(BPy_PropertyRNA *self)
 {
        PyObject *ret;
        
@@ -1212,6 +1225,241 @@ PyObject *pyrna_prop_values(BPy_PropertyRNA *self)
        return ret;
 }
 
+#if (PY_VERSION_HEX >= 0x03000000) /* foreach needs py3 */
+static void foreach_attr_type( BPy_PropertyRNA *self, char *attr,
+                                                                       /* values to assign */
+                                                                       RawPropertyType *raw_type, int *attr_tot, int *attr_signed )
+{
+       PropertyRNA *prop;
+       *raw_type= -1;
+       *attr_tot= 0;
+       *attr_signed= 0;
+
+       RNA_PROP_BEGIN(&self->ptr, itemptr, self->prop) {
+               prop = RNA_struct_find_property(&itemptr, attr);
+               *raw_type= RNA_property_raw_type(prop);
+               *attr_tot = RNA_property_array_length(prop);
+               *attr_signed= (RNA_property_subtype(prop)==PROP_UNSIGNED) ? 0:1;
+               break;
+       }
+       RNA_PROP_END;
+}
+
+/* pyrna_prop_foreach_get/set both use this */
+static int foreach_parse_args(
+               BPy_PropertyRNA *self, PyObject *args,
+
+               /*values to assign */
+               char **attr, PyObject **seq, int *tot, int *size, RawPropertyType *raw_type, int *attr_tot, int *attr_signed)
+{
+       int array_tot;
+       int target_tot;
+
+       *size= *raw_type= *attr_tot= *attr_signed= 0;
+
+       if(!PyArg_ParseTuple(args, "sO", attr, seq) || (!PySequence_Check(*seq) && PyObject_CheckBuffer(*seq))) {
+               PyErr_SetString( PyExc_TypeError, "foreach_get(attr, sequence) expects a string and a sequence" );
+               return -1;
+       }
+
+       *tot= PySequence_Length(*seq); // TODO - buffer may not be a sequence! array.array() is tho.
+
+       if(*tot>0) {
+               foreach_attr_type(self, *attr, raw_type, attr_tot, attr_signed);
+               *size= RNA_raw_type_sizeof(*raw_type);
+
+#if 0  // works fine but not strictly needed, we could allow RNA_property_collection_raw_* to do the checks
+               if((*attr_tot) < 1)
+                       *attr_tot= 1;
+
+               if (RNA_property_type(self->prop) == PROP_COLLECTION)
+                       array_tot = RNA_property_collection_length(&self->ptr, self->prop);
+               else
+                       array_tot = RNA_property_array_length(self->prop);
+
+
+               target_tot= array_tot * (*attr_tot);
+
+               /* rna_access.c - rna_raw_access(...) uses this same method */
+               if(target_tot != (*tot)) {
+                       PyErr_Format( PyExc_TypeError, "foreach_get(attr, sequence) sequence length mismatch given %d, needed %d", *tot, target_tot);
+                       return -1;
+               }
+#endif
+       }
+
+       return 0;
+}
+
+static int foreach_compat_buffer(RawPropertyType raw_type, int attr_signed, const char *format)
+{
+       char f = format ? *format:'B'; /* B is assumed when not set */
+
+       switch(raw_type) {
+       case PROP_RAW_CHAR:
+               if (attr_signed)        return (f=='b') ? 1:0;
+               else                            return (f=='B') ? 1:0;
+       case PROP_RAW_SHORT:
+               if (attr_signed)        return (f=='h') ? 1:0;
+               else                            return (f=='H') ? 1:0;
+       case PROP_RAW_INT:
+               if (attr_signed)        return (f=='i') ? 1:0;
+               else                            return (f=='I') ? 1:0;
+       case PROP_RAW_FLOAT:
+               return (f=='f') ? 1:0;
+       case PROP_RAW_DOUBLE:
+               return (f=='d') ? 1:0;
+       }
+
+       return 0;
+}
+
+static PyObject *foreach_getset(BPy_PropertyRNA *self, PyObject *args, int set)
+{
+       PyObject *item;
+       int i=0, ok, buffer_is_compat;
+       void *array= NULL;
+
+       /* get/set both take the same args currently */
+       char *attr;
+       PyObject *seq;
+       int tot, size, attr_tot, attr_signed;
+       RawPropertyType raw_type;
+
+       if(foreach_parse_args(self, args,    &attr, &seq, &tot, &size, &raw_type, &attr_tot, &attr_signed) < 0)
+               return NULL;
+
+       if(tot==0)
+               Py_RETURN_NONE;
+
+
+
+       if(set) { /* get the array from python */
+               buffer_is_compat = 0;
+               if(PyObject_CheckBuffer(seq)) {
+                       Py_buffer buf;
+                       PyObject_GetBuffer(seq, &buf, PyBUF_SIMPLE | PyBUF_FORMAT);
+
+                       /* check if the buffer matches, TODO - signed/unsigned types */
+
+                       buffer_is_compat = foreach_compat_buffer(raw_type, attr_signed, buf.format);
+
+                       if(buffer_is_compat) {
+                               ok = RNA_property_collection_raw_set(NULL, &self->ptr, self->prop, attr, buf.buf, raw_type, tot);
+                       }
+
+                       PyBuffer_Release(&buf);
+               }
+
+               /* could not use the buffer, fallback to sequence */
+               if(!buffer_is_compat) {
+                       array= PyMem_Malloc(size * tot);
+
+                       for( ; i<tot; i++) {
+                               item= PySequence_GetItem(seq, i);
+                               switch(raw_type) {
+                               case PROP_RAW_CHAR:
+                                       ((char *)array)[i]= (char)PyLong_AsSsize_t(item);
+                                       break;
+                               case PROP_RAW_SHORT:
+                                       ((short *)array)[i]= (short)PyLong_AsSsize_t(item);
+                                       break;
+                               case PROP_RAW_INT:
+                                       ((int *)array)[i]= (int)PyLong_AsSsize_t(item);
+                                       break;
+                               case PROP_RAW_FLOAT:
+                                       ((float *)array)[i]= (float)PyFloat_AsDouble(item);
+                                       break;
+                               case PROP_RAW_DOUBLE:
+                                       ((double *)array)[i]= (double)PyFloat_AsDouble(item);
+                                       break;
+                               }
+
+                               Py_DECREF(item);
+                       }
+
+                       ok = RNA_property_collection_raw_set(NULL, &self->ptr, self->prop, attr, array, raw_type, tot);
+               }
+       }
+       else {
+               buffer_is_compat = 0;
+               if(PyObject_CheckBuffer(seq)) {
+                       Py_buffer buf;
+                       PyObject_GetBuffer(seq, &buf, PyBUF_SIMPLE | PyBUF_FORMAT);
+
+                       /* check if the buffer matches, TODO - signed/unsigned types */
+
+                       buffer_is_compat = foreach_compat_buffer(raw_type, attr_signed, buf.format);
+
+                       if(buffer_is_compat) {
+                               ok = RNA_property_collection_raw_get(NULL, &self->ptr, self->prop, attr, buf.buf, raw_type, tot);
+                       }
+
+                       PyBuffer_Release(&buf);
+               }
+
+               /* could not use the buffer, fallback to sequence */
+               if(!buffer_is_compat) {
+                       array= PyMem_Malloc(size * tot);
+
+                       ok = RNA_property_collection_raw_get(NULL, &self->ptr, self->prop, attr, array, raw_type, tot);
+
+                       if(!ok) i= tot; /* skip the loop */
+
+                       for( ; i<tot; i++) {
+
+                               switch(raw_type) {
+                               case PROP_RAW_CHAR:
+                                       item= PyLong_FromSsize_t(  (Py_ssize_t) ((char *)array)[i]  );
+                                       break;
+                               case PROP_RAW_SHORT:
+                                       item= PyLong_FromSsize_t(  (Py_ssize_t) ((short *)array)[i]  );
+                                       break;
+                               case PROP_RAW_INT:
+                                       item= PyLong_FromSsize_t(  (Py_ssize_t) ((int *)array)[i]  );
+                                       break;
+                               case PROP_RAW_FLOAT:
+                                       item= PyFloat_FromDouble(  (double) ((float *)array)[i]  );
+                                       break;
+                               case PROP_RAW_DOUBLE:
+                                       item= PyFloat_FromDouble(  (double) ((double *)array)[i]  );
+                                       break;
+                               }
+
+                               PySequence_SetItem(seq, i, item);
+                               Py_DECREF(item);
+                       }
+               }
+       }
+
+       if(PyErr_Occurred()) {
+               /* Maybe we could make our own error */
+               PyErr_Print();
+               PyErr_SetString(PyExc_SystemError, "could not access the py sequence");
+               return NULL;
+       }
+       if (!ok) {
+               PyErr_SetString(PyExc_SystemError, "internal error setting the array");
+               return NULL;
+       }
+
+       if(array)
+               PyMem_Free(array);
+
+       Py_RETURN_NONE;
+}
+
+static PyObject *pyrna_prop_foreach_get(BPy_PropertyRNA *self, PyObject *args)
+{
+       return foreach_getset(self, args, 0);
+}
+
+static  PyObject *pyrna_prop_foreach_set(BPy_PropertyRNA *self, PyObject *args)
+{
+       return foreach_getset(self, args, 1);
+}
+#endif /* #if (PY_VERSION_HEX >= 0x03000000) */
+
 /* A bit of a kludge, make a list out of a collection or array,
  * then return the lists iter function, not especially fast but convenient for now */
 PyObject *pyrna_prop_iter(BPy_PropertyRNA *self)
@@ -1246,14 +1494,20 @@ PyObject *pyrna_prop_iter(BPy_PropertyRNA *self)
 }
 
 static struct PyMethodDef pyrna_struct_methods[] = {
-       {"__dir__", (PyCFunction)pyrna_struct_dir, METH_NOARGS, ""},
+       {"__dir__", (PyCFunction)pyrna_struct_dir, METH_NOARGS, NULL},
        {NULL, NULL, 0, NULL}
 };
 
 static struct PyMethodDef pyrna_prop_methods[] = {
-       {"keys", (PyCFunction)pyrna_prop_keys, METH_NOARGS, ""},
-       {"items", (PyCFunction)pyrna_prop_items, METH_NOARGS, ""},
-       {"values", (PyCFunction)pyrna_prop_values, METH_NOARGS, ""},
+       {"keys", (PyCFunction)pyrna_prop_keys, METH_NOARGS, NULL},
+       {"items", (PyCFunction)pyrna_prop_items, METH_NOARGS,NULL},
+       {"values", (PyCFunction)pyrna_prop_values, METH_NOARGS, NULL},
+
+#if (PY_VERSION_HEX >= 0x03000000)
+       /* array accessor function */
+       {"foreach_get", (PyCFunction)pyrna_prop_foreach_get, METH_VARARGS, NULL},
+       {"foreach_set", (PyCFunction)pyrna_prop_foreach_set, METH_VARARGS, NULL},
+#endif
        {NULL, NULL, 0, NULL}
 };
 
@@ -1384,10 +1638,21 @@ PyObject *pyrna_param_to_py(PointerRNA *ptr, PropertyRNA *prop, void *data)
                        break;
                }
                case PROP_COLLECTION:
-                       /* XXX not supported yet
-                        * ret = pyrna_prop_CreatePyObject(ptr, prop); */
-                       ret = NULL;
+               {
+                       ListBase *lb= (ListBase*)data;
+                       CollectionPointerLink *link;
+                       PyObject *linkptr;
+
+                       ret = PyList_New(0);
+
+                       for(link=lb->first; link; link=link->next) {
+                               linkptr= pyrna_struct_CreatePyObject(&link->ptr);
+                               PyList_Append(ret, linkptr);
+                               Py_DECREF(linkptr);
+                       }
+
                        break;
+               }
                default:
                        PyErr_Format(PyExc_AttributeError, "RNA Error: unknown type \"%d\" (pyrna_param_to_py)", type);
                        ret = NULL;