style cleanup: python api
[blender.git] / source / blender / python / generic / idprop_py_api.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  *
19  * Contributor(s): Joseph Eagar, Campbell Barton
20  *
21  * ***** END GPL LICENSE BLOCK *****
22  */
23
24 /** \file blender/python/generic/idprop_py_api.c
25  *  \ingroup pygen
26  */
27
28
29 #include <Python.h>
30
31 #include "idprop_py_api.h"
32 #include "MEM_guardedalloc.h"
33
34 #include "BLI_string.h"
35 #include "BLI_utildefines.h"
36
37 #include "BKE_idprop.h"
38
39
40 #define USE_STRING_COERCE
41
42 #ifdef USE_STRING_COERCE
43 #include "py_capi_utils.h"
44 #endif
45
46 extern PyTypeObject BPy_IDArray_Type;
47 extern PyTypeObject BPy_IDGroup_Iter_Type;
48 extern PyTypeObject BPy_IDGroup_Type;
49
50 /*********************** ID Property Main Wrapper Stuff ***************/
51
52 /* ----------------------------------------------------------------------------
53  * static conversion functions to avoid duplicate code, no type checking.
54  */
55
56 static PyObject *idprop_py_from_idp_string(IDProperty *prop)
57 {
58         if (prop->subtype == IDP_STRING_SUB_BYTE) {
59                 return PyBytes_FromStringAndSize(IDP_Array(prop), prop->len);
60         }
61         else {
62 #ifdef USE_STRING_COERCE
63                 return PyC_UnicodeFromByteAndSize(IDP_Array(prop), prop->len - 1);
64 #else
65                 return PyUnicode_FromStringAndSize(IDP_Array(prop), prop->len - 1);
66 #endif
67         }
68 }
69
70 static PyObject *idprop_py_from_idp_int(IDProperty *prop)
71 {
72         return PyLong_FromLong((long)prop->data.val);
73 }
74
75 static PyObject *idprop_py_from_idp_float(IDProperty *prop)
76 {
77         return PyFloat_FromDouble((double)(*(float *)(&prop->data.val)));
78 }
79
80 static PyObject *idprop_py_from_idp_double(IDProperty *prop)
81 {
82         return PyFloat_FromDouble((*(double *)(&prop->data.val)));
83 }
84
85 static PyObject *idprop_py_from_idp_group(ID *id, IDProperty *prop, IDProperty *parent)
86 {
87         BPy_IDProperty *group = PyObject_New(BPy_IDProperty, &BPy_IDGroup_Type);
88         group->id = id;
89         group->prop = prop;
90         group->parent = parent; /* can be NULL */
91         return (PyObject *)group;
92 }
93
94 static PyObject *idprop_py_from_idp_array(ID *id, IDProperty *prop)
95 {
96         BPy_IDProperty *array = PyObject_New(BPy_IDProperty, &BPy_IDArray_Type);
97         array->id = id;
98         array->prop = prop;
99         return (PyObject *)array;
100 }
101
102 static PyObject *idprop_py_from_idp_idparray(ID *id, IDProperty *prop)
103 {
104         PyObject *seq = PyList_New(prop->len), *wrap;
105         IDProperty *array = IDP_IDPArray(prop);
106         int i;
107
108         if (!seq) {
109                 PyErr_Format(PyExc_RuntimeError,
110                              "%s: IDP_IDPARRAY: PyList_New(%d) failed",
111                              __func__, prop->len);
112                 return NULL;
113         }
114
115         for (i = 0; i < prop->len; i++) {
116                 wrap = BPy_IDGroup_WrapData(id, array++, prop);
117
118                 if (!wrap) /* BPy_IDGroup_MapDataToPy sets the error */
119                         return NULL;
120
121                 PyList_SET_ITEM(seq, i, wrap);
122         }
123
124         return seq;
125 }
126
127 /* -------------------------------------------------------------------------- */
128
129 /* use for both array and group */
130 static Py_hash_t BPy_IDGroup_hash(BPy_IDProperty *self)
131 {
132         return _Py_HashPointer(self->prop);
133 }
134
135 static PyObject *BPy_IDGroup_repr(BPy_IDProperty *self)
136 {
137         return PyUnicode_FromFormat("<bpy id property from \"%s\">", self->id->name);
138 }
139
140 PyObject *BPy_IDGroup_WrapData(ID *id, IDProperty *prop, IDProperty *parent)
141 {
142         switch (prop->type) {
143                 case IDP_STRING:   return idprop_py_from_idp_string(prop);
144                 case IDP_INT:      return idprop_py_from_idp_int(prop);
145                 case IDP_FLOAT:    return idprop_py_from_idp_float(prop);
146                 case IDP_DOUBLE:   return idprop_py_from_idp_double(prop);
147                 case IDP_GROUP:    return idprop_py_from_idp_group(id, prop, parent);
148                 case IDP_ARRAY:    return idprop_py_from_idp_array(id, prop);
149                 case IDP_IDPARRAY: return idprop_py_from_idp_idparray(id, prop); /* this could be better a internal type */
150                 default: Py_RETURN_NONE;
151         }
152 }
153
154 #if 0 /* UNUSED, currenly assignment overwrites into new properties, rather than setting in-place */
155 static int BPy_IDGroup_SetData(BPy_IDProperty *self, IDProperty *prop, PyObject *value)
156 {
157         switch (prop->type) {
158                 case IDP_STRING:
159                 {
160                         char *st;
161                         if (!PyUnicode_Check(value)) {
162                                 PyErr_SetString(PyExc_TypeError, "expected a string!");
163                                 return -1;
164                         }
165                         /* NOTE: if this code is enabled, bytes support needs to be added */
166 #ifdef USE_STRING_COERCE
167                         {
168                                 int alloc_len;
169                                 PyObject *value_coerce = NULL;
170
171                                 st = (char *)PyC_UnicodeAsByte(value, &value_coerce);
172                                 alloc_len = strlen(st) + 1;
173
174                                 st = _PyUnicode_AsString(value);
175                                 IDP_ResizeArray(prop, alloc_len);
176                                 memcpy(IDP_Array(prop), st, alloc_len);
177                                 Py_XDECREF(value_coerce);
178                         }
179 #else
180                         st = _PyUnicode_AsString(value);
181                         IDP_ResizeArray(prop, strlen(st) + 1);
182                         strcpy(IDP_Array(prop), st);
183 #endif
184
185                         return 0;
186                 }
187
188                 case IDP_INT:
189                 {
190                         int ivalue = PyLong_AsSsize_t(value);
191                         if (ivalue == -1 && PyErr_Occurred()) {
192                                 PyErr_SetString(PyExc_TypeError, "expected an int type");
193                                 return -1;
194                         }
195                         prop->data.val = ivalue;
196                         break;
197                 }
198                 case IDP_FLOAT:
199                 {
200                         float fvalue = (float)PyFloat_AsDouble(value);
201                         if (fvalue == -1 && PyErr_Occurred()) {
202                                 PyErr_SetString(PyExc_TypeError, "expected a float");
203                                 return -1;
204                         }
205                         *(float *)&self->prop->data.val = fvalue;
206                         break;
207                 }
208                 case IDP_DOUBLE:
209                 {
210                         double dvalue = PyFloat_AsDouble(value);
211                         if (dvalue == -1 && PyErr_Occurred()) {
212                                 PyErr_SetString(PyExc_TypeError, "expected a float");
213                                 return -1;
214                         }
215                         *(double *)&self->prop->data.val = dvalue;
216                         break;
217                 }
218                 default:
219                         PyErr_SetString(PyExc_AttributeError, "attempt to set read-only attribute!");
220                         return -1;
221         }
222         return 0;
223 }
224 #endif
225
226 static PyObject *BPy_IDGroup_GetName(BPy_IDProperty *self, void *UNUSED(closure))
227 {
228         return PyUnicode_FromString(self->prop->name);
229 }
230
231 static int BPy_IDGroup_SetName(BPy_IDProperty *self, PyObject *value, void *UNUSED(closure))
232 {
233         const char *name;
234         Py_ssize_t name_size;
235
236         if (!PyUnicode_Check(value)) {
237                 PyErr_SetString(PyExc_TypeError, "expected a string!");
238                 return -1;
239         }
240
241         name = _PyUnicode_AsStringAndSize(value, &name_size);
242
243         if (name_size > MAX_IDPROP_NAME) {
244                 PyErr_SetString(PyExc_TypeError, "string length cannot exceed 63 characters!");
245                 return -1;
246         }
247
248         memcpy(self->prop->name, name, name_size);
249         return 0;
250 }
251
252 #if 0
253 static PyObject *BPy_IDGroup_GetType(BPy_IDProperty *self)
254 {
255         return PyLong_FromSsize_t(self->prop->type);
256 }
257 #endif
258
259 static PyGetSetDef BPy_IDGroup_getseters[] = {
260         {(char *)"name", (getter)BPy_IDGroup_GetName, (setter)BPy_IDGroup_SetName, (char *)"The name of this Group.", NULL},
261         {NULL, NULL, NULL, NULL, NULL}
262 };
263
264 static Py_ssize_t BPy_IDGroup_Map_Len(BPy_IDProperty *self)
265 {
266         if (self->prop->type != IDP_GROUP) {
267                 PyErr_SetString(PyExc_TypeError, "len() of unsized object");
268                 return -1;
269         }
270
271         return self->prop->len;
272 }
273
274 static PyObject *BPy_IDGroup_Map_GetItem(BPy_IDProperty *self, PyObject *item)
275 {
276         IDProperty *idprop;
277         const char *name;
278
279         if (self->prop->type  != IDP_GROUP) {
280                 PyErr_SetString(PyExc_TypeError, "unsubscriptable object");
281                 return NULL;
282         }
283
284         name = _PyUnicode_AsString(item);
285
286         if (name == NULL) {
287                 PyErr_SetString(PyExc_TypeError, "only strings are allowed as keys of ID properties");
288                 return NULL;
289         }
290
291         idprop = IDP_GetPropertyFromGroup(self->prop, name);
292
293         if (idprop == NULL) {
294                 PyErr_SetString(PyExc_KeyError, "key not in subgroup dict");
295                 return NULL;
296         }
297
298         return BPy_IDGroup_WrapData(self->id, idprop, self->prop);
299 }
300
301 /* returns NULL on success, error string on failure */
302 static int idp_sequence_type(PyObject *seq)
303 {
304         PyObject *item;
305         int type = IDP_INT;
306
307         Py_ssize_t i, len = PySequence_Size(seq);
308         for (i = 0; i < len; i++) {
309                 item = PySequence_GetItem(seq, i);
310                 if (PyFloat_Check(item)) {
311                         if (type == IDP_IDPARRAY) { /* mixed dict/int */
312                                 Py_DECREF(item);
313                                 return -1;
314                         }
315                         type = IDP_DOUBLE;
316                 }
317                 else if (PyLong_Check(item)) {
318                         if (type == IDP_IDPARRAY) { /* mixed dict/int */
319                                 Py_DECREF(item);
320                                 return -1;
321                         }
322                 }
323                 else if (PyMapping_Check(item)) {
324                         if (i != 0 && (type != IDP_IDPARRAY)) { /* mixed dict/int */
325                                 Py_DECREF(item);
326                                 return -1;
327                         }
328                         type = IDP_IDPARRAY;
329                 }
330                 else {
331                         Py_XDECREF(item);
332                         return -1;
333                 }
334
335                 Py_DECREF(item);
336         }
337
338         return type;
339 }
340
341 /* note: group can be a pointer array or a group.
342  * assume we already checked key is a string. */
343 const char *BPy_IDProperty_Map_ValidateAndCreate(PyObject *name_obj, IDProperty *group, PyObject *ob)
344 {
345         IDProperty *prop = NULL;
346         IDPropertyTemplate val = {0};
347
348         const char *name = "";
349
350         if (name_obj) {
351                 Py_ssize_t name_size;
352                 name = _PyUnicode_AsStringAndSize(name_obj, &name_size);
353                 if (name_size > MAX_IDPROP_NAME) {
354                         return "the length of IDProperty names is limited to 63 characters";
355                 }
356         }
357
358         if (PyFloat_Check(ob)) {
359                 val.d = PyFloat_AsDouble(ob);
360                 prop = IDP_New(IDP_DOUBLE, &val, name);
361         }
362         else if (PyLong_Check(ob)) {
363                 val.i = (int) PyLong_AsSsize_t(ob);
364                 prop = IDP_New(IDP_INT, &val, name);
365         }
366         else if (PyUnicode_Check(ob)) {
367 #ifdef USE_STRING_COERCE
368                 PyObject *value_coerce = NULL;
369                 val.string.str = (char *)PyC_UnicodeAsByte(ob, &value_coerce);
370                 val.string.subtype = IDP_STRING_SUB_UTF8;
371                 prop = IDP_New(IDP_STRING, &val, name);
372                 Py_XDECREF(value_coerce);
373 #else
374                 val.str = _PyUnicode_AsString(ob);
375                 prop = IDP_New(IDP_STRING, val, name);
376 #endif
377         }
378         else if (PyBytes_Check(ob)) {
379                 val.string.str = PyBytes_AS_STRING(ob);
380                 val.string.len = PyBytes_GET_SIZE(ob);
381                 val.string.subtype = IDP_STRING_SUB_BYTE;
382
383                 prop = IDP_New(IDP_STRING, &val, name);
384                 //prop = IDP_NewString(PyBytes_AS_STRING(ob), name, PyBytes_GET_SIZE(ob));
385                 //prop->subtype = IDP_STRING_SUB_BYTE;
386         }
387         else if (PySequence_Check(ob)) {
388                 PyObject *item;
389                 int i;
390
391                 if ((val.array.type = idp_sequence_type(ob)) == -1)
392                         return "only floats, ints and dicts are allowed in ID property arrays";
393
394                 /* validate sequence and derive type.
395                  * we assume IDP_INT unless we hit a float
396                  * number; then we assume it's */
397
398                 val.array.len = PySequence_Size(ob);
399
400                 switch (val.array.type) {
401                         case IDP_DOUBLE:
402                                 prop = IDP_New(IDP_ARRAY, &val, name);
403                                 for (i = 0; i < val.array.len; i++) {
404                                         item = PySequence_GetItem(ob, i);
405                                         ((double *)IDP_Array(prop))[i] = (float)PyFloat_AsDouble(item);
406                                         Py_DECREF(item);
407                                 }
408                                 break;
409                         case IDP_INT:
410                                 prop = IDP_New(IDP_ARRAY, &val, name);
411                                 for (i = 0; i < val.array.len; i++) {
412                                         item = PySequence_GetItem(ob, i);
413                                         ((int *)IDP_Array(prop))[i] = (int)PyLong_AsSsize_t(item);
414                                         Py_DECREF(item);
415                                 }
416                                 break;
417                         case IDP_IDPARRAY:
418                                 prop = IDP_NewIDPArray(name);
419                                 for (i = 0; i < val.array.len; i++) {
420                                         const char *error;
421                                         item = PySequence_GetItem(ob, i);
422                                         error = BPy_IDProperty_Map_ValidateAndCreate(NULL, prop, item);
423                                         Py_DECREF(item);
424
425                                         if (error)
426                                                 return error;
427                                 }
428                                 break;
429                 }
430         }
431         else if (PyMapping_Check(ob)) {
432                 PyObject *keys, *vals, *key, *pval;
433                 int i, len;
434                 /*yay! we get into recursive stuff now!*/
435                 keys = PyMapping_Keys(ob);
436                 vals = PyMapping_Values(ob);
437
438                 /* we allocate the group first; if we hit any invalid data,
439                  * we can delete it easily enough.*/
440                 prop = IDP_New(IDP_GROUP, &val, name);
441                 len = PyMapping_Length(ob);
442                 for (i = 0; i < len; i++) {
443                         key = PySequence_GetItem(keys, i);
444                         pval = PySequence_GetItem(vals, i);
445                         if (!PyUnicode_Check(key)) {
446                                 IDP_FreeProperty(prop);
447                                 MEM_freeN(prop);
448                                 Py_XDECREF(keys);
449                                 Py_XDECREF(vals);
450                                 Py_XDECREF(key);
451                                 Py_XDECREF(pval);
452                                 return "invalid element in subgroup dict template!";
453                         }
454                         if (BPy_IDProperty_Map_ValidateAndCreate(key, prop, pval)) {
455                                 IDP_FreeProperty(prop);
456                                 MEM_freeN(prop);
457                                 Py_XDECREF(keys);
458                                 Py_XDECREF(vals);
459                                 Py_XDECREF(key);
460                                 Py_XDECREF(pval);
461                                 return "invalid element in subgroup dict template!";
462                         }
463                         Py_XDECREF(key);
464                         Py_XDECREF(pval);
465                 }
466                 Py_XDECREF(keys);
467                 Py_XDECREF(vals);
468         }
469         else return "invalid property value";
470
471         if (group->type == IDP_IDPARRAY) {
472                 IDP_AppendArray(group, prop);
473                 // IDP_FreeProperty(item); // IDP_AppendArray does a shallow copy (memcpy), only free memory
474                 MEM_freeN(prop);
475         }
476         else {
477                 IDP_ReplaceInGroup(group, prop);
478         }
479
480         return NULL;
481 }
482
483 int BPy_Wrap_SetMapItem(IDProperty *prop, PyObject *key, PyObject *val)
484 {
485         if (prop->type  != IDP_GROUP) {
486                 PyErr_SetString(PyExc_TypeError, "unsubscriptable object");
487                 return -1;
488         }
489
490         if (val == NULL) { /* del idprop[key] */
491                 IDProperty *pkey = IDP_GetPropertyFromGroup(prop, _PyUnicode_AsString(key));
492                 if (pkey) {
493                         IDP_RemFromGroup(prop, pkey);
494                         IDP_FreeProperty(pkey);
495                         MEM_freeN(pkey);
496                         return 0;
497                 }
498                 else {
499                         PyErr_SetString(PyExc_KeyError, "property not found in group");
500                         return -1;
501                 }
502         }
503         else {
504                 const char *err;
505
506                 if (!PyUnicode_Check(key)) {
507                         PyErr_SetString(PyExc_TypeError, "only strings are allowed as subgroup keys");
508                         return -1;
509                 }
510
511                 err = BPy_IDProperty_Map_ValidateAndCreate(key, prop, val);
512                 if (err) {
513                         PyErr_SetString(PyExc_KeyError, err);
514                         return -1;
515                 }
516
517                 return 0;
518         }
519 }
520
521 static int BPy_IDGroup_Map_SetItem(BPy_IDProperty *self, PyObject *key, PyObject *val)
522 {
523         return BPy_Wrap_SetMapItem(self->prop, key, val);
524 }
525
526 static PyObject *BPy_IDGroup_iter(BPy_IDProperty *self)
527 {
528         BPy_IDGroup_Iter *iter = PyObject_New(BPy_IDGroup_Iter, &BPy_IDGroup_Iter_Type);
529         iter->group = self;
530         iter->mode = IDPROP_ITER_KEYS;
531         iter->cur = self->prop->data.group.first;
532         Py_XINCREF(iter);
533         return (PyObject *)iter;
534 }
535
536 /* for simple, non nested types this is the same as BPy_IDGroup_WrapData */
537 static PyObject *BPy_IDGroup_MapDataToPy(IDProperty *prop)
538 {
539         switch (prop->type) {
540                 case IDP_STRING:
541                         return idprop_py_from_idp_string(prop);
542                 case IDP_INT:
543                         return idprop_py_from_idp_int(prop);
544                 case IDP_FLOAT:
545                         return idprop_py_from_idp_float(prop);
546                 case IDP_DOUBLE:
547                         return idprop_py_from_idp_double(prop);
548                 case IDP_ARRAY:
549                 {
550                         PyObject *seq = PyList_New(prop->len);
551                         int i;
552
553                         if (!seq) {
554                                 PyErr_Format(PyExc_RuntimeError,
555                                              "%s: IDP_ARRAY: PyList_New(%d) failed",
556                                              __func__, prop->len);
557                                 return NULL;
558                         }
559
560                         switch (prop->subtype) {
561                                 case IDP_FLOAT:
562                                 {
563                                         float *array = (float *)IDP_Array(prop);
564                                         for (i = 0; i < prop->len; i++) {
565                                                 PyList_SET_ITEM(seq, i, PyFloat_FromDouble(array[i]));
566                                         }
567                                         break;
568                                 }
569                                 case IDP_DOUBLE:
570                                 {
571                                         double *array = (double *)IDP_Array(prop);
572                                         for (i = 0; i < prop->len; i++) {
573                                                 PyList_SET_ITEM(seq, i, PyFloat_FromDouble(array[i]));
574                                         }
575                                         break;
576                                 }
577                                 case IDP_INT:
578                                 {
579                                         int *array = (int *)IDP_Array(prop);
580                                         for (i = 0; i < prop->len; i++) {
581                                                 PyList_SET_ITEM(seq, i, PyLong_FromLong(array[i]));
582                                         }
583                                         break;
584                                 }
585                                 default:
586                                         PyErr_Format(PyExc_RuntimeError,
587                                                      "%s: invalid/corrupt array type '%d'!",
588                                                      __func__, prop->subtype);
589                                         Py_DECREF(seq);
590                                         return NULL;
591                         }
592
593                         return seq;
594                 }
595                 case IDP_IDPARRAY:
596                 {
597                         PyObject *seq = PyList_New(prop->len), *wrap;
598                         IDProperty *array = IDP_IDPArray(prop);
599                         int i;
600
601                         if (!seq) {
602                                 PyErr_Format(PyExc_RuntimeError,
603                                              "%s: IDP_IDPARRAY: PyList_New(%d) failed",
604                                              __func__, prop->len);
605                                 return NULL;
606                         }
607
608                         for (i = 0; i < prop->len; i++) {
609                                 wrap = BPy_IDGroup_MapDataToPy(array++);
610
611                                 if (!wrap) /* BPy_IDGroup_MapDataToPy sets the error */
612                                         return NULL;
613
614                                 PyList_SET_ITEM(seq, i, wrap);
615                         }
616                         return seq;
617                 }
618                 case IDP_GROUP:
619                 {
620                         PyObject *dict = PyDict_New(), *wrap;
621                         IDProperty *loop;
622
623                         for (loop = prop->data.group.first; loop; loop = loop->next) {
624                                 wrap = BPy_IDGroup_MapDataToPy(loop);
625
626                                 if (!wrap) /* BPy_IDGroup_MapDataToPy sets the error */
627                                         return NULL;
628
629                                 PyDict_SetItemString(dict, loop->name, wrap);
630                                 Py_DECREF(wrap);
631                         }
632                         return dict;
633                 }
634         }
635
636         PyErr_Format(PyExc_RuntimeError,
637                      "%s ERROR: '%s' property exists with a bad type code '%d'!",
638                      __func__, prop->name, prop->type);
639         return NULL;
640 }
641
642 static PyObject *BPy_IDGroup_Pop(BPy_IDProperty *self, PyObject *value)
643 {
644         IDProperty *idprop;
645         PyObject *pyform;
646         const char *name = _PyUnicode_AsString(value);
647
648         if (!name) {
649                 PyErr_Format(PyExc_TypeError,
650                              "pop expected at least a string argument, not %.200s",
651                              Py_TYPE(value)->tp_name);
652                 return NULL;
653         }
654
655         idprop = IDP_GetPropertyFromGroup(self->prop, name);
656
657         if (idprop) {
658                 pyform = BPy_IDGroup_MapDataToPy(idprop);
659
660                 if (!pyform) {
661                         /* ok something bad happened with the pyobject,
662                          * so don't remove the prop from the group.  if pyform is
663                          * NULL, then it already should have raised an exception.*/
664                         return NULL;
665                 }
666
667                 IDP_RemFromGroup(self->prop, idprop);
668                 return pyform;
669         }
670
671         PyErr_SetString(PyExc_KeyError, "item not in group");
672         return NULL;
673 }
674
675 static PyObject *BPy_IDGroup_IterItems(BPy_IDProperty *self)
676 {
677         BPy_IDGroup_Iter *iter = PyObject_New(BPy_IDGroup_Iter, &BPy_IDGroup_Iter_Type);
678         iter->group = self;
679         iter->mode = IDPROP_ITER_ITEMS;
680         iter->cur = self->prop->data.group.first;
681         Py_XINCREF(iter);
682         return (PyObject *)iter;
683 }
684
685 /* utility function */
686 static void BPy_IDGroup_CorrectListLen(IDProperty *prop, PyObject *seq, int len, const char *func)
687 {
688         int j;
689
690         printf("%s: ID Property Error found and corrected!\n", func);
691
692         /*fill rest of list with valid references to None*/
693         for (j = len; j < prop->len; j++) {
694                 Py_INCREF(Py_None);
695                 PyList_SET_ITEM(seq, j, Py_None);
696         }
697
698         /*set correct group length*/
699         prop->len = len;
700 }
701
702 PyObject *BPy_Wrap_GetKeys(IDProperty *prop)
703 {
704         PyObject *list = PyList_New(prop->len);
705         IDProperty *loop;
706         int i;
707
708         for (i = 0, loop = prop->data.group.first; loop && (i < prop->len); loop = loop->next, i++)
709                 PyList_SET_ITEM(list, i, PyUnicode_FromString(loop->name));
710
711         /* if the id prop is corrupt, count the remaining */
712         for ( ; loop; loop = loop->next, i++) {
713                 /* pass */
714         }
715
716         if (i != prop->len) { /* if the loop didnt finish, we know the length is wrong */
717                 BPy_IDGroup_CorrectListLen(prop, list, i, __func__);
718                 Py_DECREF(list); /*free the list*/
719                 /*call self again*/
720                 return BPy_Wrap_GetKeys(prop);
721         }
722
723         return list;
724 }
725
726 PyObject *BPy_Wrap_GetValues(ID *id, IDProperty *prop)
727 {
728         PyObject *list = PyList_New(prop->len);
729         IDProperty *loop;
730         int i;
731
732         for (i = 0, loop = prop->data.group.first; loop; loop = loop->next, i++) {
733                 PyList_SET_ITEM(list, i, BPy_IDGroup_WrapData(id, loop, prop));
734         }
735
736         if (i != prop->len) {
737                 BPy_IDGroup_CorrectListLen(prop, list, i, __func__);
738                 Py_DECREF(list); /*free the list*/
739                 /*call self again*/
740                 return BPy_Wrap_GetValues(id, prop);
741         }
742
743         return list;
744 }
745
746 PyObject *BPy_Wrap_GetItems(ID *id, IDProperty *prop)
747 {
748         PyObject *seq = PyList_New(prop->len);
749         IDProperty *loop;
750         int i;
751
752         for (i = 0, loop = prop->data.group.first; loop; loop = loop->next, i++) {
753                 PyObject *item = PyTuple_New(2);
754                 PyTuple_SET_ITEM(item, 0, PyUnicode_FromString(loop->name));
755                 PyTuple_SET_ITEM(item, 1, BPy_IDGroup_WrapData(id, loop, prop));
756                 PyList_SET_ITEM(seq, i, item);
757         }
758
759         if (i != prop->len) {
760                 BPy_IDGroup_CorrectListLen(prop, seq, i, __func__);
761                 Py_DECREF(seq); /*free the list*/
762                 /*call self again*/
763                 return BPy_Wrap_GetItems(id, prop);
764         }
765
766         return seq;
767 }
768
769
770 static PyObject *BPy_IDGroup_GetKeys(BPy_IDProperty *self)
771 {
772         return BPy_Wrap_GetKeys(self->prop);
773 }
774
775 static PyObject *BPy_IDGroup_GetValues(BPy_IDProperty *self)
776 {
777         return BPy_Wrap_GetValues(self->id, self->prop);
778 }
779
780 static PyObject *BPy_IDGroup_GetItems(BPy_IDProperty *self)
781 {
782         return BPy_Wrap_GetItems(self->id, self->prop);
783 }
784
785 static int BPy_IDGroup_Contains(BPy_IDProperty *self, PyObject *value)
786 {
787         const char *name = _PyUnicode_AsString(value);
788
789         if (!name) {
790                 PyErr_Format(PyExc_TypeError,
791                              "expected a string, not a %.200s",
792                              Py_TYPE(value)->tp_name);
793                 return -1;
794         }
795
796         return IDP_GetPropertyFromGroup(self->prop, name) ? 1 : 0;
797 }
798
799 static PyObject *BPy_IDGroup_Update(BPy_IDProperty *self, PyObject *value)
800 {
801         PyObject *pkey, *pval;
802         Py_ssize_t i = 0;
803
804         if (!PyDict_Check(value)) {
805                 PyErr_Format(PyExc_TypeError,
806                              "expected a dict not a %.200s",
807                              Py_TYPE(value)->tp_name);
808                 return NULL;
809         }
810
811         while (PyDict_Next(value, &i, &pkey, &pval)) {
812                 BPy_IDGroup_Map_SetItem(self, pkey, pval);
813                 if (PyErr_Occurred()) return NULL;
814         }
815
816         Py_RETURN_NONE;
817 }
818
819 static PyObject *BPy_IDGroup_to_dict(BPy_IDProperty *self)
820 {
821         return BPy_IDGroup_MapDataToPy(self->prop);
822 }
823
824
825 /* Matches python dict.get(key, [default]) */
826 static PyObject *BPy_IDGroup_Get(BPy_IDProperty *self, PyObject *args)
827 {
828         IDProperty *idprop;
829         char *key;
830         PyObject *def = Py_None;
831
832         if (!PyArg_ParseTuple(args, "s|O:get", &key, &def))
833                 return NULL;
834
835         idprop = IDP_GetPropertyFromGroup(self->prop, key);
836         if (idprop) {
837                 PyObject *pyobj = BPy_IDGroup_WrapData(self->id, idprop, self->prop);
838                 if (pyobj)
839                         return pyobj;
840         }
841
842         Py_INCREF(def);
843         return def;
844 }
845
846 static struct PyMethodDef BPy_IDGroup_methods[] = {
847         {"pop", (PyCFunction)BPy_IDGroup_Pop, METH_O,
848          "pop an item from the group; raises KeyError if the item doesn't exist"},
849         {"iteritems", (PyCFunction)BPy_IDGroup_IterItems, METH_NOARGS,
850          "iterate through the items in the dict; behaves like dictionary method iteritems"},
851         {"keys", (PyCFunction)BPy_IDGroup_GetKeys, METH_NOARGS,
852          "get the keys associated with this group as a list of strings"},
853         {"values", (PyCFunction)BPy_IDGroup_GetValues, METH_NOARGS,
854          "get the values associated with this group"},
855         {"items", (PyCFunction)BPy_IDGroup_GetItems, METH_NOARGS,
856          "get the items associated with this group"},
857         {"update", (PyCFunction)BPy_IDGroup_Update, METH_O,
858          "updates the values in the group with the values of another or a dict"},
859         {"get", (PyCFunction)BPy_IDGroup_Get, METH_VARARGS,
860          "idprop.get(k[,d]) -> idprop[k] if k in idprop, else d.  d defaults to None"},
861         {"to_dict", (PyCFunction)BPy_IDGroup_to_dict, METH_NOARGS,
862          "return a purely python version of the group"},
863         {NULL, NULL, 0, NULL}
864 };
865
866 static PySequenceMethods BPy_IDGroup_Seq = {
867         (lenfunc) BPy_IDGroup_Map_Len,      /* lenfunc sq_length */
868         NULL,                               /* binaryfunc sq_concat */
869         NULL,                               /* ssizeargfunc sq_repeat */
870         NULL,                               /* ssizeargfunc sq_item */ /* TODO - setting this will allow PySequence_Check to return True */
871         NULL,                               /* intintargfunc ***was_sq_slice*** */
872         NULL,                               /* intobjargproc sq_ass_item */
873         NULL,                               /* ssizeobjargproc ***was_sq_ass_slice*** */
874         (objobjproc) BPy_IDGroup_Contains,  /* objobjproc sq_contains */
875         NULL,                               /* binaryfunc sq_inplace_concat */
876         NULL,                               /* ssizeargfunc sq_inplace_repeat */
877 };
878
879 static PyMappingMethods BPy_IDGroup_Mapping = {
880         (lenfunc)BPy_IDGroup_Map_Len,           /*inquiry mp_length */
881         (binaryfunc)BPy_IDGroup_Map_GetItem,    /*binaryfunc mp_subscript */
882         (objobjargproc)BPy_IDGroup_Map_SetItem, /*objobjargproc mp_ass_subscript */
883 };
884
885 PyTypeObject BPy_IDGroup_Type = {
886         PyVarObject_HEAD_INIT(NULL, 0)
887         /*  For printing, in format "<module>.<name>" */
888         "Blender IDProperty",       /* char *tp_name; */
889         sizeof(BPy_IDProperty),     /* int tp_basicsize; */
890         0,                          /* tp_itemsize;  For allocation */
891
892         /* Methods to implement standard operations */
893
894         NULL,                       /* destructor tp_dealloc; */
895         NULL,                       /* printfunc tp_print; */
896         NULL,                       /* getattrfunc tp_getattr; */
897         NULL,                       /* setattrfunc tp_setattr; */
898         NULL,                       /* cmpfunc tp_compare; */
899         (reprfunc)BPy_IDGroup_repr,     /* reprfunc tp_repr; */
900
901         /* Method suites for standard classes */
902
903         NULL,                       /* PyNumberMethods *tp_as_number; */
904         &BPy_IDGroup_Seq,           /* PySequenceMethods *tp_as_sequence; */
905         &BPy_IDGroup_Mapping,       /* PyMappingMethods *tp_as_mapping; */
906
907         /* More standard operations (here for binary compatibility) */
908
909         (hashfunc)BPy_IDGroup_hash, /* hashfunc tp_hash; */
910         NULL,                       /* ternaryfunc tp_call; */
911         NULL,                       /* reprfunc tp_str; */
912         NULL,                       /* getattrofunc tp_getattro; */
913         NULL,                       /* setattrofunc tp_setattro; */
914
915         /* Functions to access object as input/output buffer */
916         NULL,                       /* PyBufferProcs *tp_as_buffer; */
917
918         /*** Flags to define presence of optional/expanded features ***/
919         Py_TPFLAGS_DEFAULT,         /* long tp_flags; */
920
921         NULL,                       /*  char *tp_doc;  Documentation string */
922         /*** Assigned meaning in release 2.0 ***/
923         /* call function for all accessible objects */
924         NULL,                       /* traverseproc tp_traverse; */
925
926         /* delete references to contained objects */
927         NULL,                       /* inquiry tp_clear; */
928
929         /***  Assigned meaning in release 2.1 ***/
930         /*** rich comparisons ***/
931         NULL,                       /* richcmpfunc tp_richcompare; */
932
933         /***  weak reference enabler ***/
934         0,                          /* long tp_weaklistoffset; */
935
936         /*** Added in release 2.2 ***/
937         /*   Iterators */
938         (getiterfunc)BPy_IDGroup_iter, /* getiterfunc tp_iter; */
939         NULL,                       /* iternextfunc tp_iternext; */
940         /*** Attribute descriptor and subclassing stuff ***/
941         BPy_IDGroup_methods,        /* struct PyMethodDef *tp_methods; */
942         NULL,                       /* struct PyMemberDef *tp_members; */
943         BPy_IDGroup_getseters,       /* struct PyGetSetDef *tp_getset; */
944 };
945
946 /********Array Wrapper********/
947
948 static PyTypeObject *idp_array_py_type(BPy_IDArray *self, short *is_double)
949 {
950         switch (self->prop->subtype) {
951                 case IDP_FLOAT:
952                         *is_double = 0;
953                         return &PyFloat_Type;
954                 case IDP_DOUBLE:
955                         *is_double = 1;
956                         return &PyFloat_Type;
957                 case IDP_INT:
958                         *is_double = 0;
959                         return &PyLong_Type;
960         }
961
962         *is_double = 0;
963         return NULL;
964 }
965
966 static PyObject *BPy_IDArray_repr(BPy_IDArray *self)
967 {
968         return PyUnicode_FromFormat("<bpy id property array [%d]>", self->prop->len);
969 }
970
971 static PyObject *BPy_IDArray_GetType(BPy_IDArray *self)
972 {
973         switch (self->prop->subtype) {
974                 case IDP_FLOAT:  return PyUnicode_FromString("f");
975                 case IDP_DOUBLE: return PyUnicode_FromString("d");
976                 case IDP_INT:    return PyUnicode_FromString("i");
977         }
978
979         PyErr_Format(PyExc_RuntimeError,
980                      "%s: invalid/corrupt array type '%d'!",
981                      __func__, self->prop->subtype);
982
983         return NULL;
984 }
985
986 static PyGetSetDef BPy_IDArray_getseters[] = {
987         /* matches pythons array.typecode */
988         {(char *)"typecode", (getter)BPy_IDArray_GetType, (setter)NULL, (char *)"The type of the data in the array, is an int.", NULL},
989         {NULL, NULL, NULL, NULL, NULL},
990 };
991
992 static PyObject *BPy_IDArray_to_list(BPy_IDArray *self)
993 {
994         return BPy_IDGroup_MapDataToPy(self->prop);
995 }
996
997 static PyMethodDef BPy_IDArray_methods[] = {
998         {"to_list", (PyCFunction)BPy_IDArray_to_list, METH_NOARGS,
999          "return the array as a list"},
1000         {NULL, NULL, 0, NULL}
1001 };
1002
1003 static int BPy_IDArray_Len(BPy_IDArray *self)
1004 {
1005         return self->prop->len;
1006 }
1007
1008 static PyObject *BPy_IDArray_GetItem(BPy_IDArray *self, int index)
1009 {
1010         if (index < 0 || index >= self->prop->len) {
1011                 PyErr_SetString(PyExc_IndexError, "index out of range!");
1012                 return NULL;
1013         }
1014
1015         switch (self->prop->subtype) {
1016                 case IDP_FLOAT:
1017                         return PyFloat_FromDouble(((float *)IDP_Array(self->prop))[index]);
1018                 case IDP_DOUBLE:
1019                         return PyFloat_FromDouble(((double *)IDP_Array(self->prop))[index]);
1020                 case IDP_INT:
1021                         return PyLong_FromLong((long)((int *)IDP_Array(self->prop))[index]);
1022         }
1023
1024         PyErr_Format(PyExc_RuntimeError,
1025                      "%s: invalid/corrupt array type '%d'!",
1026                      __func__, self->prop->subtype);
1027
1028         return NULL;
1029 }
1030
1031 static int BPy_IDArray_SetItem(BPy_IDArray *self, int index, PyObject *value)
1032 {
1033         int i;
1034         float f;
1035         double d;
1036
1037         if (index < 0 || index >= self->prop->len) {
1038                 PyErr_SetString(PyExc_RuntimeError, "index out of range!");
1039                 return -1;
1040         }
1041
1042         switch (self->prop->subtype) {
1043                 case IDP_FLOAT:
1044                         f = (float)PyFloat_AsDouble(value);
1045                         if (f == -1 && PyErr_Occurred()) {
1046                                 PyErr_SetString(PyExc_TypeError, "expected a float");
1047                                 return -1;
1048                         }
1049                         ((float *)IDP_Array(self->prop))[index] = f;
1050                         break;
1051                 case IDP_DOUBLE:
1052                         d = PyFloat_AsDouble(value);
1053                         if (d == -1 && PyErr_Occurred()) {
1054                                 PyErr_SetString(PyExc_TypeError, "expected a float");
1055                                 return -1;
1056                         }
1057                         ((double *)IDP_Array(self->prop))[index] = d;
1058                         break;
1059                 case IDP_INT:
1060                         i = PyLong_AsSsize_t(value);
1061                         if (i == -1 && PyErr_Occurred()) {
1062                                 PyErr_SetString(PyExc_TypeError, "expected an int type");
1063                                 return -1;
1064                         }
1065
1066                         ((int *)IDP_Array(self->prop))[index] = i;
1067                         break;
1068         }
1069         return 0;
1070 }
1071
1072 static PySequenceMethods BPy_IDArray_Seq = {
1073         (lenfunc) BPy_IDArray_Len,          /* inquiry sq_length */
1074         NULL,                               /* binaryfunc sq_concat */
1075         NULL,                               /* intargfunc sq_repeat */
1076         (ssizeargfunc)BPy_IDArray_GetItem,  /* intargfunc sq_item */
1077         NULL,                               /* intintargfunc sq_slice */
1078         (ssizeobjargproc)BPy_IDArray_SetItem, /* intobjargproc sq_ass_item */
1079         NULL,                               /* intintobjargproc sq_ass_slice */
1080         NULL,                               /* objobjproc sq_contains */
1081         /* Added in release 2.0 */
1082         NULL,                               /* binaryfunc sq_inplace_concat */
1083         NULL,                               /* intargfunc sq_inplace_repeat */
1084 };
1085
1086
1087
1088 /* sequence slice (get): idparr[a:b] */
1089 static PyObject *BPy_IDArray_slice(BPy_IDArray *self, int begin, int end)
1090 {
1091         IDProperty *prop = self->prop;
1092         PyObject *tuple;
1093         int count;
1094
1095         CLAMP(begin, 0, prop->len);
1096         if (end < 0) end = prop->len + end + 1;
1097         CLAMP(end, 0, prop->len);
1098         begin = MIN2(begin, end);
1099
1100         tuple = PyTuple_New(end - begin);
1101
1102         switch (prop->subtype) {
1103                 case IDP_FLOAT:
1104                 {
1105                         float *array = (float *)IDP_Array(prop);
1106                         for (count = begin; count < end; count++) {
1107                                 PyTuple_SET_ITEM(tuple, count - begin, PyFloat_FromDouble(array[count]));
1108                         }
1109                         break;
1110                 }
1111                 case IDP_DOUBLE:
1112                 {
1113                         double *array = (double *)IDP_Array(prop);
1114                         for (count = begin; count < end; count++) {
1115                                 PyTuple_SET_ITEM(tuple, count - begin, PyFloat_FromDouble(array[count]));
1116                         }
1117                         break;
1118                 }
1119                 case IDP_INT:
1120                 {
1121                         int *array = (int *)IDP_Array(prop);
1122                         for (count = begin; count < end; count++) {
1123                                 PyTuple_SET_ITEM(tuple, count - begin, PyLong_FromLong(array[count]));
1124                         }
1125                         break;
1126                 }
1127         }
1128
1129         return tuple;
1130 }
1131 /* sequence slice (set): idparr[a:b] = value */
1132 static int BPy_IDArray_ass_slice(BPy_IDArray *self, int begin, int end, PyObject *seq)
1133 {
1134         IDProperty *prop = self->prop;
1135         short is_double = 0;
1136         const PyTypeObject *py_type = idp_array_py_type(self, &is_double);
1137         const size_t elem_size = is_double ? sizeof(double) : sizeof(float);
1138         size_t alloc_len;
1139         size_t size;
1140         void *vec;
1141
1142         CLAMP(begin, 0, prop->len);
1143         CLAMP(end, 0, prop->len);
1144         begin = MIN2(begin, end);
1145
1146         size = (end - begin);
1147         alloc_len = size * elem_size;
1148
1149         vec = MEM_mallocN(alloc_len, "array assignment"); /* NOTE: we count on int/float being the same size here */
1150         if (PyC_AsArray(vec, seq, size, py_type, is_double, "slice assignment: ") == -1) {
1151                 MEM_freeN(vec);
1152                 return -1;
1153         }
1154
1155         memcpy((void *)(((char *)IDP_Array(prop)) + (begin * elem_size)), vec, alloc_len);
1156
1157         MEM_freeN(vec);
1158         return 0;
1159 }
1160
1161 static PyObject *BPy_IDArray_subscript(BPy_IDArray *self, PyObject *item)
1162 {
1163         if (PyIndex_Check(item)) {
1164                 Py_ssize_t i;
1165                 i = PyNumber_AsSsize_t(item, PyExc_IndexError);
1166                 if (i == -1 && PyErr_Occurred())
1167                         return NULL;
1168                 if (i < 0)
1169                         i += self->prop->len;
1170                 return BPy_IDArray_GetItem(self, i);
1171         }
1172         else if (PySlice_Check(item)) {
1173                 Py_ssize_t start, stop, step, slicelength;
1174
1175                 if (PySlice_GetIndicesEx((void *)item, self->prop->len, &start, &stop, &step, &slicelength) < 0)
1176                         return NULL;
1177
1178                 if (slicelength <= 0) {
1179                         return PyTuple_New(0);
1180                 }
1181                 else if (step == 1) {
1182                         return BPy_IDArray_slice(self, start, stop);
1183                 }
1184                 else {
1185                         PyErr_SetString(PyExc_TypeError, "slice steps not supported with vectors");
1186                         return NULL;
1187                 }
1188         }
1189         else {
1190                 PyErr_Format(PyExc_TypeError,
1191                              "vector indices must be integers, not %.200s",
1192                              __func__, Py_TYPE(item)->tp_name);
1193                 return NULL;
1194         }
1195 }
1196
1197 static int BPy_IDArray_ass_subscript(BPy_IDArray *self, PyObject *item, PyObject *value)
1198 {
1199         if (PyIndex_Check(item)) {
1200                 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
1201                 if (i == -1 && PyErr_Occurred())
1202                         return -1;
1203                 if (i < 0)
1204                         i += self->prop->len;
1205                 return BPy_IDArray_SetItem(self, i, value);
1206         }
1207         else if (PySlice_Check(item)) {
1208                 Py_ssize_t start, stop, step, slicelength;
1209
1210                 if (PySlice_GetIndicesEx((void *)item, self->prop->len, &start, &stop, &step, &slicelength) < 0)
1211                         return -1;
1212
1213                 if (step == 1)
1214                         return BPy_IDArray_ass_slice(self, start, stop, value);
1215                 else {
1216                         PyErr_SetString(PyExc_TypeError, "slice steps not supported with vectors");
1217                         return -1;
1218                 }
1219         }
1220         else {
1221                 PyErr_Format(PyExc_TypeError,
1222                              "vector indices must be integers, not %.200s",
1223                              Py_TYPE(item)->tp_name);
1224                 return -1;
1225         }
1226 }
1227
1228 static PyMappingMethods BPy_IDArray_AsMapping = {
1229         (lenfunc)BPy_IDArray_Len,
1230         (binaryfunc)BPy_IDArray_subscript,
1231         (objobjargproc)BPy_IDArray_ass_subscript
1232 };
1233
1234
1235 PyTypeObject BPy_IDArray_Type = {
1236         PyVarObject_HEAD_INIT(NULL, 0)
1237         /*  For printing, in format "<module>.<name>" */
1238         "Blender IDArray",           /* char *tp_name; */
1239         sizeof(BPy_IDArray),       /* int tp_basicsize; */
1240         0,                          /* tp_itemsize;  For allocation */
1241
1242         /* Methods to implement standard operations */
1243
1244         NULL,                       /* destructor tp_dealloc; */
1245         NULL,                       /* printfunc tp_print; */
1246         NULL,     /* getattrfunc tp_getattr; */
1247         NULL,     /* setattrfunc tp_setattr; */
1248         NULL,                       /* cmpfunc tp_compare; */
1249         (reprfunc)BPy_IDArray_repr,     /* reprfunc tp_repr; */
1250
1251         /* Method suites for standard classes */
1252
1253         NULL,                       /* PyNumberMethods *tp_as_number; */
1254         &BPy_IDArray_Seq,           /* PySequenceMethods *tp_as_sequence; */
1255         &BPy_IDArray_AsMapping,     /* PyMappingMethods *tp_as_mapping; */
1256
1257         /* More standard operations (here for binary compatibility) */
1258
1259         NULL,                       /* hashfunc tp_hash; */
1260         NULL,                       /* ternaryfunc tp_call; */
1261         NULL,                       /* reprfunc tp_str; */
1262         NULL,                       /* getattrofunc tp_getattro; */
1263         NULL,                       /* setattrofunc tp_setattro; */
1264
1265         /* Functions to access object as input/output buffer */
1266         NULL,                       /* PyBufferProcs *tp_as_buffer; */
1267
1268         /*** Flags to define presence of optional/expanded features ***/
1269         Py_TPFLAGS_DEFAULT,         /* long tp_flags; */
1270
1271         NULL,                       /*  char *tp_doc;  Documentation string */
1272         /*** Assigned meaning in release 2.0 ***/
1273         /* call function for all accessible objects */
1274         NULL,                       /* traverseproc tp_traverse; */
1275
1276         /* delete references to contained objects */
1277         NULL,                       /* inquiry tp_clear; */
1278
1279         /***  Assigned meaning in release 2.1 ***/
1280         /*** rich comparisons ***/
1281         NULL,                       /* richcmpfunc tp_richcompare; */
1282
1283         /***  weak reference enabler ***/
1284         0,                          /* long tp_weaklistoffset; */
1285
1286         /*** Added in release 2.2 ***/
1287         /*   Iterators */
1288         NULL,                       /* getiterfunc tp_iter; */
1289         NULL,                       /* iternextfunc tp_iternext; */
1290
1291         /*** Attribute descriptor and subclassing stuff ***/
1292         BPy_IDArray_methods,        /* struct PyMethodDef *tp_methods; */
1293         NULL,                       /* struct PyMemberDef *tp_members; */
1294         BPy_IDArray_getseters,       /* struct PyGetSetDef *tp_getset; */
1295         NULL,                       /* struct _typeobject *tp_base; */
1296         NULL,                       /* PyObject *tp_dict; */
1297         NULL,                       /* descrgetfunc tp_descr_get; */
1298         NULL,                       /* descrsetfunc tp_descr_set; */
1299         0,                          /* long tp_dictoffset; */
1300         NULL,                       /* initproc tp_init; */
1301         NULL,                       /* allocfunc tp_alloc; */
1302         NULL,                       /* newfunc tp_new; */
1303         /*  Low-level free-memory routine */
1304         NULL,                       /* freefunc tp_free;  */
1305         /* For PyObject_IS_GC */
1306         NULL,                       /* inquiry tp_is_gc;  */
1307         NULL,                       /* PyObject *tp_bases; */
1308         /* method resolution order */
1309         NULL,                       /* PyObject *tp_mro;  */
1310         NULL,                       /* PyObject *tp_cache; */
1311         NULL,                       /* PyObject *tp_subclasses; */
1312         NULL,                       /* PyObject *tp_weaklist; */
1313         NULL
1314 };
1315
1316 /*********** ID Property Group iterator ********/
1317
1318 static PyObject *IDGroup_Iter_repr(BPy_IDGroup_Iter *self)
1319 {
1320         return PyUnicode_FromFormat("(ID Property Group Iter \"%s\")", self->group->prop->name);
1321 }
1322
1323 static PyObject *BPy_Group_Iter_Next(BPy_IDGroup_Iter *self)
1324 {
1325
1326         if (self->cur) {
1327                 PyObject *ret;
1328                 IDProperty *cur;
1329
1330                 cur = self->cur;
1331                 self->cur = self->cur->next;
1332
1333                 if (self->mode == IDPROP_ITER_ITEMS) {
1334                         ret = PyTuple_New(2);
1335                         PyTuple_SET_ITEM(ret, 0, PyUnicode_FromString(cur->name));
1336                         PyTuple_SET_ITEM(ret, 1, BPy_IDGroup_WrapData(self->group->id, cur, self->group->prop));
1337                         return ret;
1338                 }
1339                 else {
1340                         return PyUnicode_FromString(cur->name);
1341                 }
1342         }
1343         else {
1344                 PyErr_SetString(PyExc_StopIteration, "iterator at end");
1345                 return NULL;
1346         }
1347 }
1348
1349 PyTypeObject BPy_IDGroup_Iter_Type = {
1350         PyVarObject_HEAD_INIT(NULL, 0)
1351         /*  For printing, in format "<module>.<name>" */
1352         "Blender IDGroup_Iter",           /* char *tp_name; */
1353         sizeof(BPy_IDGroup_Iter),       /* int tp_basicsize; */
1354         0,                          /* tp_itemsize;  For allocation */
1355
1356         /* Methods to implement standard operations */
1357
1358         NULL,                       /* destructor tp_dealloc; */
1359         NULL,                       /* printfunc tp_print; */
1360         NULL,     /* getattrfunc tp_getattr; */
1361         NULL,     /* setattrfunc tp_setattr; */
1362         NULL,                       /* cmpfunc tp_compare; */
1363         (reprfunc) IDGroup_Iter_repr,     /* reprfunc tp_repr; */
1364
1365         /* Method suites for standard classes */
1366
1367         NULL,                       /* PyNumberMethods *tp_as_number; */
1368         NULL,                       /* PySequenceMethods *tp_as_sequence; */
1369         NULL,                       /* PyMappingMethods *tp_as_mapping; */
1370
1371         /* More standard operations (here for binary compatibility) */
1372
1373         NULL,                       /* hashfunc tp_hash; */
1374         NULL,                       /* ternaryfunc tp_call; */
1375         NULL,                       /* reprfunc tp_str; */
1376         NULL,                       /* getattrofunc tp_getattro; */
1377         NULL,                       /* setattrofunc tp_setattro; */
1378
1379         /* Functions to access object as input/output buffer */
1380         NULL,                       /* PyBufferProcs *tp_as_buffer; */
1381
1382         /*** Flags to define presence of optional/expanded features ***/
1383         Py_TPFLAGS_DEFAULT,         /* long tp_flags; */
1384
1385         NULL,                       /*  char *tp_doc;  Documentation string */
1386         /*** Assigned meaning in release 2.0 ***/
1387         /* call function for all accessible objects */
1388         NULL,                       /* traverseproc tp_traverse; */
1389
1390         /* delete references to contained objects */
1391         NULL,                       /* inquiry tp_clear; */
1392
1393         /***  Assigned meaning in release 2.1 ***/
1394         /*** rich comparisons ***/
1395         NULL,                       /* richcmpfunc tp_richcompare; */
1396
1397         /***  weak reference enabler ***/
1398         0,                          /* long tp_weaklistoffset; */
1399
1400         /*** Added in release 2.2 ***/
1401         /*   Iterators */
1402         PyObject_SelfIter,                  /* getiterfunc tp_iter; */
1403         (iternextfunc) BPy_Group_Iter_Next, /* iternextfunc tp_iternext; */
1404 };
1405
1406 void IDProp_Init_Types(void)
1407 {
1408         PyType_Ready(&BPy_IDGroup_Type);
1409         PyType_Ready(&BPy_IDGroup_Iter_Type);
1410         PyType_Ready(&BPy_IDArray_Type);
1411 }