rna function api was overwriting useful errors with keyword errors.
[blender.git] / source / blender / python / intern / bpy_rna.c
index c71d7c7d90dc94c48fd459357cd8388b8c13cec9..50e32f34594a206de22b018bb53d1b36292af04e 100644 (file)
@@ -130,8 +130,74 @@ Mathutils_Callback mathutils_rna_matrix_cb = {
        (BaseMathSetIndexFunc)  NULL
 };
 
+PyObject *pyrna_math_object_from_array(PointerRNA *ptr, PropertyRNA *prop)
+{
+       PyObject *ret= NULL;
+
+#ifdef USE_MATHUTILS
+       int type, subtype, totdim;
+       int len;
+
+       len= RNA_property_array_length(ptr, prop);
+       type= RNA_property_type(prop);
+       subtype= RNA_property_subtype(prop);
+       totdim= RNA_property_array_dimension(ptr, prop, NULL);
+
+       if (type != PROP_FLOAT) return NULL;
+
+       if (totdim == 1 || (totdim == 2 && subtype == PROP_MATRIX)) {
+               ret = pyrna_prop_CreatePyObject(ptr, prop);
+
+               switch(RNA_property_subtype(prop)) {
+               case PROP_TRANSLATION:
+               case PROP_DIRECTION:
+               case PROP_VELOCITY:
+               case PROP_ACCELERATION:
+               case PROP_XYZ:
+                       if(len>=2 && len <= 4) {
+                               PyObject *vec_cb= newVectorObject_cb(ret, len, mathutils_rna_array_cb_index, FALSE);
+                               Py_DECREF(ret); /* the vector owns now */
+                               ret= vec_cb; /* return the vector instead */
+                       }
+                       break;
+               case PROP_MATRIX:
+                       if(len==16) {
+                               PyObject *mat_cb= newMatrixObject_cb(ret, 4,4, mathutils_rna_matrix_cb_index, FALSE);
+                               Py_DECREF(ret); /* the matrix owns now */
+                               ret= mat_cb; /* return the matrix instead */
+                       }
+                       else if (len==9) {
+                               PyObject *mat_cb= newMatrixObject_cb(ret, 3,3, mathutils_rna_matrix_cb_index, FALSE);
+                               Py_DECREF(ret); /* the matrix owns now */
+                               ret= mat_cb; /* return the matrix instead */
+                       }
+                       break;
+               case PROP_EULER:
+               case PROP_QUATERNION:
+                       if(len==3) { /* euler */
+                               PyObject *eul_cb= newEulerObject_cb(ret, mathutils_rna_array_cb_index, FALSE);
+                               Py_DECREF(ret); /* the matrix owns now */
+                               ret= eul_cb; /* return the matrix instead */
+                       }
+                       else if (len==4) {
+                               PyObject *quat_cb= newQuaternionObject_cb(ret, mathutils_rna_array_cb_index, FALSE);
+                               Py_DECREF(ret); /* the matrix owns now */
+                               ret= quat_cb; /* return the matrix instead */
+                       }
+                       break;
+               default:
+                       break;
+               }
+       }
+#endif
+
+       return ret;
+}
+
 #endif
 
+static StructRNA *pyrna_struct_as_srna(PyObject *self);
+
 static int pyrna_struct_compare( BPy_StructRNA * a, BPy_StructRNA * b )
 {
        return (a->ptr.data==b->ptr.data) ? 0 : -1;
@@ -142,25 +208,64 @@ static int pyrna_prop_compare( BPy_PropertyRNA * a, BPy_PropertyRNA * b )
        return (a->prop==b->prop && a->ptr.data==b->ptr.data ) ? 0 : -1;
 }
 
-/* For some reason python3 needs these :/ */
-static PyObject *pyrna_struct_richcmp(BPy_StructRNA * a, BPy_StructRNA * b, int op)
+static PyObject *pyrna_struct_richcmp(PyObject *a, PyObject *b, int op)
 {
-       int cmp_result= -1; /* assume false */
-       if (BPy_StructRNA_Check(a) && BPy_StructRNA_Check(b)) {
-               cmp_result= pyrna_struct_compare(a, b);
+       PyObject *res;
+       int ok= -1; /* zero is true */
+
+       if (BPy_StructRNA_Check(a) && BPy_StructRNA_Check(b))
+               ok= pyrna_struct_compare((BPy_StructRNA *)a, (BPy_StructRNA *)b);
+
+       switch (op) {
+       case Py_NE:
+               ok = !ok; /* pass through */
+       case Py_EQ:
+               res = ok ? Py_False : Py_True;
+               break;
+
+       case Py_LT:
+       case Py_LE:
+       case Py_GT:
+       case Py_GE:
+               res = Py_NotImplemented;
+               break;
+       default:
+               PyErr_BadArgument();
+               return NULL;
        }
 
-       return Py_CmpToRich(op, cmp_result);
+       Py_INCREF(res);
+       return res;
 }
 
-static PyObject *pyrna_prop_richcmp(BPy_PropertyRNA * a, BPy_PropertyRNA * b, int op)
+static PyObject *pyrna_prop_richcmp(PyObject *a, PyObject *b, int op)
 {
-       int cmp_result= -1; /* assume false */
-       if (BPy_PropertyRNA_Check(a) && BPy_PropertyRNA_Check(b)) {
-               cmp_result= pyrna_prop_compare(a, b);
+       PyObject *res;
+       int ok= -1; /* zero is true */
+
+       if (BPy_PropertyRNA_Check(a) && BPy_PropertyRNA_Check(b))
+               ok= pyrna_prop_compare((BPy_PropertyRNA *)a, (BPy_PropertyRNA *)b);
+
+       switch (op) {
+       case Py_NE:
+               ok = !ok; /* pass through */
+       case Py_EQ:
+               res = ok ? Py_False : Py_True;
+               break;
+
+       case Py_LT:
+       case Py_LE:
+       case Py_GT:
+       case Py_GE:
+               res = Py_NotImplemented;
+               break;
+       default:
+               PyErr_BadArgument();
+               return NULL;
        }
 
-       return Py_CmpToRich(op, cmp_result);
+       Py_INCREF(res);
+       return res;
 }
 
 /*----------------------repr--------------------------------------------*/
@@ -244,61 +349,9 @@ PyObject * pyrna_prop_to_py(PointerRNA *ptr, PropertyRNA *prop)
 {
        PyObject *ret;
        int type = RNA_property_type(prop);
-       int len = RNA_property_array_length(prop);
-
-       if (len > 0) {
-               /* resolve the array from a new pytype */
-               PyObject *ret = pyrna_prop_CreatePyObject(ptr, prop);
-               
-#ifdef USE_MATHUTILS
-
-               /* return a mathutils vector where possible */
-               if(RNA_property_type(prop)==PROP_FLOAT) {
-                       switch(RNA_property_subtype(prop)) {
-                       case PROP_TRANSLATION:
-                       case PROP_DIRECTION:
-                       case PROP_VELOCITY:
-                       case PROP_ACCELERATION:
-                       case PROP_XYZ:
-                               if(len>=2 && len <= 4) {
-                                       PyObject *vec_cb= newVectorObject_cb(ret, len, mathutils_rna_array_cb_index, FALSE);
-                                       Py_DECREF(ret); /* the vector owns now */
-                                       ret= vec_cb; /* return the vector instead */
-                               }
-                               break;
-                       case PROP_MATRIX:
-                               if(len==16) {
-                                       PyObject *mat_cb= newMatrixObject_cb(ret, 4,4, mathutils_rna_matrix_cb_index, FALSE);
-                                       Py_DECREF(ret); /* the matrix owns now */
-                                       ret= mat_cb; /* return the matrix instead */
-                               }
-                               else if (len==9) {
-                                       PyObject *mat_cb= newMatrixObject_cb(ret, 3,3, mathutils_rna_matrix_cb_index, FALSE);
-                                       Py_DECREF(ret); /* the matrix owns now */
-                                       ret= mat_cb; /* return the matrix instead */
-                               }
-                               break;
-                       case PROP_EULER:
-                       case PROP_QUATERNION:
-                               if(len==3) { /* euler */
-                                       PyObject *eul_cb= newEulerObject_cb(ret, mathutils_rna_array_cb_index, FALSE);
-                                       Py_DECREF(ret); /* the matrix owns now */
-                                       ret= eul_cb; /* return the matrix instead */
-                               }
-                               else if (len==4) {
-                                       PyObject *quat_cb= newQuaternionObject_cb(ret, mathutils_rna_array_cb_index, FALSE);
-                                       Py_DECREF(ret); /* the matrix owns now */
-                                       ret= quat_cb; /* return the matrix instead */
-                               }
-                               break;
-                       default:
-                               break;
-                       }
-               }
 
-#endif
-               
-               return ret;
+       if (RNA_property_array_check(ptr, prop)) {
+               return pyrna_py_from_array(ptr, prop);
        }
        
        /* see if we can coorce into a python type - PropertyType */
@@ -467,128 +520,33 @@ int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyObject *v
 {
        /* XXX hard limits should be checked here */
        int type = RNA_property_type(prop);
-       int len = RNA_property_array_length(prop);
        
-       if (len > 0) {
-               PyObject *item;
-               int py_len = -1;
-               int i;
-               
+
+       if (RNA_property_array_check(ptr, prop)) {
+
+               /* char error_str[512]; */
+               int ok= 1;
 
 #ifdef USE_MATHUTILS
                if(MatrixObject_Check(value)) {
                        MatrixObject *mat = (MatrixObject*)value;
                        if(!BaseMath_ReadCallback(mat))
                                return -1;
-
-                       py_len = mat->rowSize * mat->colSize;
                } else /* continue... */
 #endif
-               if (PySequence_Check(value)) {
-                       py_len= (int)PySequence_Length(value);
-               }
-               else {
+               if (!PySequence_Check(value)) {
                        PyErr_Format(PyExc_TypeError, "%.200s RNA array assignment expected a sequence instead of %.200s instance.", error_prefix, Py_TYPE(value)->tp_name);
                        return -1;
                }
                /* done getting the length */
-               
-               if (py_len != len) {
-                       PyErr_Format(PyExc_TypeError, "%.200s python sequence length %d did not match the RNA array length %d.", error_prefix, py_len, len);
-                       return -1;
-               }
-               
-               /* for arrays we have a limited number of types */
-               switch (type) {
-               case PROP_BOOLEAN:
-               {
-                       int *param_arr;
-                       if(data)        param_arr= (int*)data;
-                       else            param_arr= MEM_mallocN(sizeof(int) * len, "pyrna bool array");
-
-                       
-                       /* collect the variables before assigning, incase one of them is incorrect */
-                       for (i=0; i<len; i++) {
-                               item = PySequence_GetItem(value, i);
-                               param_arr[i] = PyObject_IsTrue( item );
-                               Py_DECREF(item);
-                               
-                               if (param_arr[i] < 0) {
-                                       if(data==NULL)
-                                               MEM_freeN(param_arr);
-                                       PyErr_Format(PyExc_AttributeError, "%.200s one or more of the values in the sequence is not a boolean", error_prefix);
-                                       return -1;
-                               }
-                       }
-                       if(data==NULL) {
-                               RNA_property_boolean_set_array(ptr, prop, param_arr);
-                               MEM_freeN(param_arr);
-                       }
-
-                       break;
-               }
-               case PROP_INT:
-               {
-                       int *param_arr;
-                       if(data)        param_arr= (int*)data;
-                       else            param_arr= MEM_mallocN(sizeof(int) * len, "pyrna int array");
-
-                       
-                       /* collect the variables */
-                       for (i=0; i<len; i++) {
-                               item = PySequence_GetItem(value, i);
-                               param_arr[i] = (int)PyLong_AsSsize_t(item); /* deal with any errors later */
-                               Py_DECREF(item);
-                       }
-                       
-                       if (PyErr_Occurred()) {
-                               if(data==NULL)
-                                       MEM_freeN(param_arr);
-                               PyErr_Format(PyExc_AttributeError, "%.200s one or more of the values in the sequence could not be used as an int", error_prefix);
-                               return -1;
-                       }
-                       if(data==NULL) {
-                               RNA_property_int_set_array(ptr, prop, param_arr);
-                               MEM_freeN(param_arr);
-                       }
-                       break;
-               }
-               case PROP_FLOAT:
-               {
-                       float *param_arr;
-                       if(data)        param_arr = (float*)data;
-                       else            param_arr = MEM_mallocN(sizeof(float) * len, "pyrna float array");
-
-
-#ifdef USE_MATHUTILS
-                       if(MatrixObject_Check(value) && RNA_property_subtype(prop) == PROP_MATRIX) {
-                               MatrixObject *mat = (MatrixObject*)value;
-                               memcpy(param_arr, mat->contigPtr, sizeof(float) * len);
-                       } else /* continue... */
-#endif
-                       {
-                               /* collect the variables */
-                               for (i=0; i<len; i++) {
-                                       item = PySequence_GetItem(value, i);
-                                       param_arr[i] = (float)PyFloat_AsDouble(item); /* deal with any errors later */
-                                       Py_DECREF(item);
-                               }
-                       }
+               ok= pyrna_py_to_array(ptr, prop, data, value, error_prefix);
 
-                       if (PyErr_Occurred()) {
-                               if(data==NULL)
-                                       MEM_freeN(param_arr);
-                               PyErr_Format(PyExc_AttributeError, "%.200s one or more of the values in the sequence could not be used as a float", error_prefix);
-                               return -1;
-                       }
-                       if(data==NULL) {
-                               RNA_property_float_set_array(ptr, prop, param_arr);                             
-                               MEM_freeN(param_arr);
-                       }
-                       break;
-               }
+               if (!ok) {
+                       /* PyErr_Format(PyExc_AttributeError, "%.200s %s", error_prefix, error_str); */
+                       return -1;
                }
-       } else {
+       }
+       else {
                /* Normal Property (not an array) */
                
                /* see if we can coorce into a python type - PropertyType */
@@ -670,17 +628,18 @@ int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyObject *v
                case PROP_POINTER:
                {
                        StructRNA *ptype= RNA_property_pointer_type(ptr, prop);
+                       int flag = RNA_property_flag(prop);
 
                        if(!BPy_StructRNA_Check(value) && value != Py_None) {
-                               PointerRNA tmp;
-                               RNA_pointer_create(NULL, ptype, NULL, &tmp);
-                               PyErr_Format(PyExc_TypeError, "%.200s expected a %.200s type", error_prefix, RNA_struct_identifier(tmp.type));
+                               PyErr_Format(PyExc_TypeError, "%.200s expected a %.200s type", error_prefix, RNA_struct_identifier(ptype));
+                               return -1;
+                       } else if((flag & PROP_NEVER_NULL) && value == Py_None) {
+                               PyErr_Format(PyExc_TypeError, "property can't be assigned a None value");
                                return -1;
                        } else {
                                BPy_StructRNA *param= (BPy_StructRNA*)value;
                                int raise_error= FALSE;
                                if(data) {
-                                       int flag = RNA_property_flag(prop);
 
                                        if(flag & PROP_RNAPTR) {
                                                if(value == Py_None)
@@ -777,95 +736,95 @@ int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyObject *v
        return 0;
 }
 
-static PyObject * pyrna_prop_to_py_index(PointerRNA *ptr, PropertyRNA *prop, int index)
+static PyObject * pyrna_prop_to_py_index(BPy_PropertyRNA *self, int index)
 {
-       PyObject *ret;
-       int type = RNA_property_type(prop);
-       
-       /* see if we can coorce into a python type - PropertyType */
-       switch (type) {
-       case PROP_BOOLEAN:
-               ret = PyBool_FromLong( RNA_property_boolean_get_index(ptr, prop, index) );
-               break;
-       case PROP_INT:
-               ret = PyLong_FromSsize_t( (Py_ssize_t)RNA_property_int_get_index(ptr, prop, index) );
-               break;
-       case PROP_FLOAT:
-               ret = PyFloat_FromDouble( RNA_property_float_get_index(ptr, prop, index) );
-               break;
-       default:
-               PyErr_SetString(PyExc_AttributeError, "not an array type");
-               ret = NULL;
-               break;
-       }
-       
-       return ret;
+       return pyrna_py_from_array_index(self, index);
 }
 
-static int pyrna_py_to_prop_index(PointerRNA *ptr, PropertyRNA *prop, int index, PyObject *value)
+static int pyrna_py_to_prop_index(BPy_PropertyRNA *self, int index, PyObject *value)
 {
        int ret = 0;
+       int totdim;
+       PointerRNA *ptr= &self->ptr;
+       PropertyRNA *prop= self->prop;
        int type = RNA_property_type(prop);
-       
-       /* see if we can coorce into a python type - PropertyType */
-       switch (type) {
-       case PROP_BOOLEAN:
-       {
-               int param = PyObject_IsTrue( value );
-               
-               if( param < 0 ) {
-                       PyErr_SetString(PyExc_TypeError, "expected True/False or 0/1");
-                       ret = -1;
-               } else {
-                       RNA_property_boolean_set_index(ptr, prop, index, param);
-               }
-               break;
-       }
-       case PROP_INT:
-       {
-               int param = PyLong_AsSsize_t(value);
-               if (PyErr_Occurred()) {
-                       PyErr_SetString(PyExc_TypeError, "expected an int type");
-                       ret = -1;
-               } else {
-                       RNA_property_int_set_index(ptr, prop, index, param);
+
+       totdim= RNA_property_array_dimension(ptr, prop, NULL);
+
+       if (totdim > 1) {
+               /* char error_str[512]; */
+               if (!pyrna_py_to_array_index(&self->ptr, self->prop, self->arraydim, self->arrayoffset, index, value, "")) {
+                       /* PyErr_SetString(PyExc_AttributeError, error_str); */
+                       ret= -1;
                }
-               break;
        }
-       case PROP_FLOAT:
-       {
-               float param = PyFloat_AsDouble(value);
-               if (PyErr_Occurred()) {
-                       PyErr_SetString(PyExc_TypeError, "expected a float type");
+       else {
+               /* see if we can coorce into a python type - PropertyType */
+               switch (type) {
+               case PROP_BOOLEAN:
+                       {
+                               int param = PyObject_IsTrue( value );
+               
+                               if( param < 0 ) {
+                                       PyErr_SetString(PyExc_TypeError, "expected True/False or 0/1");
+                                       ret = -1;
+                               } else {
+                                       RNA_property_boolean_set_index(ptr, prop, index, param);
+                               }
+                               break;
+                       }
+               case PROP_INT:
+                       {
+                               int param = PyLong_AsSsize_t(value);
+                               if (PyErr_Occurred()) {
+                                       PyErr_SetString(PyExc_TypeError, "expected an int type");
+                                       ret = -1;
+                               } else {
+                                       RNA_property_int_set_index(ptr, prop, index, param);
+                               }
+                               break;
+                       }
+               case PROP_FLOAT:
+                       {
+                               float param = PyFloat_AsDouble(value);
+                               if (PyErr_Occurred()) {
+                                       PyErr_SetString(PyExc_TypeError, "expected a float type");
+                                       ret = -1;
+                               } else {
+                                       RNA_property_float_set_index(ptr, prop, index, param);
+                               }
+                               break;
+                       }
+               default:
+                       PyErr_SetString(PyExc_AttributeError, "not an array type");
                        ret = -1;
-               } else {
-                       RNA_property_float_set_index(ptr, prop, index, param);
+                       break;
                }
-               break;
-       }
-       default:
-               PyErr_SetString(PyExc_AttributeError, "not an array type");
-               ret = -1;
-               break;
        }
        
        return ret;
 }
 
 //---------------sequence-------------------------------------------
+static int pyrna_prop_array_length(BPy_PropertyRNA *self)
+{
+       if (RNA_property_array_dimension(&self->ptr, self->prop, NULL) > 1)
+               return RNA_property_multi_array_length(&self->ptr, self->prop, self->arraydim);
+       else
+               return RNA_property_array_length(&self->ptr, self->prop);
+}
+
 static Py_ssize_t pyrna_prop_len( BPy_PropertyRNA * self )
 {
        Py_ssize_t len;
        
        if (RNA_property_type(self->prop) == PROP_COLLECTION) {
                len = RNA_property_collection_length(&self->ptr, self->prop);
+       } else if (RNA_property_array_check(&self->ptr, self->prop)) {
+               len = pyrna_prop_array_length(self);
        } else {
-               len = RNA_property_array_length(self->prop);
-               
-               if (len==0) { /* not an array*/
-                       PyErr_SetString(PyExc_AttributeError, "len() only available for collection RNA types");
-                       return -1;
-               }
+               PyErr_SetString(PyExc_AttributeError, "len() only available for collection and array RNA types");
+               len = -1; /* error value */
        }
        
        return len;
@@ -884,14 +843,15 @@ static PyObject *prop_subscript_collection_int(BPy_PropertyRNA * self, int keynu
        PyErr_Format(PyExc_IndexError, "index %d out of range", keynum);
        return NULL;
 }
+
 static PyObject *prop_subscript_array_int(BPy_PropertyRNA * self, int keynum)
 {
-       int len= RNA_property_array_length(self->prop);
+       int len= pyrna_prop_array_length(self);
 
        if(keynum < 0) keynum += len;
 
        if(keynum >= 0 && keynum < len)
-               return pyrna_prop_to_py_index(&self->ptr, self->prop, keynum);
+               return pyrna_prop_to_py_index(self, keynum);
 
        PyErr_Format(PyExc_IndexError, "index %d out of range", keynum);
        return NULL;
@@ -938,7 +898,7 @@ static PyObject *prop_subscript_array_slice(BPy_PropertyRNA * self, int start, i
        start = MIN2(start,stop); /* values are clamped from PySlice_GetIndicesEx */
 
        for(count = start; count < stop; count++)
-               PyList_SetItem(list, count - start, pyrna_prop_to_py_index(&self->ptr, self->prop, count));
+               PyList_SetItem(list, count - start, pyrna_prop_to_py_index(self, count));
 
        return list;
 }
@@ -991,8 +951,8 @@ static PyObject *prop_subscript_array(BPy_PropertyRNA * self, PyObject *key)
                return prop_subscript_array_int(self, PyLong_AsSsize_t(key));
        }
        else if (PySlice_Check(key)) {
-               int len= RNA_property_array_length(self->prop);
                Py_ssize_t start, stop, step, slicelength;
+               int len = pyrna_prop_array_length(self);
 
                if (PySlice_GetIndicesEx((PySliceObject*)key, len, &start, &stop, &step, &slicelength) < 0)
                        return NULL;
@@ -1018,13 +978,12 @@ static PyObject *pyrna_prop_subscript( BPy_PropertyRNA * self, PyObject *key )
 {
        if (RNA_property_type(self->prop) == PROP_COLLECTION) {
                return prop_subscript_collection(self, key);
-       } else if (RNA_property_array_length(self->prop)) { /* arrays are currently fixed length, zero length means its not an array */
+       } else if (RNA_property_array_check(&self->ptr, self->prop)) {
                return prop_subscript_array(self, key);
-       } else {
-               PyErr_SetString(PyExc_TypeError, "rna type is not an array or a collection");
-               return NULL;
-       }
+       } 
 
+       PyErr_SetString(PyExc_TypeError, "rna type is not an array or a collection");
+       return NULL;
 }
 
 static int prop_subscript_ass_array_slice(BPy_PropertyRNA * self, int begin, int end, PyObject *value)
@@ -1035,7 +994,7 @@ static int prop_subscript_ass_array_slice(BPy_PropertyRNA * self, int begin, int
        begin = MIN2(begin,end);
 
        for(count = begin; count < end; count++) {
-               if(pyrna_py_to_prop_index(&self->ptr, self->prop, count - begin, value) == -1) {
+               if(pyrna_py_to_prop_index(self, count - begin, value) == -1) {
                        /* TODO - this is wrong since some values have been assigned... will need to fix that */
                        return -1; /* pyrna_struct_CreatePyObject should set the error */
                }
@@ -1046,13 +1005,12 @@ static int prop_subscript_ass_array_slice(BPy_PropertyRNA * self, int begin, int
 
 static int prop_subscript_ass_array_int(BPy_PropertyRNA * self, int keynum, PyObject *value)
 {
-
-       int len= RNA_property_array_length(self->prop);
+       int len= pyrna_prop_array_length(self);
 
        if(keynum < 0) keynum += len;
 
        if(keynum >= 0 && keynum < len)
-               return pyrna_py_to_prop_index(&self->ptr, self->prop, keynum, value);
+               return pyrna_py_to_prop_index(self, keynum, value);
 
        PyErr_SetString(PyExc_IndexError, "out of range");
        return -1;
@@ -1081,7 +1039,7 @@ static int pyrna_prop_ass_subscript( BPy_PropertyRNA * self, PyObject *key, PyOb
                return prop_subscript_ass_array_int(self, i, value);
        }
        else if (PySlice_Check(key)) {
-               int len= RNA_property_array_length(self->prop);
+               int len= RNA_property_array_length(&self->ptr, self->prop);
                Py_ssize_t start, stop, step, slicelength;
 
                if (PySlice_GetIndicesEx((PySliceObject*)key, len, &start, &stop, &step, &slicelength) < 0)
@@ -1449,6 +1407,38 @@ static PyObject *pyrna_prop_get(BPy_PropertyRNA *self, PyObject *args)
 }
 
 
+static PyObject *pyrna_prop_add(BPy_PropertyRNA *self, PyObject *args)
+{
+       PointerRNA newptr;
+
+       RNA_property_collection_add(&self->ptr, self->prop, &newptr);
+       if(!newptr.data) {
+               PyErr_SetString( PyExc_TypeError, "add() not supported for this collection");
+               return NULL;
+       }
+       else {
+               return pyrna_struct_CreatePyObject(&newptr);
+       }
+}
+
+static PyObject *pyrna_prop_remove(BPy_PropertyRNA *self, PyObject *args)
+{
+       PyObject *ret;
+       int key= 0;
+
+       if (!PyArg_ParseTuple(args, "i:remove", &key))
+               return NULL;
+
+       if(!RNA_property_collection_remove(&self->ptr, self->prop, key)) {
+               PyErr_SetString( PyExc_TypeError, "remove() not supported for this collection");
+               return NULL;
+       }
+
+       ret = Py_None;
+       Py_INCREF(ret);
+
+       return ret;
+}
 
 static void foreach_attr_type( BPy_PropertyRNA *self, char *attr,
                                                                        /* values to assign */
@@ -1462,7 +1452,7 @@ static void foreach_attr_type(    BPy_PropertyRNA *self, char *attr,
        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_tot = RNA_property_array_length(&itemptr, prop);
                *attr_signed= (RNA_property_subtype(prop)==PROP_UNSIGNED) ? FALSE:TRUE;
                break;
        }
@@ -1501,7 +1491,7 @@ static int foreach_parse_args(
                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);
+                       array_tot = RNA_property_array_length(&self->ptr, self->prop);
 
 
                target_tot= array_tot * (*attr_tot);
@@ -1690,32 +1680,32 @@ static  PyObject *pyrna_prop_foreach_set(BPy_PropertyRNA *self, PyObject *args)
 PyObject *pyrna_prop_iter(BPy_PropertyRNA *self)
 {
        /* Try get values from a collection */
-       PyObject *ret = pyrna_prop_values(self);
+       PyObject *ret;
+       PyObject *iter;
        
-       if (ret==NULL) {
-               /* collection did not work, try array */
-               int len = RNA_property_array_length(self->prop);
+       if(RNA_property_array_check(&self->ptr, self->prop)) {
+               int len = pyrna_prop_array_length(self);
+               int i;
+               PyErr_Clear();
+               ret = PyList_New(len);
                
-               if (len) {
-                       int i;
-                       PyErr_Clear();
-                       ret = PyList_New(len);
-                       
-                       for (i=0; i < len; i++) {
-                               PyList_SET_ITEM(ret, i, pyrna_prop_to_py_index(&self->ptr, self->prop, i));
-                       }
+               for (i=0; i < len; i++) {
+                       PyList_SET_ITEM(ret, i, pyrna_prop_to_py_index(self, i));
                }
        }
-       
-       if (ret) {
-               /* we know this is a list so no need to PyIter_Check */
-               PyObject *iter = PyObject_GetIter(ret); 
-               Py_DECREF(ret);
-               return iter;
+       else if ((ret = pyrna_prop_values(self))) {
+               /* do nothing */
+       }
+       else {
+               PyErr_SetString( PyExc_TypeError, "this BPy_PropertyRNA object is not iterable" );
+               return NULL;
        }
        
-       PyErr_SetString( PyExc_TypeError, "this BPy_PropertyRNA object is not iterable" );
-       return NULL;
+       
+       /* we know this is a list so no need to PyIter_Check */
+       iter = PyObject_GetIter(ret);
+       Py_DECREF(ret);
+       return iter;
 }
 
 static struct PyMethodDef pyrna_struct_methods[] = {
@@ -1734,6 +1724,9 @@ static struct PyMethodDef pyrna_prop_methods[] = {
        
        {"get", (PyCFunction)pyrna_prop_get, METH_VARARGS, NULL},
 
+       {"add", (PyCFunction)pyrna_prop_add, METH_VARARGS, NULL},
+       {"remove", (PyCFunction)pyrna_prop_remove, METH_VARARGS, NULL},
+
        /* array accessor function */
        {"foreach_get", (PyCFunction)pyrna_prop_foreach_get, METH_VARARGS, NULL},
        {"foreach_set", (PyCFunction)pyrna_prop_foreach_set, METH_VARARGS, NULL},
@@ -1782,14 +1775,17 @@ PyObject *pyrna_param_to_py(PointerRNA *ptr, PropertyRNA *prop, void *data)
 {
        PyObject *ret;
        int type = RNA_property_type(prop);
-       int len = RNA_property_array_length(prop);
 
        int a;
 
-       if(len > 0) {
+       if(RNA_property_array_check(ptr, prop)) {
+               int len = RNA_property_array_length(ptr, prop);
+
                /* resolve the array from a new pytype */
                ret = PyTuple_New(len);
 
+               /* kazanbas: TODO make multidim sequences here */
+
                switch (type) {
                case PROP_BOOLEAN:
                        for(a=0; a<len; a++)
@@ -1998,8 +1994,10 @@ static PyObject * pyrna_func_call(PyObject * self, PyObject *args, PyObject *kw)
 
        /* Check if we gave args that dont exist in the function
         * printing the error is slow but it should only happen when developing.
-        * the if below is quick, checking if it passed less keyword args then we gave */
-       if(kw && (PyDict_Size(kw) > kw_tot)) {
+        * the if below is quick, checking if it passed less keyword args then we gave.
+        * (Dont overwrite the error if we have one, otherwise can skip important messages and confuse with args)
+        */
+       if(err == 0 && kw && (PyDict_Size(kw) > kw_tot)) {
                PyObject *key, *value;
                Py_ssize_t pos = 0;
 
@@ -2263,7 +2261,7 @@ static void pyrna_subtype_set_rna(PyObject *newclass, StructRNA *srna)
        PyObject *item;
        
        Py_INCREF(newclass);
-       
+
        if (RNA_struct_py_type_get(srna))
                PyObSpit("RNA WAS SET - ", RNA_struct_py_type_get(srna));
        
@@ -2273,18 +2271,47 @@ static void pyrna_subtype_set_rna(PyObject *newclass, StructRNA *srna)
 
        /* Not 100% needed but useful,
         * having an instance within a type looks wrong however this instance IS an rna type */
+
+       /* python deals with the curcular ref */
        RNA_pointer_create(NULL, &RNA_Struct, srna, &ptr);
        item = pyrna_struct_CreatePyObject(&ptr);
+
+       //item = PyCObject_FromVoidPtr(srna, NULL);
        PyDict_SetItemString(((PyTypeObject *)newclass)->tp_dict, "__rna__", item);
        Py_DECREF(item);
        /* done with rna instance */
 }
 
+/*
+static StructRNA *srna_from_self(PyObject *self);
+PyObject *BPy_GetStructRNA(PyObject *self)
+{
+       StructRNA *srna= pyrna_struct_as_srna(self);
+       PointerRNA ptr;
+       PyObject *ret;
+
+       RNA_pointer_create(NULL, &RNA_Struct, srna, &ptr);
+       ret= pyrna_struct_CreatePyObject(&ptr);
+
+       if(ret) {
+               return ret;
+       }
+       else {
+               Py_RETURN_NONE;
+       }
+}
+*/
+
 static struct PyMethodDef pyrna_struct_subtype_methods[] = {
-       {"FloatProperty", (PyCFunction)BPy_FloatProperty, METH_VARARGS|METH_KEYWORDS, ""},
-       {"IntProperty", (PyCFunction)BPy_IntProperty, METH_VARARGS|METH_KEYWORDS, ""},
        {"BoolProperty", (PyCFunction)BPy_BoolProperty, METH_VARARGS|METH_KEYWORDS, ""},
+       {"IntProperty", (PyCFunction)BPy_IntProperty, METH_VARARGS|METH_KEYWORDS, ""},
+       {"FloatProperty", (PyCFunction)BPy_FloatProperty, METH_VARARGS|METH_KEYWORDS, ""},
        {"StringProperty", (PyCFunction)BPy_StringProperty, METH_VARARGS|METH_KEYWORDS, ""},
+       {"EnumProperty", (PyCFunction)BPy_EnumProperty, METH_VARARGS|METH_KEYWORDS, ""},
+       {"PointerProperty", (PyCFunction)BPy_PointerProperty, METH_VARARGS|METH_KEYWORDS, ""},
+       {"CollectionProperty", (PyCFunction)BPy_CollectionProperty, METH_VARARGS|METH_KEYWORDS, ""},
+
+//     {"__get_rna", (PyCFunction)BPy_GetStructRNA, METH_NOARGS, ""},
        {NULL, NULL, 0, NULL}
 };
 
@@ -2328,14 +2355,17 @@ PyObject* pyrna_srna_Subtype(StructRNA *srna)
                
                /* always use O not N when calling, N causes refcount errors */
                newclass = PyObject_CallFunction(       (PyObject*)&PyType_Type, "s(O){ssss}", idname, py_base, "__module__","bpy.types", "__doc__",descr);
+               /* newclass will now have 2 ref's, ???, probably 1 is internal since decrefing here segfaults */
+
+               /* PyObSpit("new class ref", newclass); */
 
                if (newclass) {
 
-                       /* incref's the new class (has 2 now)
-                        * srna owns one, and the other is owned by the caller */
+                       /* srna owns one, and the other is owned by the caller */
                        pyrna_subtype_set_rna(newclass, srna);
 
-                       // PyObSpit("NewStructRNA Type: ", (PyObject *)newclass);
+                       Py_DECREF(newclass); /* let srna own */
+
 
                        /* attach functions into the class
                         * so you can do... bpy.types.Scene.SomeFunction()
@@ -2422,12 +2452,18 @@ PyObject *pyrna_prop_CreatePyObject( PointerRNA *ptr, PropertyRNA *prop )
        
        pyrna->ptr = *ptr;
        pyrna->prop = prop;
+
+       pyrna->arraydim= 0;
+       pyrna->arrayoffset= 0;
                
        return ( PyObject * ) pyrna;
 }
 
+/* bpy.data from python */
+static PointerRNA *rna_module_ptr= NULL;
 PyObject *BPY_rna_module( void )
 {
+       BPy_StructRNA *pyrna;
        PointerRNA ptr;
        
 #ifdef USE_MATHUTILS // register mathutils callbacks, ok to run more then once.
@@ -2447,8 +2483,15 @@ PyObject *BPY_rna_module( void )
 
        /* for now, return the base RNA type rather then a real module */
        RNA_main_pointer_create(G.main, &ptr);
+       pyrna= (BPy_StructRNA *)pyrna_struct_CreatePyObject(&ptr);
        
-       return pyrna_struct_CreatePyObject(&ptr);
+       rna_module_ptr= &pyrna->ptr;
+       return (PyObject *)pyrna;
+}
+
+void BPY_update_rna_module(void)
+{
+       RNA_main_pointer_create(G.main, rna_module_ptr);
 }
 
 #if 0
@@ -2494,8 +2537,8 @@ static PyObject *pyrna_basetype_getattro( BPy_BaseTypeRNA * self, PyObject *pyna
 static PyObject *pyrna_basetype_dir(BPy_BaseTypeRNA *self);
 static struct PyMethodDef pyrna_basetype_methods[] = {
        {"__dir__", (PyCFunction)pyrna_basetype_dir, METH_NOARGS, ""},
-       {"register", (PyCFunction)pyrna_basetype_register, METH_VARARGS, ""},
-       {"unregister", (PyCFunction)pyrna_basetype_unregister, METH_VARARGS, ""},
+       {"register", (PyCFunction)pyrna_basetype_register, METH_O, ""},
+       {"unregister", (PyCFunction)pyrna_basetype_unregister, METH_O, ""},
        {NULL, NULL, 0, NULL}
 };
 
@@ -2542,10 +2585,13 @@ PyObject *BPY_rna_types(void)
 }
 
 static struct PyMethodDef props_methods[] = {
-       {"FloatProperty", (PyCFunction)BPy_FloatProperty, METH_VARARGS|METH_KEYWORDS, ""},
-       {"IntProperty", (PyCFunction)BPy_IntProperty, METH_VARARGS|METH_KEYWORDS, ""},
        {"BoolProperty", (PyCFunction)BPy_BoolProperty, METH_VARARGS|METH_KEYWORDS, ""},
+       {"IntProperty", (PyCFunction)BPy_IntProperty, METH_VARARGS|METH_KEYWORDS, ""},
+       {"FloatProperty", (PyCFunction)BPy_FloatProperty, METH_VARARGS|METH_KEYWORDS, ""},
        {"StringProperty", (PyCFunction)BPy_StringProperty, METH_VARARGS|METH_KEYWORDS, ""},
+       {"EnumProperty", (PyCFunction)BPy_EnumProperty, METH_VARARGS|METH_KEYWORDS, ""},
+       {"PointerProperty", (PyCFunction)BPy_PointerProperty, METH_VARARGS|METH_KEYWORDS, ""},
+       {"CollectionProperty", (PyCFunction)BPy_CollectionProperty, METH_VARARGS|METH_KEYWORDS, ""},
        {NULL, NULL, 0, NULL}
 };
 
@@ -2571,31 +2617,19 @@ PyObject *BPY_rna_props( void )
        return submodule;
 }
 
-/* Orphan functions, not sure where they should go */
-/* get the srna for methods attached to types */
-/* */
-static StructRNA *srna_from_self(PyObject *self)
+static StructRNA *pyrna_struct_as_srna(PyObject *self)
 {
        BPy_StructRNA *py_srna;
+       StructRNA *srna;
        
-       /* a bit sloppy but would cause a very confusing bug if
-        * an error happened to be set here */
-       PyErr_Clear();
-       
-       if(self==NULL) {
-               return NULL;
-       }
-       else if (PyCObject_Check(self)) {
-               return PyCObject_AsVoidPtr(self);
-       }
-       else if (PyType_Check(self)==0) {
-               return NULL;
+       /* ack, PyObject_GetAttrString wont look up this types tp_dict first :/ */
+       if(PyType_Check(self)) {
+               py_srna = (BPy_StructRNA *)PyDict_GetItemString(((PyTypeObject *)self)->tp_dict, "__rna__");
+               Py_XINCREF(py_srna);
        }
-       /* These cases above not errors, they just mean the type was not compatible
-        * After this any errors will be raised in the script */
-
        
-       py_srna= (BPy_StructRNA *)PyObject_GetAttrString(self, "__rna__");
+       if(py_srna==NULL)
+               py_srna = (BPy_StructRNA*)PyObject_GetAttrString(self, "__rna__");
 
        if(py_srna==NULL) {
                PyErr_SetString(PyExc_SystemError, "internal error, self had no __rna__ attribute, should never happen.");
@@ -2603,21 +2637,46 @@ static StructRNA *srna_from_self(PyObject *self)
        }
 
        if(!BPy_StructRNA_Check(py_srna)) {
-               PyErr_SetString(PyExc_SystemError, "internal error, self's __rna__ attribute isnt a StructRNA type, should never happen.");
+               PyErr_Format(PyExc_SystemError, "internal error, __rna__ was of type %.200s, instead of %.200s instance.", Py_TYPE(py_srna)->tp_name, pyrna_struct_Type.tp_name);
+               Py_DECREF(py_srna);
                return NULL;
        }
 
-       if((py_srna->ptr.data && py_srna->ptr.type == &RNA_Struct) == 0) {
-               PyErr_SetString(PyExc_SystemError, "internal error, self's __rna__ attribute wasnt an RNA_Struct, should never happen.");
+       if(py_srna->ptr.type != &RNA_Struct) {
+               PyErr_SetString(PyExc_SystemError, "internal error, __rna__ was not a RNA_Struct type of rna struct.");
+               Py_DECREF(py_srna);
                return NULL;
        }
 
-       if(!RNA_struct_is_ID(py_srna->ptr.data)) {
-               PyErr_SetString(PyExc_TypeError, "only ID types support python defined properties");
+       srna= py_srna->ptr.data;
+       Py_DECREF(py_srna);
+
+       return srna;
+}
+
+
+/* Orphan functions, not sure where they should go */
+/* get the srna for methods attached to types */
+/* */
+static StructRNA *srna_from_self(PyObject *self)
+{
+       /* a bit sloppy but would cause a very confusing bug if
+        * an error happened to be set here */
+       PyErr_Clear();
+       
+       if(self==NULL) {
                return NULL;
        }
+       else if (PyCObject_Check(self)) {
+               return PyCObject_AsVoidPtr(self);
+       }
+       else if (PyType_Check(self)==0) {
+               return NULL;
+       }
+       /* These cases above not errors, they just mean the type was not compatible
+        * After this any errors will be raised in the script */
 
-       return py_srna->ptr.data;
+       return pyrna_struct_as_srna(self);
 }
 
 /* operators use this so it can store the args given but defer running
@@ -2634,15 +2693,16 @@ static PyObject *bpy_prop_deferred_return(void *func, PyObject *kw)
 
 /* Function that sets RNA, NOTE - self is NULL when called from python, but being abused from C so we can pass the srna allong
  * This isnt incorrect since its a python object - but be careful */
-PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw)
+
+PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw)
 {
-       static char *kwlist[] = {"attr", "name", "description", "min", "max", "soft_min", "soft_max", "default", NULL};
+       static char *kwlist[] = {"attr", "name", "description", "default", NULL};
        char *id, *name="", *description="";
-       float min=FLT_MIN, max=FLT_MAX, soft_min=FLT_MIN, soft_max=FLT_MAX, def=0.0f;
+       int def=0;
        PropertyRNA *prop;
        StructRNA *srna;
 
-       if (!PyArg_ParseTupleAndKeywords(args, kw, "s|ssfffff:FloatProperty", kwlist, &id, &name, &description, &min, &max, &soft_min, &soft_max, &def))
+       if (!PyArg_ParseTupleAndKeywords(args, kw, "s|ssi:BoolProperty", kwlist, &id, &name, &description, &def))
                return NULL;
        
        if (PyTuple_Size(args) > 0) {
@@ -2655,12 +2715,12 @@ PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw)
                return NULL; /* self's type was compatible but error getting the srna */
        }
        else if(srna) {
-               prop= RNA_def_float(srna, id, def, min, max, name, description, soft_min, soft_max);
+               prop= RNA_def_boolean(srna, id, def, name, description);
                RNA_def_property_duplicate_pointers(prop);
                Py_RETURN_NONE;
        }
        else { /* operators defer running this function */
-               return bpy_prop_deferred_return((void *)BPy_FloatProperty, kw);
+               return bpy_prop_deferred_return((void *)BPy_BoolProperty, kw);
        }
 }
 
@@ -2694,15 +2754,15 @@ PyObject *BPy_IntProperty(PyObject *self, PyObject *args, PyObject *kw)
        }
 }
 
-PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw)
+PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw)
 {
-       static char *kwlist[] = {"attr", "name", "description", "default", NULL};
+       static char *kwlist[] = {"attr", "name", "description", "min", "max", "soft_min", "soft_max", "default", NULL};
        char *id, *name="", *description="";
-       int def=0;
+       float min=FLT_MIN, max=FLT_MAX, soft_min=FLT_MIN, soft_max=FLT_MAX, def=0.0f;
        PropertyRNA *prop;
        StructRNA *srna;
 
-       if (!PyArg_ParseTupleAndKeywords(args, kw, "s|ssi:BoolProperty", kwlist, &id, &name, &description, &def))
+       if (!PyArg_ParseTupleAndKeywords(args, kw, "s|ssfffff:FloatProperty", kwlist, &id, &name, &description, &min, &max, &soft_min, &soft_max, &def))
                return NULL;
        
        if (PyTuple_Size(args) > 0) {
@@ -2715,12 +2775,12 @@ PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw)
                return NULL; /* self's type was compatible but error getting the srna */
        }
        else if(srna) {
-               prop= RNA_def_boolean(srna, id, def, name, description);
+               prop= RNA_def_float(srna, id, def, min, max, name, description, soft_min, soft_max);
                RNA_def_property_duplicate_pointers(prop);
                Py_RETURN_NONE;
        }
        else { /* operators defer running this function */
-               return bpy_prop_deferred_return((void *)BPy_BoolProperty, kw);
+               return bpy_prop_deferred_return((void *)BPy_FloatProperty, kw);
        }
 }
 
@@ -2754,6 +2814,224 @@ PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw)
        }
 }
 
+static EnumPropertyItem *enum_items_from_py(PyObject *value, const char *def, int *defvalue)
+{
+       EnumPropertyItem *items= NULL;
+       PyObject *item;
+       int seq_len, i, totitem= 0;
+       
+       if(!PySequence_Check(value)) {
+               PyErr_SetString(PyExc_TypeError, "expected a sequence of tuples for the enum items");
+               return NULL;
+       }
+
+       seq_len = PySequence_Length(value);
+       for(i=0; i<seq_len; i++) {
+               EnumPropertyItem tmp= {0, "", 0, "", ""};
+
+               item= PySequence_GetItem(value, i);
+               if(item==NULL || PyTuple_Check(item)==0) {
+                       PyErr_SetString(PyExc_TypeError, "expected a sequence of tuples for the enum items");
+                       if(items) MEM_freeN(items);
+                       Py_XDECREF(item);
+                       return NULL;
+               }
+
+               if(!PyArg_ParseTuple(item, "sss", &tmp.identifier, &tmp.name, &tmp.description)) {
+                       PyErr_SetString(PyExc_TypeError, "expected an identifier, name and description in the tuple");
+                       Py_DECREF(item);
+                       return NULL;
+               }
+
+               tmp.value= i;
+               RNA_enum_item_add(&items, &totitem, &tmp);
+
+               if(def[0] && strcmp(def, tmp.identifier) == 0)
+                       *defvalue= tmp.value;
+
+               Py_DECREF(item);
+       }
+
+       if(!def[0])
+               *defvalue= 0;
+
+       RNA_enum_item_end(&items, &totitem);
+
+       return items;
+}
+
+PyObject *BPy_EnumProperty(PyObject *self, PyObject *args, PyObject *kw)
+{
+       static char *kwlist[] = {"attr", "items", "name", "description", "default", NULL};
+       char *id, *name="", *description="", *def="";
+       int defvalue=0;
+       PyObject *items= Py_None;
+       EnumPropertyItem *eitems;
+       PropertyRNA *prop;
+       StructRNA *srna;
+
+       if (!PyArg_ParseTupleAndKeywords(args, kw, "sO|sss:EnumProperty", kwlist, &id, &items, &name, &description, &def))
+               return NULL;
+       
+       if (PyTuple_Size(args) > 0) {
+               PyErr_SetString(PyExc_ValueError, "all args must be keywors"); // TODO - py3 can enforce this.
+               return NULL;
+       }
+       
+       srna= srna_from_self(self);
+       if(srna==NULL && PyErr_Occurred()) {
+               return NULL; /* self's type was compatible but error getting the srna */
+       }
+       else if(srna) {
+               eitems= enum_items_from_py(items, def, &defvalue);
+               if(!eitems)
+                       return NULL;
+                       
+               prop= RNA_def_enum(srna, id, eitems, defvalue, name, description);
+               RNA_def_property_duplicate_pointers(prop);
+               MEM_freeN(eitems);
+
+               Py_RETURN_NONE;
+       }
+       else { /* operators defer running this function */
+               return bpy_prop_deferred_return((void *)BPy_EnumProperty, kw);
+       }
+}
+
+static StructRNA *pointer_type_from_py(PyObject *value)
+{
+       StructRNA *srna;
+
+       srna= srna_from_self(value);
+       if(!srna) {
+               PyErr_SetString(PyExc_SystemError, "expected an RNA type derived from IDPropertyGroup");
+               return NULL;
+       }
+
+       if(!RNA_struct_is_a(srna, &RNA_IDPropertyGroup)) {
+               PyErr_SetString(PyExc_SystemError, "expected an RNA type derived from IDPropertyGroup");
+               return NULL;
+       }
+
+       return srna;
+}
+
+PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw)
+{
+       static char *kwlist[] = {"attr", "type", "name", "description", NULL};
+       char *id, *name="", *description="";
+       PropertyRNA *prop;
+       StructRNA *srna, *ptype;
+       PyObject *type= Py_None;
+
+       if (!PyArg_ParseTupleAndKeywords(args, kw, "sO|ss:PointerProperty", kwlist, &id, &type, &name, &description))
+               return NULL;
+       
+       if (PyTuple_Size(args) > 0) {
+               PyErr_SetString(PyExc_ValueError, "all args must be keywors"); // TODO - py3 can enforce this.
+               return NULL;
+       }
+
+       srna= srna_from_self(self);
+       if(srna==NULL && PyErr_Occurred()) {
+               return NULL; /* self's type was compatible but error getting the srna */
+       }
+       else if(srna) {
+               ptype= pointer_type_from_py(type);
+               if(!ptype)
+                       return NULL;
+
+               prop= RNA_def_pointer_runtime(srna, id, ptype, name, description);
+               RNA_def_property_duplicate_pointers(prop);
+               Py_RETURN_NONE;
+       }
+       else { /* operators defer running this function */
+               return bpy_prop_deferred_return((void *)BPy_PointerProperty, kw);
+       }
+       return NULL;
+}
+
+PyObject *BPy_CollectionProperty(PyObject *self, PyObject *args, PyObject *kw)
+{
+       static char *kwlist[] = {"attr", "type", "name", "description", NULL};
+       char *id, *name="", *description="";
+       PropertyRNA *prop;
+       StructRNA *srna, *ptype;
+       PyObject *type= Py_None;
+
+       if (!PyArg_ParseTupleAndKeywords(args, kw, "sO|ss:CollectionProperty", kwlist, &id, &type, &name, &description))
+               return NULL;
+       
+       if (PyTuple_Size(args) > 0) {
+               PyErr_SetString(PyExc_ValueError, "all args must be keywors"); // TODO - py3 can enforce this.
+               return NULL;
+       }
+
+       srna= srna_from_self(self);
+       if(srna==NULL && PyErr_Occurred()) {
+               return NULL; /* self's type was compatible but error getting the srna */
+       }
+       else if(srna) {
+               ptype= pointer_type_from_py(type);
+               if(!ptype)
+                       return NULL;
+
+               prop= RNA_def_collection_runtime(srna, id, ptype, name, description);
+               RNA_def_property_duplicate_pointers(prop);
+               Py_RETURN_NONE;
+       }
+       else { /* operators defer running this function */
+               return bpy_prop_deferred_return((void *)BPy_CollectionProperty, kw);
+       }
+       return NULL;
+}
+
+static int deferred_register_props(PyObject *py_class, StructRNA *srna)
+{
+       PyObject *props, *dummy_args, *item;
+       int i;
+
+       props= PyObject_GetAttrString(py_class, "__props__");
+       
+       if(!props) {
+               PyErr_Clear();
+               return 1;
+       }
+
+       dummy_args = PyTuple_New(0);
+
+       for(i=0; i<PyList_Size(props); i++) {
+               PyObject *py_func_ptr, *py_kw, *py_srna_cobject, *py_ret;
+               item = PyList_GET_ITEM(props, i);
+               
+               if(PyArg_ParseTuple(item, "O!O!", &PyCObject_Type, &py_func_ptr, &PyDict_Type, &py_kw)) {
+                       PyObject *(*pyfunc)(PyObject *, PyObject *, PyObject *);
+                       pyfunc = PyCObject_AsVoidPtr(py_func_ptr);
+                       py_srna_cobject = PyCObject_FromVoidPtr(srna, NULL);
+                       
+                       py_ret = pyfunc(py_srna_cobject, dummy_args, py_kw);
+                       Py_DECREF(py_srna_cobject);
+
+                       if(py_ret) {
+                               Py_DECREF(py_ret);
+                       }
+                       else {
+                               Py_DECREF(dummy_args);
+                               return 0;
+                       }
+               }
+               else {
+                       PyErr_Clear();
+                       PyErr_SetString(PyExc_AttributeError, "expected list of dicts for __props__.");
+                       Py_DECREF(dummy_args);
+                       return 0;
+               }
+       }
+
+       Py_DECREF(dummy_args);
+       return 1;
+}
+
 /*-------------------- Type Registration ------------------------*/
 
 static int rna_function_arg_count(FunctionRNA *func)
@@ -3005,6 +3283,28 @@ static void bpy_class_free(void *pyob_ptr)
        PyGILState_Release(gilstate);
 }
 
+void pyrna_alloc_types(void)
+{
+       PyGILState_STATE gilstate;
+
+       PointerRNA ptr;
+       PropertyRNA *prop;
+       
+       gilstate = PyGILState_Ensure();
+
+       /* avoid doing this lookup for every getattr */
+       RNA_blender_rna_pointer_create(&ptr);
+       prop = RNA_struct_find_property(&ptr, "structs");
+
+       RNA_PROP_BEGIN(&ptr, itemptr, prop) {
+               Py_DECREF(pyrna_struct_Subtype(&itemptr));
+       }
+       RNA_PROP_END;
+
+       PyGILState_Release(gilstate);
+}
+
+
 void pyrna_free_types(void)
 {
        PointerRNA ptr;
@@ -3029,43 +3329,32 @@ void pyrna_free_types(void)
        RNA_PROP_END;
 }
 
-PyObject *pyrna_basetype_register(PyObject *self, PyObject *args)
+/* Note! MemLeak XXX
+ *
+ * There is currently a bug where moving registering a python class does
+ * not properly manage refcounts from the python class, since the srna owns
+ * the python class this should not be so tricky but changing the references as
+ * youd expect when changing ownership crashes blender on exit so I had to comment out
+ * the decref. This is not so bad because the leak only happens when re-registering (hold F8)
+ * - Should still be fixed - Campbell
+ * */
+
+PyObject *pyrna_basetype_register(PyObject *self, PyObject *py_class)
 {
        bContext *C= NULL;
-       PyObject *py_class, *item;
        ReportList reports;
        StructRegisterFunc reg;
-       BPy_StructRNA *py_srna;
        StructRNA *srna;
+       StructRNA *srna_new;
+       PyObject *item;
+       const char *identifier= "";
 
-       if(!PyArg_ParseTuple(args, "O:register", &py_class))
-               return NULL;
-       
-       if(!PyType_Check(py_class)) {
-               PyErr_SetString(PyExc_AttributeError, "expected a Type subclassed from a registerable rna type (no a Type object).");
-               return NULL;
-       }
-
-       /* check we got an __rna__ attribute */
-       item= PyObject_GetAttrString(py_class, "__rna__");
-
-       if(!item || !BPy_StructRNA_Check(item)) {
-               Py_XDECREF(item);
-               PyErr_SetString(PyExc_AttributeError, "expected a Type subclassed from a registerable rna type (no __rna__ property).");
-               return NULL;
-       }
-
-       /* check the __rna__ attribute has the right type */
-       Py_DECREF(item);
-       py_srna= (BPy_StructRNA*)item;
-
-       if(py_srna->ptr.type != &RNA_Struct) {
-               PyErr_SetString(PyExc_AttributeError, "expected a Type subclassed from a registerable rna type (not a Struct).");
+       srna= pyrna_struct_as_srna(py_class);
+       if(srna==NULL)
                return NULL;
-       }
        
        /* check that we have a register callback for this type */
-       reg= RNA_struct_register(py_srna->ptr.data);
+       reg= RNA_struct_register(srna);
 
        if(!reg) {
                PyErr_SetString(PyExc_AttributeError, "expected a Type subclassed from a registerable rna type (no register supported).");
@@ -3075,11 +3364,19 @@ PyObject *pyrna_basetype_register(PyObject *self, PyObject *args)
        /* get the context, so register callback can do necessary refreshes */
        C= BPy_GetContext();
 
-       /* call the register callback */
+       /* call the register callback with reports & identifier */
        BKE_reports_init(&reports, RPT_STORE);
-       srna= reg(C, &reports, py_class, bpy_class_validate, bpy_class_call, bpy_class_free);
 
-       if(!srna) {
+       item= PyObject_GetAttrString(py_class, "__name__");
+
+       if(item) {
+               identifier= _PyUnicode_AsString(item);
+               Py_DECREF(item); /* no need to keep a ref, the class owns it */
+       }
+
+       srna_new= reg(C, &reports, py_class, identifier, bpy_class_validate, bpy_class_call, bpy_class_free);
+
+       if(!srna_new) {
                BPy_reports_to_error(&reports);
                BKE_reports_clear(&reports);
                return NULL;
@@ -3087,44 +3384,32 @@ PyObject *pyrna_basetype_register(PyObject *self, PyObject *args)
 
        BKE_reports_clear(&reports);
 
-       pyrna_subtype_set_rna(py_class, srna); /* takes a ref to py_class */
+       pyrna_subtype_set_rna(py_class, srna_new); /* takes a ref to py_class */
+
+       /* old srna still references us, keep the check incase registering somehow can free it  */
+       if(RNA_struct_py_type_get(srna)) {
+               RNA_struct_py_type_set(srna, NULL);
+               // Py_DECREF(py_class); // shuld be able to do this XXX since the old rna adds a new ref.
+       }
+
+       if(!deferred_register_props(py_class, srna_new))
+               return NULL;
 
        Py_RETURN_NONE;
 }
 
-PyObject *pyrna_basetype_unregister(PyObject *self, PyObject *args)
+PyObject *pyrna_basetype_unregister(PyObject *self, PyObject *py_class)
 {
        bContext *C= NULL;
-       PyObject *py_class, *item;
-       BPy_StructRNA *py_srna;
        StructUnregisterFunc unreg;
+       StructRNA *srna;
 
-       if(!PyArg_ParseTuple(args, "O:unregister", &py_class))
-               return NULL;
-
-       if(!PyType_Check(py_class)) {
-               PyErr_SetString(PyExc_AttributeError, "expected a Type subclassed from a registerable rna type (no a Type object).");
-               return NULL;
-       }
-
-       /* check we got an __rna__ attribute */
-       item= PyDict_GetItemString(((PyTypeObject*)py_class)->tp_dict, "__rna__");  /* borrow ref */
-
-       if(!item || !BPy_StructRNA_Check(item)) {
-               PyErr_SetString(PyExc_AttributeError, "expected a Type subclassed from a registerable rna type (no __rna__ property).");
-               return NULL;
-       }
-
-       /* check the __rna__ attribute has the right type */
-       py_srna= (BPy_StructRNA*)item;
-
-       if(py_srna->ptr.type != &RNA_Struct) {
-               PyErr_SetString(PyExc_AttributeError, "expected a Type subclassed from a registerable rna type (not a Struct).");
+       srna= pyrna_struct_as_srna(py_class);
+       if(srna==NULL)
                return NULL;
-       }
        
        /* check that we have a unregister callback for this type */
-       unreg= RNA_struct_unregister(py_srna->ptr.data);
+       unreg= RNA_struct_unregister(srna);
 
        if(!unreg) {
                PyErr_SetString(PyExc_AttributeError, "expected a Type subclassed from a registerable rna type (no unregister supported).");
@@ -3133,13 +3418,9 @@ PyObject *pyrna_basetype_unregister(PyObject *self, PyObject *args)
        
        /* get the context, so register callback can do necessary refreshes */
        C= BPy_GetContext();
-       
 
        /* call unregister */
-       unreg(C, py_srna->ptr.data);
-
-       /* remove reference to old type */
-       Py_DECREF(py_class);
+       unreg(C, srna); /* calls bpy_class_free, this decref's py_class */
 
        Py_RETURN_NONE;
 }