Blender V2.61 - r43446

idprop_py_api.c

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  *
00019  * Contributor(s): Joseph Eagar, Campbell Barton
00020  *
00021  * ***** END GPL LICENSE BLOCK *****
00022  */
00023 
00029 #include <Python.h>
00030 
00031 #include "idprop_py_api.h"
00032 #include "MEM_guardedalloc.h"
00033 
00034 #include "BLI_string.h"
00035 #include "BLI_utildefines.h"
00036 
00037 #include "BKE_idprop.h"
00038 
00039 
00040 #define USE_STRING_COERCE
00041 
00042 #ifdef USE_STRING_COERCE
00043 #include "py_capi_utils.h"
00044 #endif
00045 
00046 extern PyTypeObject BPy_IDArray_Type;
00047 extern PyTypeObject BPy_IDGroup_Iter_Type;
00048 extern PyTypeObject BPy_IDGroup_Type;
00049 
00050 /*********************** ID Property Main Wrapper Stuff ***************/
00051 
00052 /* ----------------------------------------------------------------------------
00053  * static conversion functions to avoid duplicate code, no type checking.
00054  */
00055 
00056 static PyObject *idprop_py_from_idp_string(IDProperty *prop)
00057 {
00058     if (prop->subtype == IDP_STRING_SUB_BYTE) {
00059         return PyBytes_FromStringAndSize(IDP_Array(prop), prop->len);
00060     }
00061     else {
00062 #ifdef USE_STRING_COERCE
00063         return PyC_UnicodeFromByteAndSize(IDP_Array(prop), prop->len - 1);
00064 #else
00065         return PyUnicode_FromStringAndSize(IDP_Array(prop), prop->len - 1);
00066 #endif
00067     }
00068 }
00069 
00070 static PyObject *idprop_py_from_idp_int(IDProperty *prop)
00071 {
00072     return PyLong_FromLong((long)prop->data.val);
00073 }
00074 
00075 static PyObject *idprop_py_from_idp_float(IDProperty *prop)
00076 {
00077     return PyFloat_FromDouble((double)(*(float*)(&prop->data.val)));
00078 }
00079 
00080 static PyObject *idprop_py_from_idp_double(IDProperty *prop)
00081 {
00082     return PyFloat_FromDouble((*(double*)(&prop->data.val)));
00083 }
00084 
00085 static PyObject *idprop_py_from_idp_group(ID *id, IDProperty *prop, IDProperty *parent)
00086 {
00087     BPy_IDProperty *group= PyObject_New(BPy_IDProperty, &BPy_IDGroup_Type);
00088     group->id = id;
00089     group->prop = prop;
00090     group->parent = parent; /* can be NULL */
00091     return (PyObject*) group;
00092 }
00093 
00094 static PyObject *idprop_py_from_idp_array(ID *id, IDProperty *prop)
00095 {
00096     BPy_IDProperty *array = PyObject_New(BPy_IDProperty, &BPy_IDArray_Type);
00097     array->id = id;
00098     array->prop = prop;
00099     return (PyObject*) array;
00100 }
00101 
00102 static PyObject *idprop_py_from_idp_idparray(ID *id, IDProperty *prop)
00103 {
00104     PyObject *seq = PyList_New(prop->len), *wrap;
00105     IDProperty *array= IDP_IDPArray(prop);
00106     int i;
00107 
00108     if (!seq) {
00109         PyErr_Format(PyExc_RuntimeError,
00110                      "%s: IDP_IDPARRAY: PyList_New(%d) failed",
00111                      __func__, prop->len);
00112         return NULL;
00113     }
00114 
00115     for (i=0; i<prop->len; i++) {
00116         wrap= BPy_IDGroup_WrapData(id, array++, prop);
00117 
00118         if (!wrap) /* BPy_IDGroup_MapDataToPy sets the error */
00119             return NULL;
00120 
00121         PyList_SET_ITEM(seq, i, wrap);
00122     }
00123 
00124     return seq;
00125 }
00126 
00127 /* -------------------------------------------------------------------------- */
00128 
00129 /* use for both array and group */
00130 static long BPy_IDGroup_hash(BPy_IDProperty *self)
00131 {
00132     return _Py_HashPointer(self->prop);
00133 }
00134 
00135 static PyObject *BPy_IDGroup_repr(BPy_IDProperty *self)
00136 {
00137     return PyUnicode_FromFormat( "<bpy id property from \"%s\">", self->id->name);
00138 }
00139 
00140 PyObject *BPy_IDGroup_WrapData(ID *id, IDProperty *prop, IDProperty *parent)
00141 {
00142     switch (prop->type) {
00143     case IDP_STRING:
00144         return idprop_py_from_idp_string(prop);
00145     case IDP_INT:
00146         return idprop_py_from_idp_int(prop);
00147     case IDP_FLOAT:
00148         return idprop_py_from_idp_float(prop);
00149     case IDP_DOUBLE:
00150         return idprop_py_from_idp_double(prop);
00151     case IDP_GROUP:
00152         return idprop_py_from_idp_group(id, prop, parent);
00153     case IDP_ARRAY:
00154         return idprop_py_from_idp_array(id, prop);
00155     case IDP_IDPARRAY: /* this could be better a internal type */
00156         return idprop_py_from_idp_idparray(id, prop);
00157     default:
00158         Py_RETURN_NONE;
00159     }
00160 }
00161 
00162 #if 0 /* UNUSED, currenly assignment overwrites into new properties, rather than setting in-place */
00163 static int BPy_IDGroup_SetData(BPy_IDProperty *self, IDProperty *prop, PyObject *value)
00164 {
00165     switch (prop->type) {
00166         case IDP_STRING:
00167         {
00168             char *st;
00169             if (!PyUnicode_Check(value)) {
00170                 PyErr_SetString(PyExc_TypeError, "expected a string!");
00171                 return -1;
00172             }
00173             /* NOTE: if this code is enabled, bytes support needs to be added */
00174 #ifdef USE_STRING_COERCE
00175             {
00176                 int alloc_len;
00177                 PyObject *value_coerce= NULL;
00178 
00179                 st= (char *)PyC_UnicodeAsByte(value, &value_coerce);
00180                 alloc_len= strlen(st) + 1;
00181 
00182                 st = _PyUnicode_AsString(value);
00183                 IDP_ResizeArray(prop, alloc_len);
00184                 memcpy(IDP_Array(prop), st, alloc_len);
00185                 Py_XDECREF(value_coerce);
00186             }
00187 #else
00188             st = _PyUnicode_AsString(value);
00189             IDP_ResizeArray(prop, strlen(st)+1);
00190             strcpy(IDP_Array(prop), st);
00191 #endif
00192 
00193             return 0;
00194         }
00195 
00196         case IDP_INT:
00197         {
00198             int ivalue= PyLong_AsSsize_t(value);
00199             if (ivalue==-1 && PyErr_Occurred()) {
00200                 PyErr_SetString(PyExc_TypeError, "expected an int type");
00201                 return -1;
00202             }
00203             prop->data.val = ivalue;
00204             break;
00205         }
00206         case IDP_FLOAT:
00207         {
00208             float fvalue= (float)PyFloat_AsDouble(value);
00209             if (fvalue==-1 && PyErr_Occurred()) {
00210                 PyErr_SetString(PyExc_TypeError, "expected a float");
00211                 return -1;
00212             }
00213             *(float*)&self->prop->data.val = fvalue;
00214             break;
00215         }
00216         case IDP_DOUBLE:
00217         {
00218             double dvalue= PyFloat_AsDouble(value);
00219             if (dvalue==-1 && PyErr_Occurred()) {
00220                 PyErr_SetString(PyExc_TypeError, "expected a float");
00221                 return -1;
00222             }
00223             *(double*)&self->prop->data.val = dvalue;
00224             break;
00225         }
00226         default:
00227             PyErr_SetString(PyExc_AttributeError, "attempt to set read-only attribute!");
00228             return -1;
00229     }
00230     return 0;
00231 }
00232 #endif
00233 
00234 static PyObject *BPy_IDGroup_GetName(BPy_IDProperty *self, void *UNUSED(closure))
00235 {
00236     return PyUnicode_FromString(self->prop->name);
00237 }
00238 
00239 static int BPy_IDGroup_SetName(BPy_IDProperty *self, PyObject *value, void *UNUSED(closure))
00240 {
00241     const char *name;
00242     Py_ssize_t name_size;
00243 
00244     if (!PyUnicode_Check(value)) {
00245         PyErr_SetString(PyExc_TypeError, "expected a string!");
00246         return -1;
00247     }
00248 
00249     name = _PyUnicode_AsStringAndSize(value, &name_size);
00250 
00251     if (name_size > MAX_IDPROP_NAME) {
00252         PyErr_SetString(PyExc_TypeError, "string length cannot exceed 63 characters!");
00253         return -1;
00254     }
00255 
00256     memcpy(self->prop->name, name, name_size);
00257     return 0;
00258 }
00259 
00260 #if 0
00261 static PyObject *BPy_IDGroup_GetType(BPy_IDProperty *self)
00262 {
00263     return PyLong_FromSsize_t(self->prop->type);
00264 }
00265 #endif
00266 
00267 static PyGetSetDef BPy_IDGroup_getseters[] = {
00268     {(char *)"name", (getter)BPy_IDGroup_GetName, (setter)BPy_IDGroup_SetName, (char *)"The name of this Group.", NULL},
00269      {NULL, NULL, NULL, NULL, NULL}
00270 };
00271 
00272 static Py_ssize_t BPy_IDGroup_Map_Len(BPy_IDProperty *self)
00273 {
00274     if (self->prop->type != IDP_GROUP) {
00275         PyErr_SetString(PyExc_TypeError, "len() of unsized object");
00276         return -1;
00277     }
00278 
00279     return self->prop->len;
00280 }
00281 
00282 static PyObject *BPy_IDGroup_Map_GetItem(BPy_IDProperty *self, PyObject *item)
00283 {
00284     IDProperty *idprop;
00285     const char *name;
00286 
00287     if (self->prop->type  != IDP_GROUP) {
00288         PyErr_SetString(PyExc_TypeError, "unsubscriptable object");
00289         return NULL;
00290     }
00291 
00292     name= _PyUnicode_AsString(item);
00293 
00294     if (name == NULL) {
00295         PyErr_SetString(PyExc_TypeError, "only strings are allowed as keys of ID properties");
00296         return NULL;
00297     }
00298 
00299     idprop= IDP_GetPropertyFromGroup(self->prop, name);
00300 
00301     if (idprop==NULL) {
00302         PyErr_SetString(PyExc_KeyError, "key not in subgroup dict");
00303         return NULL;
00304     }
00305 
00306     return BPy_IDGroup_WrapData(self->id, idprop, self->prop);
00307 }
00308 
00309 /*returns NULL on success, error string on failure*/
00310 static int idp_sequence_type(PyObject *seq)
00311 {
00312     PyObject *item;
00313     int type= IDP_INT;
00314 
00315     Py_ssize_t i, len = PySequence_Size(seq);
00316     for (i=0; i < len; i++) {
00317         item = PySequence_GetItem(seq, i);
00318         if (PyFloat_Check(item)) {
00319             if (type == IDP_IDPARRAY) { /* mixed dict/int */
00320                 Py_DECREF(item);
00321                 return -1;
00322             }
00323             type= IDP_DOUBLE;
00324         }
00325         else if (PyLong_Check(item)) {
00326             if (type == IDP_IDPARRAY) { /* mixed dict/int */
00327                 Py_DECREF(item);
00328                 return -1;
00329             }
00330         }
00331         else if (PyMapping_Check(item)) {
00332             if (i != 0 && (type != IDP_IDPARRAY)) { /* mixed dict/int */
00333                 Py_DECREF(item);
00334                 return -1;
00335             }
00336             type= IDP_IDPARRAY;
00337         }
00338         else {
00339             Py_XDECREF(item);
00340             return -1;
00341         }
00342 
00343         Py_DECREF(item);
00344     }
00345 
00346     return type;
00347 }
00348 
00349 /* note: group can be a pointer array or a group.
00350  * assume we already checked key is a string. */
00351 const char *BPy_IDProperty_Map_ValidateAndCreate(PyObject *name_obj, IDProperty *group, PyObject *ob)
00352 {
00353     IDProperty *prop = NULL;
00354     IDPropertyTemplate val = {0};
00355 
00356     const char *name= "";
00357 
00358     if (name_obj) {
00359         Py_ssize_t name_size;
00360         name = _PyUnicode_AsStringAndSize(name_obj, &name_size);
00361         if (name_size > MAX_IDPROP_NAME) {
00362             return "the length of IDProperty names is limited to 63 characters";
00363         }
00364     }
00365 
00366     if (PyFloat_Check(ob)) {
00367         val.d = PyFloat_AsDouble(ob);
00368         prop = IDP_New(IDP_DOUBLE, &val, name);
00369     }
00370     else if (PyLong_Check(ob)) {
00371         val.i = (int) PyLong_AsSsize_t(ob);
00372         prop = IDP_New(IDP_INT, &val, name);
00373     }
00374     else if (PyUnicode_Check(ob)) {
00375 #ifdef USE_STRING_COERCE
00376         PyObject *value_coerce= NULL;
00377         val.string.str = (char *)PyC_UnicodeAsByte(ob, &value_coerce);
00378         val.string.subtype = IDP_STRING_SUB_UTF8;
00379         prop = IDP_New(IDP_STRING, &val, name);
00380         Py_XDECREF(value_coerce);
00381 #else
00382         val.str = _PyUnicode_AsString(ob);
00383         prop = IDP_New(IDP_STRING, val, name);
00384 #endif
00385     }
00386     else if (PyBytes_Check(ob)) {
00387         val.string.str= PyBytes_AS_STRING(ob);
00388         val.string.len= PyBytes_GET_SIZE(ob);
00389         val.string.subtype= IDP_STRING_SUB_BYTE;
00390 
00391         prop = IDP_New(IDP_STRING, &val, name);
00392         //prop = IDP_NewString(PyBytes_AS_STRING(ob), name, PyBytes_GET_SIZE(ob));
00393         //prop->subtype= IDP_STRING_SUB_BYTE;
00394     }
00395     else if (PySequence_Check(ob)) {
00396         PyObject *item;
00397         int i;
00398 
00399         if ((val.array.type= idp_sequence_type(ob)) == -1)
00400             return "only floats, ints and dicts are allowed in ID property arrays";
00401 
00402         /*validate sequence and derive type.
00403         we assume IDP_INT unless we hit a float
00404         number; then we assume it's */
00405 
00406         val.array.len = PySequence_Size(ob);
00407 
00408         switch (val.array.type) {
00409         case IDP_DOUBLE:
00410             prop = IDP_New(IDP_ARRAY, &val, name);
00411             for (i=0; i<val.array.len; i++) {
00412                 item = PySequence_GetItem(ob, i);
00413                 ((double*)IDP_Array(prop))[i] = (float)PyFloat_AsDouble(item);
00414                 Py_DECREF(item);
00415             }
00416             break;
00417         case IDP_INT:
00418             prop = IDP_New(IDP_ARRAY, &val, name);
00419             for (i=0; i<val.array.len; i++) {
00420                 item = PySequence_GetItem(ob, i);
00421                 ((int*)IDP_Array(prop))[i] = (int)PyLong_AsSsize_t(item);
00422                 Py_DECREF(item);
00423             }
00424             break;
00425         case IDP_IDPARRAY:
00426             prop= IDP_NewIDPArray(name);
00427             for (i=0; i<val.array.len; i++) {
00428                 const char *error;
00429                 item = PySequence_GetItem(ob, i);
00430                 error= BPy_IDProperty_Map_ValidateAndCreate(NULL, prop, item);
00431                 Py_DECREF(item);
00432 
00433                 if (error)
00434                     return error;
00435             }
00436             break;
00437         }
00438     }
00439     else if (PyMapping_Check(ob)) {
00440         PyObject *keys, *vals, *key, *pval;
00441         int i, len;
00442         /*yay! we get into recursive stuff now!*/
00443         keys = PyMapping_Keys(ob);
00444         vals = PyMapping_Values(ob);
00445 
00446         /*we allocate the group first; if we hit any invalid data,
00447           we can delete it easily enough.*/
00448         prop = IDP_New(IDP_GROUP, &val, name);
00449         len = PyMapping_Length(ob);
00450         for (i=0; i<len; i++) {
00451             key = PySequence_GetItem(keys, i);
00452             pval = PySequence_GetItem(vals, i);
00453             if (!PyUnicode_Check(key)) {
00454                 IDP_FreeProperty(prop);
00455                 MEM_freeN(prop);
00456                 Py_XDECREF(keys);
00457                 Py_XDECREF(vals);
00458                 Py_XDECREF(key);
00459                 Py_XDECREF(pval);
00460                 return "invalid element in subgroup dict template!";
00461             }
00462             if (BPy_IDProperty_Map_ValidateAndCreate(key, prop, pval)) {
00463                 IDP_FreeProperty(prop);
00464                 MEM_freeN(prop);
00465                 Py_XDECREF(keys);
00466                 Py_XDECREF(vals);
00467                 Py_XDECREF(key);
00468                 Py_XDECREF(pval);
00469                 return "invalid element in subgroup dict template!";
00470             }
00471             Py_XDECREF(key);
00472             Py_XDECREF(pval);
00473         }
00474         Py_XDECREF(keys);
00475         Py_XDECREF(vals);
00476     }
00477     else return "invalid property value";
00478 
00479     if (group->type==IDP_IDPARRAY) {
00480         IDP_AppendArray(group, prop);
00481         // IDP_FreeProperty(item); // IDP_AppendArray does a shallow copy (memcpy), only free memory
00482         MEM_freeN(prop);
00483     }
00484     else {
00485         IDP_ReplaceInGroup(group, prop);
00486     }
00487 
00488     return NULL;
00489 }
00490 
00491 int BPy_Wrap_SetMapItem(IDProperty *prop, PyObject *key, PyObject *val)
00492 {
00493     if (prop->type  != IDP_GROUP) {
00494         PyErr_SetString(PyExc_TypeError, "unsubscriptable object");
00495         return -1;
00496     }
00497 
00498     if (val == NULL) { /* del idprop[key] */
00499         IDProperty *pkey = IDP_GetPropertyFromGroup(prop, _PyUnicode_AsString(key));
00500         if (pkey) {
00501             IDP_RemFromGroup(prop, pkey);
00502             IDP_FreeProperty(pkey);
00503             MEM_freeN(pkey);
00504             return 0;
00505         }
00506         else {
00507             PyErr_SetString(PyExc_KeyError, "property not found in group");
00508             return -1;
00509         }
00510     }
00511     else {
00512         const char *err;
00513 
00514         if (!PyUnicode_Check(key)) {
00515             PyErr_SetString(PyExc_TypeError, "only strings are allowed as subgroup keys");
00516             return -1;
00517         }
00518 
00519         err = BPy_IDProperty_Map_ValidateAndCreate(key, prop, val);
00520         if (err) {
00521             PyErr_SetString(PyExc_KeyError, err );
00522             return -1;
00523         }
00524 
00525         return 0;
00526     }
00527 }
00528 
00529 static int BPy_IDGroup_Map_SetItem(BPy_IDProperty *self, PyObject *key, PyObject *val)
00530 {
00531     return BPy_Wrap_SetMapItem(self->prop, key, val);
00532 }
00533 
00534 static PyObject *BPy_IDGroup_iter(BPy_IDProperty *self)
00535 {
00536     BPy_IDGroup_Iter *iter = PyObject_New(BPy_IDGroup_Iter, &BPy_IDGroup_Iter_Type);
00537     iter->group = self;
00538     iter->mode = IDPROP_ITER_KEYS;
00539     iter->cur = self->prop->data.group.first;
00540     Py_XINCREF(iter);
00541     return (PyObject*) iter;
00542 }
00543 
00544 /* for simple, non nested types this is the same as BPy_IDGroup_WrapData */
00545 static PyObject *BPy_IDGroup_MapDataToPy(IDProperty *prop)
00546 {
00547     switch (prop->type) {
00548     case IDP_STRING:
00549         return idprop_py_from_idp_string(prop);
00550     case IDP_INT:
00551         return idprop_py_from_idp_int(prop);
00552     case IDP_FLOAT:
00553         return idprop_py_from_idp_float(prop);
00554     case IDP_DOUBLE:
00555         return idprop_py_from_idp_double(prop);
00556     case IDP_ARRAY:
00557     {
00558         PyObject *seq = PyList_New(prop->len);
00559         int i;
00560 
00561         if (!seq) {
00562             PyErr_Format(PyExc_RuntimeError,
00563                          "%s: IDP_ARRAY: PyList_New(%d) failed",
00564                          __func__, prop->len);
00565             return NULL;
00566         }
00567 
00568         switch (prop->subtype) {
00569         case IDP_FLOAT:
00570         {
00571             float *array= (float*)IDP_Array(prop);
00572             for (i=0; i<prop->len; i++) {
00573                 PyList_SET_ITEM(seq, i, PyFloat_FromDouble(array[i]));
00574             }
00575             break;
00576         }
00577         case IDP_DOUBLE:
00578         {
00579             double *array= (double*)IDP_Array(prop);
00580             for (i=0; i<prop->len; i++) {
00581                 PyList_SET_ITEM(seq, i, PyFloat_FromDouble(array[i]));
00582             }
00583             break;
00584         }
00585         case IDP_INT:
00586         {
00587             int *array= (int*)IDP_Array(prop);
00588             for (i=0; i<prop->len; i++) {
00589                 PyList_SET_ITEM(seq, i, PyLong_FromLong(array[i]));
00590             }
00591             break;
00592         }
00593         default:
00594             PyErr_Format(PyExc_RuntimeError,
00595                          "%s: invalid/corrupt array type '%d'!",
00596                          __func__, prop->subtype);
00597             Py_DECREF(seq);
00598             return NULL;
00599         }
00600 
00601         return seq;
00602     }
00603     case IDP_IDPARRAY:
00604     {
00605         PyObject *seq = PyList_New(prop->len), *wrap;
00606         IDProperty *array= IDP_IDPArray(prop);
00607         int i;
00608 
00609         if (!seq) {
00610             PyErr_Format(PyExc_RuntimeError,
00611                          "%s: IDP_IDPARRAY: PyList_New(%d) failed",
00612                          __func__, prop->len);
00613             return NULL;
00614         }
00615 
00616         for (i=0; i<prop->len; i++) {
00617             wrap= BPy_IDGroup_MapDataToPy(array++);
00618 
00619             if (!wrap) /* BPy_IDGroup_MapDataToPy sets the error */
00620                 return NULL;
00621 
00622             PyList_SET_ITEM(seq, i, wrap);
00623         }
00624         return seq;
00625     }
00626     case IDP_GROUP:
00627     {
00628         PyObject *dict = PyDict_New(), *wrap;
00629         IDProperty *loop;
00630 
00631         for (loop=prop->data.group.first; loop; loop=loop->next) {
00632             wrap = BPy_IDGroup_MapDataToPy(loop);
00633 
00634             if (!wrap) /* BPy_IDGroup_MapDataToPy sets the error */
00635                 return NULL;
00636 
00637             PyDict_SetItemString(dict, loop->name, wrap);
00638             Py_DECREF(wrap);
00639         }
00640         return dict;
00641     }
00642     }
00643 
00644     PyErr_Format(PyExc_RuntimeError,
00645                  "%s ERROR: '%s' property exists with a bad type code '%d'!",
00646                  __func__, prop->name, prop->type);
00647     return NULL;
00648 }
00649 
00650 static PyObject *BPy_IDGroup_Pop(BPy_IDProperty *self, PyObject *value)
00651 {
00652     IDProperty *idprop;
00653     PyObject *pyform;
00654     const char *name = _PyUnicode_AsString(value);
00655 
00656     if (!name) {
00657         PyErr_Format(PyExc_TypeError,
00658                      "pop expected at least a string argument, not %.200s",
00659                      Py_TYPE(value)->tp_name);
00660         return NULL;
00661     }
00662 
00663     idprop= IDP_GetPropertyFromGroup(self->prop, name);
00664 
00665     if (idprop) {
00666         pyform = BPy_IDGroup_MapDataToPy(idprop);
00667 
00668         if (!pyform) {
00669             /*ok something bad happened with the pyobject,
00670               so don't remove the prop from the group.  if pyform is
00671               NULL, then it already should have raised an exception.*/
00672             return NULL;
00673         }
00674 
00675         IDP_RemFromGroup(self->prop, idprop);
00676         return pyform;
00677     }
00678 
00679     PyErr_SetString(PyExc_KeyError, "item not in group");
00680     return NULL;
00681 }
00682 
00683 static PyObject *BPy_IDGroup_IterItems(BPy_IDProperty *self)
00684 {
00685     BPy_IDGroup_Iter *iter = PyObject_New(BPy_IDGroup_Iter, &BPy_IDGroup_Iter_Type);
00686     iter->group = self;
00687     iter->mode = IDPROP_ITER_ITEMS;
00688     iter->cur = self->prop->data.group.first;
00689     Py_XINCREF(iter);
00690     return (PyObject*) iter;
00691 }
00692 
00693 /* utility function */
00694 static void BPy_IDGroup_CorrectListLen(IDProperty *prop, PyObject *seq, int len, const char *func)
00695 {
00696     int j;
00697 
00698     printf("%s: ID Property Error found and corrected!\n", func);
00699 
00700     /*fill rest of list with valid references to None*/
00701     for (j=len; j<prop->len; j++) {
00702         Py_INCREF(Py_None);
00703         PyList_SET_ITEM(seq, j, Py_None);
00704     }
00705 
00706     /*set correct group length*/
00707     prop->len = len;
00708 }
00709 
00710 PyObject *BPy_Wrap_GetKeys(IDProperty *prop)
00711 {
00712     PyObject *list = PyList_New(prop->len);
00713     IDProperty *loop;
00714     int i;
00715 
00716     for (i=0, loop=prop->data.group.first; loop && (i < prop->len); loop=loop->next, i++)
00717         PyList_SET_ITEM(list, i, PyUnicode_FromString(loop->name));
00718 
00719     /* if the id prop is corrupt, count the remaining */
00720     for (; loop; loop=loop->next, i++) {}
00721 
00722     if (i != prop->len) { /* if the loop didnt finish, we know the length is wrong */
00723         BPy_IDGroup_CorrectListLen(prop, list, i, __func__);
00724         Py_DECREF(list); /*free the list*/
00725         /*call self again*/
00726         return BPy_Wrap_GetKeys(prop);
00727     }
00728 
00729     return list;
00730 }
00731 
00732 PyObject *BPy_Wrap_GetValues(ID *id, IDProperty *prop)
00733 {
00734     PyObject *list = PyList_New(prop->len);
00735     IDProperty *loop;
00736     int i;
00737 
00738     for (i=0, loop=prop->data.group.first; loop; loop=loop->next, i++) {
00739         PyList_SET_ITEM(list, i, BPy_IDGroup_WrapData(id, loop, prop));
00740     }
00741 
00742     if (i != prop->len) {
00743         BPy_IDGroup_CorrectListLen(prop, list, i, __func__);
00744         Py_DECREF(list); /*free the list*/
00745         /*call self again*/
00746         return BPy_Wrap_GetValues(id, prop);
00747     }
00748 
00749     return list;
00750 }
00751 
00752 PyObject *BPy_Wrap_GetItems(ID *id, IDProperty *prop)
00753 {
00754     PyObject *seq = PyList_New(prop->len);
00755     IDProperty *loop;
00756     int i;
00757 
00758     for (i=0, loop=prop->data.group.first; loop; loop=loop->next, i++) {
00759         PyObject *item= PyTuple_New(2);
00760         PyTuple_SET_ITEM(item, 0, PyUnicode_FromString(loop->name));
00761         PyTuple_SET_ITEM(item, 1, BPy_IDGroup_WrapData(id, loop, prop));
00762         PyList_SET_ITEM(seq, i, item);
00763     }
00764 
00765     if (i != prop->len) {
00766         BPy_IDGroup_CorrectListLen(prop, seq, i, __func__);
00767         Py_DECREF(seq); /*free the list*/
00768         /*call self again*/
00769         return BPy_Wrap_GetItems(id, prop);
00770     }
00771 
00772     return seq;
00773 }
00774 
00775 
00776 static PyObject *BPy_IDGroup_GetKeys(BPy_IDProperty *self)
00777 {
00778     return BPy_Wrap_GetKeys(self->prop);
00779 }
00780 
00781 static PyObject *BPy_IDGroup_GetValues(BPy_IDProperty *self)
00782 {
00783     return BPy_Wrap_GetValues(self->id, self->prop);
00784 }
00785 
00786 static PyObject *BPy_IDGroup_GetItems(BPy_IDProperty *self)
00787 {
00788     return BPy_Wrap_GetItems(self->id, self->prop);
00789 }
00790 
00791 static int BPy_IDGroup_Contains(BPy_IDProperty *self, PyObject *value)
00792 {
00793     const char *name = _PyUnicode_AsString(value);
00794 
00795     if (!name) {
00796         PyErr_Format(PyExc_TypeError,
00797                      "expected a string, not a %.200s",
00798                      Py_TYPE(value)->tp_name);
00799         return -1;
00800     }
00801 
00802     return IDP_GetPropertyFromGroup(self->prop, name) ? 1:0;
00803 }
00804 
00805 static PyObject *BPy_IDGroup_Update(BPy_IDProperty *self, PyObject *value)
00806 {
00807     PyObject *pkey, *pval;
00808     Py_ssize_t i=0;
00809 
00810     if (!PyDict_Check(value)) {
00811         PyErr_Format(PyExc_TypeError,
00812                      "expected a dict not a %.200s",
00813                      Py_TYPE(value)->tp_name);
00814         return NULL;
00815     }
00816 
00817     while (PyDict_Next(value, &i, &pkey, &pval)) {
00818         BPy_IDGroup_Map_SetItem(self, pkey, pval);
00819         if (PyErr_Occurred()) return NULL;
00820     }
00821 
00822     Py_RETURN_NONE;
00823 }
00824 
00825 static PyObject *BPy_IDGroup_to_dict(BPy_IDProperty *self)
00826 {
00827     return BPy_IDGroup_MapDataToPy(self->prop);
00828 }
00829 
00830 
00831 /* Matches python dict.get(key, [default]) */
00832 static PyObject* BPy_IDGroup_Get(BPy_IDProperty *self, PyObject *args)
00833 {
00834     IDProperty *idprop;
00835     char *key;
00836     PyObject* def = Py_None;
00837 
00838     if (!PyArg_ParseTuple(args, "s|O:get", &key, &def))
00839         return NULL;
00840 
00841     idprop= IDP_GetPropertyFromGroup(self->prop, key);
00842     if (idprop) {
00843         PyObject* pyobj = BPy_IDGroup_WrapData(self->id, idprop, self->prop);
00844         if (pyobj)
00845             return pyobj;
00846     }
00847 
00848     Py_INCREF(def);
00849     return def;
00850 }
00851 
00852 static struct PyMethodDef BPy_IDGroup_methods[] = {
00853     {"pop", (PyCFunction)BPy_IDGroup_Pop, METH_O,
00854         "pop an item from the group; raises KeyError if the item doesn't exist"},
00855     {"iteritems", (PyCFunction)BPy_IDGroup_IterItems, METH_NOARGS,
00856         "iterate through the items in the dict; behaves like dictionary method iteritems"},
00857     {"keys", (PyCFunction)BPy_IDGroup_GetKeys, METH_NOARGS,
00858         "get the keys associated with this group as a list of strings"},
00859     {"values", (PyCFunction)BPy_IDGroup_GetValues, METH_NOARGS,
00860         "get the values associated with this group"},
00861     {"items", (PyCFunction)BPy_IDGroup_GetItems, METH_NOARGS,
00862         "get the items associated with this group"},
00863     {"update", (PyCFunction)BPy_IDGroup_Update, METH_O,
00864         "updates the values in the group with the values of another or a dict"},
00865     {"get", (PyCFunction)BPy_IDGroup_Get, METH_VARARGS,
00866         "idprop.get(k[,d]) -> idprop[k] if k in idprop, else d.  d defaults to None"},
00867     {"to_dict", (PyCFunction)BPy_IDGroup_to_dict, METH_NOARGS,
00868         "return a purely python version of the group"},
00869     {NULL, NULL, 0, NULL}
00870 };
00871 
00872 static PySequenceMethods BPy_IDGroup_Seq = {
00873     (lenfunc) BPy_IDGroup_Map_Len,      /* lenfunc sq_length */
00874     NULL,                               /* binaryfunc sq_concat */
00875     NULL,                               /* ssizeargfunc sq_repeat */
00876     NULL,                               /* ssizeargfunc sq_item */ /* TODO - setting this will allow PySequence_Check to return True */
00877     NULL,                               /* intintargfunc ***was_sq_slice*** */
00878     NULL,                               /* intobjargproc sq_ass_item */
00879     NULL,                               /* ssizeobjargproc ***was_sq_ass_slice*** */
00880     (objobjproc) BPy_IDGroup_Contains,  /* objobjproc sq_contains */
00881     NULL,                               /* binaryfunc sq_inplace_concat */
00882     NULL,                               /* ssizeargfunc sq_inplace_repeat */
00883 };
00884 
00885 static PyMappingMethods BPy_IDGroup_Mapping = {
00886     (lenfunc)BPy_IDGroup_Map_Len,       /*inquiry mp_length */
00887     (binaryfunc)BPy_IDGroup_Map_GetItem,/*binaryfunc mp_subscript */
00888     (objobjargproc)BPy_IDGroup_Map_SetItem, /*objobjargproc mp_ass_subscript */
00889 };
00890 
00891 PyTypeObject BPy_IDGroup_Type = {
00892     PyVarObject_HEAD_INIT(NULL, 0)
00893     /*  For printing, in format "<module>.<name>" */
00894     "Blender IDProperty",       /* char *tp_name; */
00895     sizeof(BPy_IDProperty),     /* int tp_basicsize; */
00896     0,                          /* tp_itemsize;  For allocation */
00897 
00898     /* Methods to implement standard operations */
00899 
00900     NULL,                       /* destructor tp_dealloc; */
00901     NULL,                       /* printfunc tp_print; */
00902     NULL,     /* getattrfunc tp_getattr; */
00903     NULL,     /* setattrfunc tp_setattr; */
00904     NULL,                       /* cmpfunc tp_compare; */
00905     (reprfunc)BPy_IDGroup_repr,     /* reprfunc tp_repr; */
00906 
00907     /* Method suites for standard classes */
00908 
00909     NULL,                       /* PyNumberMethods *tp_as_number; */
00910     &BPy_IDGroup_Seq,           /* PySequenceMethods *tp_as_sequence; */
00911     &BPy_IDGroup_Mapping,       /* PyMappingMethods *tp_as_mapping; */
00912 
00913     /* More standard operations (here for binary compatibility) */
00914 
00915     (hashfunc)BPy_IDGroup_hash, /* hashfunc tp_hash; */
00916     NULL,                       /* ternaryfunc tp_call; */
00917     NULL,                       /* reprfunc tp_str; */
00918     NULL,                       /* getattrofunc tp_getattro; */
00919     NULL,                       /* setattrofunc tp_setattro; */
00920 
00921     /* Functions to access object as input/output buffer */
00922     NULL,                       /* PyBufferProcs *tp_as_buffer; */
00923 
00924   /*** Flags to define presence of optional/expanded features ***/
00925     Py_TPFLAGS_DEFAULT,         /* long tp_flags; */
00926 
00927     NULL,                       /*  char *tp_doc;  Documentation string */
00928   /*** Assigned meaning in release 2.0 ***/
00929     /* call function for all accessible objects */
00930     NULL,                       /* traverseproc tp_traverse; */
00931 
00932     /* delete references to contained objects */
00933     NULL,                       /* inquiry tp_clear; */
00934 
00935   /***  Assigned meaning in release 2.1 ***/
00936   /*** rich comparisons ***/
00937     NULL,                       /* richcmpfunc tp_richcompare; */
00938 
00939   /***  weak reference enabler ***/
00940     0,                          /* long tp_weaklistoffset; */
00941 
00942   /*** Added in release 2.2 ***/
00943     /*   Iterators */
00944     (getiterfunc)BPy_IDGroup_iter, /* getiterfunc tp_iter; */
00945     NULL,                       /* iternextfunc tp_iternext; */
00946   /*** Attribute descriptor and subclassing stuff ***/
00947     BPy_IDGroup_methods,        /* struct PyMethodDef *tp_methods; */
00948     NULL,                       /* struct PyMemberDef *tp_members; */
00949     BPy_IDGroup_getseters,       /* struct PyGetSetDef *tp_getset; */
00950 };
00951 
00952 /********Array Wrapper********/
00953 
00954 static PyTypeObject *idp_array_py_type(BPy_IDArray *self, short *is_double)
00955 {
00956     switch (self->prop->subtype) {
00957         case IDP_FLOAT:
00958             *is_double= 0;
00959             return &PyFloat_Type;
00960         case IDP_DOUBLE:
00961             *is_double= 1;
00962             return &PyFloat_Type;
00963         case IDP_INT:
00964             *is_double= 0;
00965             return &PyLong_Type;
00966     }
00967 
00968     *is_double= 0;
00969     return NULL;
00970 }
00971 
00972 static PyObject *BPy_IDArray_repr(BPy_IDArray *self)
00973 {
00974     return PyUnicode_FromFormat("<bpy id property array [%d]>", self->prop->len);
00975 }
00976 
00977 static PyObject *BPy_IDArray_GetType(BPy_IDArray *self)
00978 {
00979     switch (self->prop->subtype) {
00980     case IDP_FLOAT:
00981         return PyUnicode_FromString("f");
00982     case IDP_DOUBLE:
00983         return PyUnicode_FromString("d");
00984     case IDP_INT:
00985         return PyUnicode_FromString("i");
00986     }
00987 
00988     PyErr_Format(PyExc_RuntimeError,
00989                  "%s: invalid/corrupt array type '%d'!",
00990                  __func__, self->prop->subtype);
00991 
00992     return NULL;
00993 }
00994 
00995 static PyGetSetDef BPy_IDArray_getseters[] = {
00996     /* matches pythons array.typecode */
00997     {(char *)"typecode", (getter)BPy_IDArray_GetType, (setter)NULL, (char *)"The type of the data in the array, is an int.", NULL},
00998     {NULL, NULL, NULL, NULL, NULL},
00999 };
01000 
01001 static PyObject *BPy_IDArray_to_list(BPy_IDArray *self)
01002 {
01003     return BPy_IDGroup_MapDataToPy(self->prop);
01004 }
01005 
01006 static PyMethodDef BPy_IDArray_methods[] = {
01007     {"to_list", (PyCFunction)BPy_IDArray_to_list, METH_NOARGS,
01008         "return the array as a list"},
01009     {NULL, NULL, 0, NULL}
01010 };
01011 
01012 static int BPy_IDArray_Len(BPy_IDArray *self)
01013 {
01014     return self->prop->len;
01015 }
01016 
01017 static PyObject *BPy_IDArray_GetItem(BPy_IDArray *self, int index)
01018 {
01019     if (index < 0 || index >= self->prop->len) {
01020         PyErr_SetString(PyExc_IndexError, "index out of range!");
01021         return NULL;
01022     }
01023 
01024     switch (self->prop->subtype) {
01025         case IDP_FLOAT:
01026             return PyFloat_FromDouble(((float*)IDP_Array(self->prop))[index]);
01027         case IDP_DOUBLE:
01028             return PyFloat_FromDouble(((double*)IDP_Array(self->prop))[index]);
01029         case IDP_INT:
01030             return PyLong_FromLong((long)((int*)IDP_Array(self->prop))[index]);
01031     }
01032 
01033     PyErr_Format(PyExc_RuntimeError,
01034                  "%s: invalid/corrupt array type '%d'!",
01035                  __func__, self->prop->subtype);
01036 
01037     return NULL;
01038 }
01039 
01040 static int BPy_IDArray_SetItem(BPy_IDArray *self, int index, PyObject *value)
01041 {
01042     int i;
01043     float f;
01044     double d;
01045 
01046     if (index < 0 || index >= self->prop->len) {
01047         PyErr_SetString(PyExc_RuntimeError, "index out of range!");
01048         return -1;
01049     }
01050 
01051     switch (self->prop->subtype) {
01052         case IDP_FLOAT:
01053             f= (float)PyFloat_AsDouble(value);
01054             if (f==-1 && PyErr_Occurred()) {
01055                 PyErr_SetString(PyExc_TypeError, "expected a float");
01056                 return -1;
01057             }
01058             ((float*)IDP_Array(self->prop))[index] = f;
01059             break;
01060         case IDP_DOUBLE:
01061             d= PyFloat_AsDouble(value);
01062             if (d==-1 && PyErr_Occurred()) {
01063                 PyErr_SetString(PyExc_TypeError, "expected a float");
01064                 return -1;
01065             }
01066             ((double*)IDP_Array(self->prop))[index] = d;
01067             break;
01068         case IDP_INT:
01069             i= PyLong_AsSsize_t(value);
01070             if (i==-1 && PyErr_Occurred()) {
01071                 PyErr_SetString(PyExc_TypeError, "expected an int type");
01072                 return -1;
01073             }
01074 
01075             ((int*)IDP_Array(self->prop))[index] = i;
01076             break;
01077     }
01078     return 0;
01079 }
01080 
01081 static PySequenceMethods BPy_IDArray_Seq = {
01082     (lenfunc) BPy_IDArray_Len,          /* inquiry sq_length */
01083     NULL,                               /* binaryfunc sq_concat */
01084     NULL,                               /* intargfunc sq_repeat */
01085     (ssizeargfunc)BPy_IDArray_GetItem,  /* intargfunc sq_item */
01086     NULL,                               /* intintargfunc sq_slice */
01087     (ssizeobjargproc)BPy_IDArray_SetItem,/* intobjargproc sq_ass_item */
01088     NULL,                               /* intintobjargproc sq_ass_slice */
01089     NULL,                               /* objobjproc sq_contains */
01090                 /* Added in release 2.0 */
01091     NULL,                               /* binaryfunc sq_inplace_concat */
01092     NULL,                               /* intargfunc sq_inplace_repeat */
01093 };
01094 
01095 
01096 
01097 /* sequence slice (get): idparr[a:b] */
01098 static PyObject *BPy_IDArray_slice(BPy_IDArray *self, int begin, int end)
01099 {
01100     IDProperty *prop= self->prop;
01101     PyObject *tuple;
01102     int count;
01103 
01104     CLAMP(begin, 0, prop->len);
01105     if (end<0) end= prop->len+end+1;
01106     CLAMP(end, 0, prop->len);
01107     begin= MIN2(begin, end);
01108 
01109     tuple= PyTuple_New(end - begin);
01110 
01111     switch (prop->subtype) {
01112         case IDP_FLOAT:
01113         {
01114             float *array= (float*)IDP_Array(prop);
01115             for (count = begin; count < end; count++) {
01116                 PyTuple_SET_ITEM(tuple, count - begin, PyFloat_FromDouble(array[count]));
01117             }
01118             break;
01119         }
01120         case IDP_DOUBLE:
01121         {
01122             double *array= (double*)IDP_Array(prop);
01123             for (count = begin; count < end; count++) {
01124                 PyTuple_SET_ITEM(tuple, count - begin, PyFloat_FromDouble(array[count]));
01125             }
01126             break;
01127         }
01128         case IDP_INT:
01129         {
01130             int *array= (int*)IDP_Array(prop);
01131             for (count = begin; count < end; count++) {
01132                 PyTuple_SET_ITEM(tuple, count - begin, PyLong_FromLong(array[count]));
01133             }
01134             break;
01135         }
01136     }
01137 
01138     return tuple;
01139 }
01140 /* sequence slice (set): idparr[a:b] = value */
01141 static int BPy_IDArray_ass_slice(BPy_IDArray *self, int begin, int end, PyObject *seq)
01142 {
01143     IDProperty *prop= self->prop;
01144     short is_double= 0;
01145     const PyTypeObject *py_type= idp_array_py_type(self, &is_double);
01146     const size_t elem_size= is_double ? sizeof(double) : sizeof(float);
01147     size_t alloc_len;
01148     size_t size;
01149     void *vec;
01150 
01151     CLAMP(begin, 0, prop->len);
01152     CLAMP(end, 0, prop->len);
01153     begin = MIN2(begin, end);
01154 
01155     size = (end - begin);
01156     alloc_len= size * elem_size;
01157 
01158     vec= MEM_mallocN(alloc_len, "array assignment"); /* NOTE: we count on int/float being the same size here */
01159     if (PyC_AsArray(vec, seq, size, py_type, is_double, "slice assignment: ") == -1) {
01160         MEM_freeN(vec);
01161         return -1;
01162     }
01163 
01164     memcpy((void *)(((char *)IDP_Array(prop)) + (begin * elem_size)), vec, alloc_len);
01165 
01166     MEM_freeN(vec);
01167     return 0;
01168 }
01169 
01170 static PyObject *BPy_IDArray_subscript(BPy_IDArray* self, PyObject* item)
01171 {
01172     if (PyIndex_Check(item)) {
01173         Py_ssize_t i;
01174         i = PyNumber_AsSsize_t(item, PyExc_IndexError);
01175         if (i == -1 && PyErr_Occurred())
01176             return NULL;
01177         if (i < 0)
01178             i += self->prop->len;
01179         return BPy_IDArray_GetItem(self, i);
01180     }
01181     else if (PySlice_Check(item)) {
01182         Py_ssize_t start, stop, step, slicelength;
01183 
01184         if (PySlice_GetIndicesEx((void *)item, self->prop->len, &start, &stop, &step, &slicelength) < 0)
01185             return NULL;
01186 
01187         if (slicelength <= 0) {
01188             return PyTuple_New(0);
01189         }
01190         else if (step == 1) {
01191             return BPy_IDArray_slice(self, start, stop);
01192         }
01193         else {
01194             PyErr_SetString(PyExc_TypeError, "slice steps not supported with vectors");
01195             return NULL;
01196         }
01197     }
01198     else {
01199         PyErr_Format(PyExc_TypeError,
01200                      "vector indices must be integers, not %.200s",
01201                      __func__, Py_TYPE(item)->tp_name);
01202         return NULL;
01203     }
01204 }
01205 
01206 static int BPy_IDArray_ass_subscript(BPy_IDArray* self, PyObject* item, PyObject* value)
01207 {
01208     if (PyIndex_Check(item)) {
01209         Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
01210         if (i == -1 && PyErr_Occurred())
01211             return -1;
01212         if (i < 0)
01213             i += self->prop->len;
01214         return BPy_IDArray_SetItem(self, i, value);
01215     }
01216     else if (PySlice_Check(item)) {
01217         Py_ssize_t start, stop, step, slicelength;
01218 
01219         if (PySlice_GetIndicesEx((void *)item, self->prop->len, &start, &stop, &step, &slicelength) < 0)
01220             return -1;
01221 
01222         if (step == 1)
01223             return BPy_IDArray_ass_slice(self, start, stop, value);
01224         else {
01225             PyErr_SetString(PyExc_TypeError, "slice steps not supported with vectors");
01226             return -1;
01227         }
01228     }
01229     else {
01230         PyErr_Format(PyExc_TypeError,
01231                      "vector indices must be integers, not %.200s",
01232                      Py_TYPE(item)->tp_name);
01233         return -1;
01234     }
01235 }
01236 
01237 static PyMappingMethods BPy_IDArray_AsMapping = {
01238     (lenfunc)BPy_IDArray_Len,
01239     (binaryfunc)BPy_IDArray_subscript,
01240     (objobjargproc)BPy_IDArray_ass_subscript
01241 };
01242 
01243 
01244 PyTypeObject BPy_IDArray_Type = {
01245     PyVarObject_HEAD_INIT(NULL, 0)
01246     /*  For printing, in format "<module>.<name>" */
01247     "Blender IDArray",           /* char *tp_name; */
01248     sizeof(BPy_IDArray),       /* int tp_basicsize; */
01249     0,                          /* tp_itemsize;  For allocation */
01250 
01251     /* Methods to implement standard operations */
01252 
01253     NULL,                       /* destructor tp_dealloc; */
01254     NULL,                       /* printfunc tp_print; */
01255     NULL,     /* getattrfunc tp_getattr; */
01256     NULL,     /* setattrfunc tp_setattr; */
01257     NULL,                       /* cmpfunc tp_compare; */
01258     (reprfunc)BPy_IDArray_repr,     /* reprfunc tp_repr; */
01259 
01260     /* Method suites for standard classes */
01261 
01262     NULL,                       /* PyNumberMethods *tp_as_number; */
01263     &BPy_IDArray_Seq,           /* PySequenceMethods *tp_as_sequence; */
01264     &BPy_IDArray_AsMapping,     /* PyMappingMethods *tp_as_mapping; */
01265 
01266     /* More standard operations (here for binary compatibility) */
01267 
01268     NULL,                       /* hashfunc tp_hash; */
01269     NULL,                       /* ternaryfunc tp_call; */
01270     NULL,                       /* reprfunc tp_str; */
01271     NULL,                       /* getattrofunc tp_getattro; */
01272     NULL,                       /* setattrofunc tp_setattro; */
01273 
01274     /* Functions to access object as input/output buffer */
01275     NULL,                       /* PyBufferProcs *tp_as_buffer; */
01276 
01277   /*** Flags to define presence of optional/expanded features ***/
01278     Py_TPFLAGS_DEFAULT,         /* long tp_flags; */
01279 
01280     NULL,                       /*  char *tp_doc;  Documentation string */
01281   /*** Assigned meaning in release 2.0 ***/
01282     /* call function for all accessible objects */
01283     NULL,                       /* traverseproc tp_traverse; */
01284 
01285     /* delete references to contained objects */
01286     NULL,                       /* inquiry tp_clear; */
01287 
01288   /***  Assigned meaning in release 2.1 ***/
01289   /*** rich comparisons ***/
01290     NULL,                       /* richcmpfunc tp_richcompare; */
01291 
01292   /***  weak reference enabler ***/
01293     0,                          /* long tp_weaklistoffset; */
01294 
01295   /*** Added in release 2.2 ***/
01296     /*   Iterators */
01297     NULL,                       /* getiterfunc tp_iter; */
01298     NULL,                       /* iternextfunc tp_iternext; */
01299 
01300   /*** Attribute descriptor and subclassing stuff ***/
01301     BPy_IDArray_methods,        /* struct PyMethodDef *tp_methods; */
01302     NULL,                       /* struct PyMemberDef *tp_members; */
01303     BPy_IDArray_getseters,       /* struct PyGetSetDef *tp_getset; */
01304     NULL,                       /* struct _typeobject *tp_base; */
01305     NULL,                       /* PyObject *tp_dict; */
01306     NULL,                       /* descrgetfunc tp_descr_get; */
01307     NULL,                       /* descrsetfunc tp_descr_set; */
01308     0,                          /* long tp_dictoffset; */
01309     NULL,                       /* initproc tp_init; */
01310     NULL,                       /* allocfunc tp_alloc; */
01311     NULL,                       /* newfunc tp_new; */
01312     /*  Low-level free-memory routine */
01313     NULL,                       /* freefunc tp_free;  */
01314     /* For PyObject_IS_GC */
01315     NULL,                       /* inquiry tp_is_gc;  */
01316     NULL,                       /* PyObject *tp_bases; */
01317     /* method resolution order */
01318     NULL,                       /* PyObject *tp_mro;  */
01319     NULL,                       /* PyObject *tp_cache; */
01320     NULL,                       /* PyObject *tp_subclasses; */
01321     NULL,                       /* PyObject *tp_weaklist; */
01322     NULL
01323 };
01324 
01325 /*********** ID Property Group iterator ********/
01326 
01327 static PyObject *IDGroup_Iter_iterself(PyObject *self)
01328 {
01329     Py_XINCREF(self);
01330     return self;
01331 }
01332 
01333 static PyObject *IDGroup_Iter_repr(BPy_IDGroup_Iter *self)
01334 {
01335     return PyUnicode_FromFormat("(ID Property Group Iter \"%s\")", self->group->prop->name);
01336 }
01337 
01338 static PyObject *BPy_Group_Iter_Next(BPy_IDGroup_Iter *self)
01339 {
01340     IDProperty *cur=NULL;
01341     PyObject *ret;
01342 
01343     if (self->cur) {
01344         cur = self->cur;
01345         self->cur = self->cur->next;
01346         if (self->mode == IDPROP_ITER_ITEMS) {
01347             ret = PyTuple_New(2);
01348             PyTuple_SET_ITEM(ret, 0, PyUnicode_FromString(cur->name));
01349             PyTuple_SET_ITEM(ret, 1, BPy_IDGroup_WrapData(self->group->id, cur, self->group->prop));
01350             return ret;
01351         }
01352         else {
01353             return PyUnicode_FromString(cur->name);
01354         }
01355     }
01356     else {
01357         PyErr_SetString(PyExc_StopIteration, "iterator at end");
01358         return NULL;
01359     }
01360 }
01361 
01362 PyTypeObject BPy_IDGroup_Iter_Type = {
01363     PyVarObject_HEAD_INIT(NULL, 0)
01364     /*  For printing, in format "<module>.<name>" */
01365     "Blender IDGroup_Iter",           /* char *tp_name; */
01366     sizeof( BPy_IDGroup_Iter ),       /* int tp_basicsize; */
01367     0,                          /* tp_itemsize;  For allocation */
01368 
01369     /* Methods to implement standard operations */
01370 
01371     NULL,                       /* destructor tp_dealloc; */
01372     NULL,                       /* printfunc tp_print; */
01373     NULL,     /* getattrfunc tp_getattr; */
01374     NULL,     /* setattrfunc tp_setattr; */
01375     NULL,                       /* cmpfunc tp_compare; */
01376     ( reprfunc ) IDGroup_Iter_repr,     /* reprfunc tp_repr; */
01377 
01378     /* Method suites for standard classes */
01379 
01380     NULL,                       /* PyNumberMethods *tp_as_number; */
01381     NULL,                       /* PySequenceMethods *tp_as_sequence; */
01382     NULL,                       /* PyMappingMethods *tp_as_mapping; */
01383 
01384     /* More standard operations (here for binary compatibility) */
01385 
01386     NULL,                       /* hashfunc tp_hash; */
01387     NULL,                       /* ternaryfunc tp_call; */
01388     NULL,                       /* reprfunc tp_str; */
01389     NULL,                       /* getattrofunc tp_getattro; */
01390     NULL,                       /* setattrofunc tp_setattro; */
01391 
01392     /* Functions to access object as input/output buffer */
01393     NULL,                       /* PyBufferProcs *tp_as_buffer; */
01394 
01395   /*** Flags to define presence of optional/expanded features ***/
01396     Py_TPFLAGS_DEFAULT,         /* long tp_flags; */
01397 
01398     NULL,                       /*  char *tp_doc;  Documentation string */
01399   /*** Assigned meaning in release 2.0 ***/
01400     /* call function for all accessible objects */
01401     NULL,                       /* traverseproc tp_traverse; */
01402 
01403     /* delete references to contained objects */
01404     NULL,                       /* inquiry tp_clear; */
01405 
01406   /***  Assigned meaning in release 2.1 ***/
01407   /*** rich comparisons ***/
01408     NULL,                       /* richcmpfunc tp_richcompare; */
01409 
01410   /***  weak reference enabler ***/
01411     0,                          /* long tp_weaklistoffset; */
01412 
01413   /*** Added in release 2.2 ***/
01414     /*   Iterators */
01415     IDGroup_Iter_iterself,              /* getiterfunc tp_iter; */
01416     (iternextfunc) BPy_Group_Iter_Next, /* iternextfunc tp_iternext; */
01417 };
01418 
01419 void IDProp_Init_Types(void)
01420 {
01421     PyType_Ready(&BPy_IDGroup_Type);
01422     PyType_Ready(&BPy_IDGroup_Iter_Type);
01423     PyType_Ready(&BPy_IDArray_Type);
01424 }