2 * ***** BEGIN GPL LICENSE BLOCK *****
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.
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.
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.
19 * Contributor(s): Joseph Eagar, Campbell Barton
21 * ***** END GPL LICENSE BLOCK *****
24 /** \file blender/python/generic/idprop_py_api.c
30 #include "MEM_guardedalloc.h"
32 #include "BLI_utildefines.h"
34 #include "idprop_py_api.h"
36 #include "BKE_idprop.h"
38 #define USE_STRING_COERCE
40 #ifdef USE_STRING_COERCE
41 #include "py_capi_utils.h"
44 #include "python_utildefines.h"
47 /*********************** ID Property Main Wrapper Stuff ***************/
49 /* ----------------------------------------------------------------------------
50 * static conversion functions to avoid duplicate code, no type checking.
53 static PyObject *idprop_py_from_idp_string(const IDProperty *prop)
55 if (prop->subtype == IDP_STRING_SUB_BYTE) {
56 return PyBytes_FromStringAndSize(IDP_String(prop), prop->len);
59 #ifdef USE_STRING_COERCE
60 return PyC_UnicodeFromByteAndSize(IDP_Array(prop), prop->len - 1);
62 return PyUnicode_FromStringAndSize(IDP_String(prop), prop->len - 1);
67 static PyObject *idprop_py_from_idp_int(const IDProperty *prop)
69 return PyLong_FromLong((long)IDP_Int(prop));
72 static PyObject *idprop_py_from_idp_float(const IDProperty *prop)
74 return PyFloat_FromDouble((double)IDP_Float(prop));
77 static PyObject *idprop_py_from_idp_double(const IDProperty *prop)
79 return PyFloat_FromDouble(IDP_Double(prop));
82 static PyObject *idprop_py_from_idp_group(ID *id, IDProperty *prop, IDProperty *parent)
84 BPy_IDProperty *group = PyObject_New(BPy_IDProperty, &BPy_IDGroup_Type);
87 group->parent = parent; /* can be NULL */
88 return (PyObject *)group;
91 static PyObject *idprop_py_from_idp_array(ID *id, IDProperty *prop)
93 BPy_IDProperty *array = PyObject_New(BPy_IDProperty, &BPy_IDArray_Type);
96 return (PyObject *)array;
99 static PyObject *idprop_py_from_idp_idparray(ID *id, IDProperty *prop)
101 PyObject *seq = PyList_New(prop->len);
102 IDProperty *array = IDP_IDPArray(prop);
106 PyErr_Format(PyExc_RuntimeError,
107 "%s: IDP_IDPARRAY: PyList_New(%d) failed",
108 __func__, prop->len);
112 for (i = 0; i < prop->len; i++) {
113 PyObject *wrap = BPy_IDGroup_WrapData(id, array++, prop);
115 /* BPy_IDGroup_MapDataToPy sets the error */
116 if (UNLIKELY(wrap == NULL)) {
121 PyList_SET_ITEM(seq, i, wrap);
127 /* -------------------------------------------------------------------------- */
129 /* use for both array and group */
130 static Py_hash_t BPy_IDGroup_hash(BPy_IDProperty *self)
132 return _Py_HashPointer(self->prop);
135 static PyObject *BPy_IDGroup_repr(BPy_IDProperty *self)
137 return PyUnicode_FromFormat("<bpy id prop: owner=\"%s\", name=\"%s\", address=%p>",
138 self->id ? self->id->name : "<NONE>", self->prop->name, self->prop);
141 PyObject *BPy_IDGroup_WrapData(ID *id, IDProperty *prop, IDProperty *parent)
143 switch (prop->type) {
144 case IDP_STRING: return idprop_py_from_idp_string(prop);
145 case IDP_INT: return idprop_py_from_idp_int(prop);
146 case IDP_FLOAT: return idprop_py_from_idp_float(prop);
147 case IDP_DOUBLE: return idprop_py_from_idp_double(prop);
148 case IDP_GROUP: return idprop_py_from_idp_group(id, prop, parent);
149 case IDP_ARRAY: return idprop_py_from_idp_array(id, prop);
150 case IDP_IDPARRAY: return idprop_py_from_idp_idparray(id, prop); /* this could be better a internal type */
151 default: Py_RETURN_NONE;
155 #if 0 /* UNUSED, currently assignment overwrites into new properties, rather than setting in-place */
156 static int BPy_IDGroup_SetData(BPy_IDProperty *self, IDProperty *prop, PyObject *value)
158 switch (prop->type) {
162 if (!PyUnicode_Check(value)) {
163 PyErr_SetString(PyExc_TypeError, "expected a string!");
166 /* NOTE: if this code is enabled, bytes support needs to be added */
167 #ifdef USE_STRING_COERCE
170 PyObject *value_coerce = NULL;
172 st = (char *)PyC_UnicodeAsByte(value, &value_coerce);
173 alloc_len = strlen(st) + 1;
175 st = _PyUnicode_AsString(value);
176 IDP_ResizeArray(prop, alloc_len);
177 memcpy(IDP_Array(prop), st, alloc_len);
178 Py_XDECREF(value_coerce);
181 st = _PyUnicode_AsString(value);
182 IDP_ResizeArray(prop, strlen(st) + 1);
183 strcpy(IDP_Array(prop), st);
191 int ivalue = PyLong_AsSsize_t(value);
192 if (ivalue == -1 && PyErr_Occurred()) {
193 PyErr_SetString(PyExc_TypeError, "expected an int type");
196 IDP_Int(prop) = ivalue;
201 float fvalue = (float)PyFloat_AsDouble(value);
202 if (fvalue == -1 && PyErr_Occurred()) {
203 PyErr_SetString(PyExc_TypeError, "expected a float");
206 IDP_Float(self->prop) = fvalue;
211 double dvalue = PyFloat_AsDouble(value);
212 if (dvalue == -1 && PyErr_Occurred()) {
213 PyErr_SetString(PyExc_TypeError, "expected a float");
216 IDP_Double(self->prop) = dvalue;
220 PyErr_SetString(PyExc_AttributeError, "attempt to set read-only attribute!");
227 static PyObject *BPy_IDGroup_GetName(BPy_IDProperty *self, void *UNUSED(closure))
229 return PyUnicode_FromString(self->prop->name);
232 static int BPy_IDGroup_SetName(BPy_IDProperty *self, PyObject *value, void *UNUSED(closure))
235 Py_ssize_t name_size;
237 if (!PyUnicode_Check(value)) {
238 PyErr_SetString(PyExc_TypeError, "expected a string!");
242 name = _PyUnicode_AsStringAndSize(value, &name_size);
244 if (name_size > MAX_IDPROP_NAME) {
245 PyErr_SetString(PyExc_TypeError, "string length cannot exceed 63 characters!");
249 memcpy(self->prop->name, name, name_size);
254 static PyObject *BPy_IDGroup_GetType(BPy_IDProperty *self)
256 return PyLong_FromLong(self->prop->type);
260 static PyGetSetDef BPy_IDGroup_getseters[] = {
261 {(char *)"name", (getter)BPy_IDGroup_GetName, (setter)BPy_IDGroup_SetName, (char *)"The name of this Group.", NULL},
262 {NULL, NULL, NULL, NULL, NULL}
265 static Py_ssize_t BPy_IDGroup_Map_Len(BPy_IDProperty *self)
267 if (self->prop->type != IDP_GROUP) {
268 PyErr_SetString(PyExc_TypeError, "len() of unsized object");
272 return self->prop->len;
275 static PyObject *BPy_IDGroup_Map_GetItem(BPy_IDProperty *self, PyObject *item)
280 if (self->prop->type != IDP_GROUP) {
281 PyErr_SetString(PyExc_TypeError, "unsubscriptable object");
285 name = _PyUnicode_AsString(item);
288 PyErr_SetString(PyExc_TypeError, "only strings are allowed as keys of ID properties");
292 idprop = IDP_GetPropertyFromGroup(self->prop, name);
294 if (idprop == NULL) {
295 PyErr_SetString(PyExc_KeyError, "key not in subgroup dict");
299 return BPy_IDGroup_WrapData(self->id, idprop, self->prop);
302 /* returns NULL on success, error string on failure */
303 static char idp_sequence_type(PyObject *seq_fast)
305 PyObject **seq_fast_items = PySequence_Fast_ITEMS(seq_fast);
309 Py_ssize_t i, len = PySequence_Fast_GET_SIZE(seq_fast);
311 for (i = 0; i < len; i++) {
312 item = seq_fast_items[i];
313 if (PyFloat_Check(item)) {
314 if (type == IDP_IDPARRAY) { /* mixed dict/int */
319 else if (PyLong_Check(item)) {
320 if (type == IDP_IDPARRAY) { /* mixed dict/int */
324 else if (PyMapping_Check(item)) {
325 if (i != 0 && (type != IDP_IDPARRAY)) { /* mixed dict/int */
338 static const char *idp_try_read_name(PyObject *name_obj)
340 const char *name = NULL;
342 Py_ssize_t name_size;
343 name = _PyUnicode_AsStringAndSize(name_obj, &name_size);
346 PyErr_Format(PyExc_KeyError,
347 "invalid id-property key, expected a string, not a %.200s",
348 Py_TYPE(name_obj)->tp_name);
352 if (name_size > MAX_IDPROP_NAME) {
353 PyErr_SetString(PyExc_KeyError, "the length of IDProperty names is limited to 63 characters");
363 /* -------------------------------------------------------------------------- */
366 * The 'idp_from_Py*' functions expect that the input type has been checked before
367 * and return NULL if the IDProperty can't be created.
370 static IDProperty *idp_from_PyFloat(const char *name, PyObject *ob)
372 IDPropertyTemplate val = {0};
373 val.d = PyFloat_AsDouble(ob);
374 return IDP_New(IDP_DOUBLE, &val, name);
377 static IDProperty *idp_from_PyLong(const char *name, PyObject *ob)
379 IDPropertyTemplate val = {0};
380 val.i = _PyLong_AsInt(ob);
381 if (val.i == -1 && PyErr_Occurred()) {
384 return IDP_New(IDP_INT, &val, name);
387 static IDProperty *idp_from_PyUnicode(const char *name, PyObject *ob)
390 IDPropertyTemplate val = {0};
391 #ifdef USE_STRING_COERCE
392 Py_ssize_t value_size;
393 PyObject *value_coerce = NULL;
394 val.string.str = PyC_UnicodeAsByteAndSize(ob, &value_size, &value_coerce);
395 val.string.len = (int)value_size + 1;
396 val.string.subtype = IDP_STRING_SUB_UTF8;
397 prop = IDP_New(IDP_STRING, &val, name);
398 Py_XDECREF(value_coerce);
400 val.str = _PyUnicode_AsString(ob);
401 prop = IDP_New(IDP_STRING, val, name);
406 static IDProperty *idp_from_PyBytes(const char *name, PyObject *ob)
408 IDPropertyTemplate val = {0};
409 val.string.str = PyBytes_AS_STRING(ob);
410 val.string.len = PyBytes_GET_SIZE(ob);
411 val.string.subtype = IDP_STRING_SUB_BYTE;
412 return IDP_New(IDP_STRING, &val, name);
415 static int idp_array_type_from_format_char(char format)
417 if (format == 'i') return IDP_INT;
418 if (format == 'f') return IDP_FLOAT;
419 if (format == 'd') return IDP_DOUBLE;
423 static const char *idp_format_from_array_type(int type)
425 if (type == IDP_INT) return "i";
426 if (type == IDP_FLOAT) return "f";
427 if (type == IDP_DOUBLE) return "d";
431 static IDProperty *idp_from_PySequence_Buffer(const char *name, Py_buffer *buffer)
434 IDPropertyTemplate val = {0};
436 int format = idp_array_type_from_format_char(*buffer->format);
438 /* should never happen as the type has been checked before */
442 val.array.type = format;
443 val.array.len = buffer->len / buffer->itemsize;
445 prop = IDP_New(IDP_ARRAY, &val, name);
446 memcpy(IDP_Array(prop), buffer->buf, buffer->len);
450 static IDProperty *idp_from_PySequence_Fast(const char *name, PyObject *ob)
453 IDPropertyTemplate val = {0};
455 PyObject **ob_seq_fast_items;
459 ob_seq_fast_items = PySequence_Fast_ITEMS(ob);
461 if ((val.array.type = idp_sequence_type(ob)) == (char)-1) {
462 PyErr_SetString(PyExc_TypeError, "only floats, ints and dicts are allowed in ID property arrays");
466 /* validate sequence and derive type.
467 * we assume IDP_INT unless we hit a float
468 * number; then we assume it's */
470 val.array.len = PySequence_Fast_GET_SIZE(ob);
472 switch (val.array.type) {
476 prop = IDP_New(IDP_ARRAY, &val, name);
477 prop_data = IDP_Array(prop);
478 for (i = 0; i < val.array.len; i++) {
479 item = ob_seq_fast_items[i];
480 if (((prop_data[i] = PyFloat_AsDouble(item)) == -1.0) && PyErr_Occurred()) {
489 prop = IDP_New(IDP_ARRAY, &val, name);
490 prop_data = IDP_Array(prop);
491 for (i = 0; i < val.array.len; i++) {
492 item = ob_seq_fast_items[i];
493 if (((prop_data[i] = _PyLong_AsInt(item)) == -1) && PyErr_Occurred()) {
501 prop = IDP_NewIDPArray(name);
502 for (i = 0; i < val.array.len; i++) {
503 item = ob_seq_fast_items[i];
504 if (BPy_IDProperty_Map_ValidateAndCreate(NULL, prop, item) == false) {
511 /* should never happen */
512 PyErr_SetString(PyExc_RuntimeError, "internal error with idp array.type");
519 static IDProperty *idp_from_PySequence(const char *name, PyObject *ob)
522 bool use_buffer = false;
524 if (PyObject_CheckBuffer(ob)) {
525 PyObject_GetBuffer(ob, &buffer, PyBUF_SIMPLE | PyBUF_FORMAT);
526 char format = *buffer.format;
527 if (ELEM(format, 'i', 'f', 'd')) {
531 PyBuffer_Release(&buffer);
536 IDProperty *prop = idp_from_PySequence_Buffer(name, &buffer);
537 PyBuffer_Release(&buffer);
541 PyObject *ob_seq_fast = PySequence_Fast(ob, "py -> idprop");
542 if (ob_seq_fast != NULL) {
543 IDProperty *prop = idp_from_PySequence_Fast(name, ob_seq_fast);
544 Py_DECREF(ob_seq_fast);
553 static IDProperty *idp_from_PyMapping(const char *name, PyObject *ob)
556 IDPropertyTemplate val = {0};
558 PyObject *keys, *vals, *key, *pval;
560 /* yay! we get into recursive stuff now! */
561 keys = PyMapping_Keys(ob);
562 vals = PyMapping_Values(ob);
564 /* we allocate the group first; if we hit any invalid data,
565 * we can delete it easily enough.*/
566 prop = IDP_New(IDP_GROUP, &val, name);
567 len = PyMapping_Length(ob);
568 for (i = 0; i < len; i++) {
569 key = PySequence_GetItem(keys, i);
570 pval = PySequence_GetItem(vals, i);
571 if (BPy_IDProperty_Map_ValidateAndCreate(key, prop, pval) == false) {
572 IDP_FreeProperty(prop);
578 /* error is already set */
589 static IDProperty *idp_from_PyObject(PyObject *name_obj, PyObject *ob)
591 const char *name = idp_try_read_name(name_obj);
596 if (PyFloat_Check(ob)) {
597 return idp_from_PyFloat(name, ob);
599 else if (PyLong_Check(ob)) {
600 return idp_from_PyLong(name, ob);
602 else if (PyUnicode_Check(ob)) {
603 return idp_from_PyUnicode(name, ob);
605 else if (PyBytes_Check(ob)) {
606 return idp_from_PyBytes(name, ob);
608 else if (PySequence_Check(ob)) {
609 return idp_from_PySequence(name, ob);
611 else if (PyMapping_Check(ob)) {
612 return idp_from_PyMapping(name, ob);
615 PyErr_Format(PyExc_TypeError,
616 "invalid id-property type %.200s not supported",
617 Py_TYPE(ob)->tp_name);
622 /* -------------------------------------------------------------------------- */
625 * \note group can be a pointer array or a group.
626 * assume we already checked key is a string.
630 bool BPy_IDProperty_Map_ValidateAndCreate(PyObject *name_obj, IDProperty *group, PyObject *ob)
632 IDProperty *prop = idp_from_PyObject(name_obj, ob);
637 if (group->type == IDP_IDPARRAY) {
638 IDP_AppendArray(group, prop);
639 /* IDP_AppendArray does a shallow copy (memcpy), only free memory */
643 IDProperty *prop_exist;
645 /* avoid freeing when types match in case they are referenced by the UI, see: T37073
646 * obviously this isn't a complete solution, but helps for common cases. */
647 prop_exist = IDP_GetPropertyFromGroup(group, prop->name);
648 if ((prop_exist != NULL) &&
649 (prop_exist->type == prop->type) &&
650 (prop_exist->subtype == prop->subtype))
652 /* Preserve prev/next links!!! See T42593. */
653 prop->prev = prop_exist->prev;
654 prop->next = prop_exist->next;
656 IDP_FreeProperty(prop_exist);
661 IDP_ReplaceInGroup_ex(group, prop, prop_exist);
668 int BPy_Wrap_SetMapItem(IDProperty *prop, PyObject *key, PyObject *val)
670 if (prop->type != IDP_GROUP) {
671 PyErr_SetString(PyExc_TypeError, "unsubscriptable object");
675 if (val == NULL) { /* del idprop[key] */
677 const char *name = _PyUnicode_AsString(key);
680 PyErr_Format(PyExc_KeyError,
681 "expected a string, not %.200s",
682 Py_TYPE(key)->tp_name);
686 pkey = IDP_GetPropertyFromGroup(prop, name);
688 IDP_FreeFromGroup(prop, pkey);
692 PyErr_SetString(PyExc_KeyError, "property not found in group");
699 ok = BPy_IDProperty_Map_ValidateAndCreate(key, prop, val);
708 static int BPy_IDGroup_Map_SetItem(BPy_IDProperty *self, PyObject *key, PyObject *val)
710 return BPy_Wrap_SetMapItem(self->prop, key, val);
713 static PyObject *BPy_IDGroup_iter(BPy_IDProperty *self)
715 BPy_IDGroup_Iter *iter = PyObject_New(BPy_IDGroup_Iter, &BPy_IDGroup_Iter_Type);
717 iter->mode = IDPROP_ITER_KEYS;
718 iter->cur = self->prop->data.group.first;
720 return (PyObject *)iter;
723 /* for simple, non nested types this is the same as BPy_IDGroup_WrapData */
724 static PyObject *BPy_IDGroup_MapDataToPy(IDProperty *prop)
726 switch (prop->type) {
728 return idprop_py_from_idp_string(prop);
730 return idprop_py_from_idp_int(prop);
732 return idprop_py_from_idp_float(prop);
734 return idprop_py_from_idp_double(prop);
737 PyObject *seq = PyList_New(prop->len);
741 PyErr_Format(PyExc_RuntimeError,
742 "%s: IDP_ARRAY: PyList_New(%d) failed",
743 __func__, prop->len);
747 switch (prop->subtype) {
750 const float *array = (float *)IDP_Array(prop);
751 for (i = 0; i < prop->len; i++) {
752 PyList_SET_ITEM(seq, i, PyFloat_FromDouble(array[i]));
758 const double *array = (double *)IDP_Array(prop);
759 for (i = 0; i < prop->len; i++) {
760 PyList_SET_ITEM(seq, i, PyFloat_FromDouble(array[i]));
766 const int *array = (int *)IDP_Array(prop);
767 for (i = 0; i < prop->len; i++) {
768 PyList_SET_ITEM(seq, i, PyLong_FromLong(array[i]));
773 PyErr_Format(PyExc_RuntimeError,
774 "%s: invalid/corrupt array type '%d'!",
775 __func__, prop->subtype);
784 PyObject *seq = PyList_New(prop->len);
785 IDProperty *array = IDP_IDPArray(prop);
789 PyErr_Format(PyExc_RuntimeError,
790 "%s: IDP_IDPARRAY: PyList_New(%d) failed",
791 __func__, prop->len);
795 for (i = 0; i < prop->len; i++) {
796 PyObject *wrap = BPy_IDGroup_MapDataToPy(array++);
798 /* BPy_IDGroup_MapDataToPy sets the error */
799 if (UNLIKELY(wrap == NULL)) {
804 PyList_SET_ITEM(seq, i, wrap);
810 PyObject *dict = _PyDict_NewPresized(prop->len);
813 for (loop = prop->data.group.first; loop; loop = loop->next) {
814 PyObject *wrap = BPy_IDGroup_MapDataToPy(loop);
816 /* BPy_IDGroup_MapDataToPy sets the error */
817 if (UNLIKELY(wrap == NULL)) {
822 PyDict_SetItemString(dict, loop->name, wrap);
829 PyErr_Format(PyExc_RuntimeError,
830 "%s ERROR: '%s' property exists with a bad type code '%d'!",
831 __func__, prop->name, prop->type);
835 PyDoc_STRVAR(BPy_IDGroup_pop_doc,
836 ".. method:: pop(key)\n"
838 " Remove an item from the group, returning a Python representation.\n"
840 " :raises KeyError: When the item doesn't exist.\n"
842 " :arg key: Name of item to remove.\n"
843 " :type key: string\n"
845 static PyObject *BPy_IDGroup_pop(BPy_IDProperty *self, PyObject *value)
849 const char *name = _PyUnicode_AsString(value);
852 PyErr_Format(PyExc_TypeError,
853 "pop expected at least a string argument, not %.200s",
854 Py_TYPE(value)->tp_name);
858 idprop = IDP_GetPropertyFromGroup(self->prop, name);
861 pyform = BPy_IDGroup_MapDataToPy(idprop);
864 /* ok something bad happened with the pyobject,
865 * so don't remove the prop from the group. if pyform is
866 * NULL, then it already should have raised an exception.*/
870 IDP_RemoveFromGroup(self->prop, idprop);
874 PyErr_SetString(PyExc_KeyError, "item not in group");
878 PyDoc_STRVAR(BPy_IDGroup_iter_items_doc,
879 ".. method:: iteritems()\n"
881 " Iterate through the items in the dict; behaves like dictionary method iteritems.\n"
883 static PyObject *BPy_IDGroup_iter_items(BPy_IDProperty *self)
885 BPy_IDGroup_Iter *iter = PyObject_New(BPy_IDGroup_Iter, &BPy_IDGroup_Iter_Type);
887 iter->mode = IDPROP_ITER_ITEMS;
888 iter->cur = self->prop->data.group.first;
890 return (PyObject *)iter;
893 /* utility function */
894 static void BPy_IDGroup_CorrectListLen(IDProperty *prop, PyObject *seq, int len, const char *func)
898 printf("%s: ID Property Error found and corrected!\n", func);
900 /* fill rest of list with valid references to None */
901 for (j = len; j < prop->len; j++) {
902 PyList_SET_ITEM(seq, j, Py_INCREF_RET(Py_None));
905 /*set correct group length*/
909 PyObject *BPy_Wrap_GetKeys(IDProperty *prop)
911 PyObject *list = PyList_New(prop->len);
915 for (i = 0, loop = prop->data.group.first; loop && (i < prop->len); loop = loop->next, i++)
916 PyList_SET_ITEM(list, i, PyUnicode_FromString(loop->name));
918 /* if the id prop is corrupt, count the remaining */
919 for ( ; loop; loop = loop->next, i++) {
923 if (i != prop->len) { /* if the loop didnt finish, we know the length is wrong */
924 BPy_IDGroup_CorrectListLen(prop, list, i, __func__);
925 Py_DECREF(list); /*free the list*/
927 return BPy_Wrap_GetKeys(prop);
933 PyObject *BPy_Wrap_GetValues(ID *id, IDProperty *prop)
935 PyObject *list = PyList_New(prop->len);
939 for (i = 0, loop = prop->data.group.first; loop; loop = loop->next, i++) {
940 PyList_SET_ITEM(list, i, BPy_IDGroup_WrapData(id, loop, prop));
943 if (i != prop->len) {
944 BPy_IDGroup_CorrectListLen(prop, list, i, __func__);
945 Py_DECREF(list); /*free the list*/
947 return BPy_Wrap_GetValues(id, prop);
953 PyObject *BPy_Wrap_GetItems(ID *id, IDProperty *prop)
955 PyObject *seq = PyList_New(prop->len);
959 for (i = 0, loop = prop->data.group.first; loop; loop = loop->next, i++) {
960 PyObject *item = PyTuple_New(2);
961 PyTuple_SET_ITEMS(item,
962 PyUnicode_FromString(loop->name),
963 BPy_IDGroup_WrapData(id, loop, prop));
964 PyList_SET_ITEM(seq, i, item);
967 if (i != prop->len) {
968 BPy_IDGroup_CorrectListLen(prop, seq, i, __func__);
969 Py_DECREF(seq); /*free the list*/
971 return BPy_Wrap_GetItems(id, prop);
977 PyDoc_STRVAR(BPy_IDGroup_keys_doc,
978 ".. method:: keys()\n"
980 " Return the keys associated with this group as a list of strings.\n"
982 static PyObject *BPy_IDGroup_keys(BPy_IDProperty *self)
984 return BPy_Wrap_GetKeys(self->prop);
987 PyDoc_STRVAR(BPy_IDGroup_values_doc,
988 ".. method:: values()\n"
990 " Return the values associated with this group.\n"
992 static PyObject *BPy_IDGroup_values(BPy_IDProperty *self)
994 return BPy_Wrap_GetValues(self->id, self->prop);
997 PyDoc_STRVAR(BPy_IDGroup_items_doc,
998 ".. method:: items()\n"
1000 " Return the items associated with this group.\n"
1002 static PyObject *BPy_IDGroup_items(BPy_IDProperty *self)
1004 return BPy_Wrap_GetItems(self->id, self->prop);
1007 static int BPy_IDGroup_Contains(BPy_IDProperty *self, PyObject *value)
1009 const char *name = _PyUnicode_AsString(value);
1012 PyErr_Format(PyExc_TypeError,
1013 "expected a string, not a %.200s",
1014 Py_TYPE(value)->tp_name);
1018 return IDP_GetPropertyFromGroup(self->prop, name) ? 1 : 0;
1021 PyDoc_STRVAR(BPy_IDGroup_update_doc,
1022 ".. method:: update(other)\n"
1024 " Update key, values.\n"
1026 " :arg other: Updates the values in the group with this.\n"
1027 " :type other: :class:`IDPropertyGroup` or dict\n"
1029 static PyObject *BPy_IDGroup_update(BPy_IDProperty *self, PyObject *value)
1031 PyObject *pkey, *pval;
1034 if (BPy_IDGroup_Check(value)) {
1035 BPy_IDProperty *other = (BPy_IDProperty *)value;
1036 if (UNLIKELY(self->prop == other->prop)) {
1040 /* XXX, possible one is inside the other */
1041 IDP_MergeGroup(self->prop, other->prop, true);
1043 else if (PyDict_Check(value)) {
1044 while (PyDict_Next(value, &i, &pkey, &pval)) {
1045 BPy_IDGroup_Map_SetItem(self, pkey, pval);
1046 if (PyErr_Occurred()) return NULL;
1050 PyErr_Format(PyExc_TypeError,
1051 "expected a dict or an IDPropertyGroup type, not a %.200s",
1052 Py_TYPE(value)->tp_name);
1060 PyDoc_STRVAR(BPy_IDGroup_to_dict_doc,
1061 ".. method:: to_dict()\n"
1063 " Return a purely python version of the group.\n"
1065 static PyObject *BPy_IDGroup_to_dict(BPy_IDProperty *self)
1067 return BPy_IDGroup_MapDataToPy(self->prop);
1070 PyDoc_STRVAR(BPy_IDGroup_clear_doc,
1071 ".. method:: clear()\n"
1073 " Clear all members from this group.\n"
1075 static PyObject *BPy_IDGroup_clear(BPy_IDProperty *self)
1077 IDP_ClearProperty(self->prop);
1081 PyDoc_STRVAR(BPy_IDGroup_get_doc,
1082 ".. method:: get(key, default=None)\n"
1084 " Return the value for key, if it exists, else default.\n"
1086 static PyObject *BPy_IDGroup_get(BPy_IDProperty *self, PyObject *args)
1090 PyObject *def = Py_None;
1092 if (!PyArg_ParseTuple(args, "s|O:get", &key, &def))
1095 idprop = IDP_GetPropertyFromGroup(self->prop, key);
1097 PyObject *pyobj = BPy_IDGroup_WrapData(self->id, idprop, self->prop);
1106 static struct PyMethodDef BPy_IDGroup_methods[] = {
1107 {"pop", (PyCFunction)BPy_IDGroup_pop, METH_O, BPy_IDGroup_pop_doc},
1108 {"iteritems", (PyCFunction)BPy_IDGroup_iter_items, METH_NOARGS, BPy_IDGroup_iter_items_doc},
1109 {"keys", (PyCFunction)BPy_IDGroup_keys, METH_NOARGS, BPy_IDGroup_keys_doc},
1110 {"values", (PyCFunction)BPy_IDGroup_values, METH_NOARGS, BPy_IDGroup_values_doc},
1111 {"items", (PyCFunction)BPy_IDGroup_items, METH_NOARGS, BPy_IDGroup_items_doc},
1112 {"update", (PyCFunction)BPy_IDGroup_update, METH_O, BPy_IDGroup_update_doc},
1113 {"get", (PyCFunction)BPy_IDGroup_get, METH_VARARGS, BPy_IDGroup_get_doc},
1114 {"to_dict", (PyCFunction)BPy_IDGroup_to_dict, METH_NOARGS, BPy_IDGroup_to_dict_doc},
1115 {"clear", (PyCFunction)BPy_IDGroup_clear, METH_NOARGS, BPy_IDGroup_clear_doc},
1116 {NULL, NULL, 0, NULL}
1119 static PySequenceMethods BPy_IDGroup_Seq = {
1120 (lenfunc) BPy_IDGroup_Map_Len, /* lenfunc sq_length */
1121 NULL, /* binaryfunc sq_concat */
1122 NULL, /* ssizeargfunc sq_repeat */
1123 NULL, /* ssizeargfunc sq_item */ /* TODO - setting this will allow PySequence_Check to return True */
1124 NULL, /* intintargfunc ***was_sq_slice*** */
1125 NULL, /* intobjargproc sq_ass_item */
1126 NULL, /* ssizeobjargproc ***was_sq_ass_slice*** */
1127 (objobjproc) BPy_IDGroup_Contains, /* objobjproc sq_contains */
1128 NULL, /* binaryfunc sq_inplace_concat */
1129 NULL, /* ssizeargfunc sq_inplace_repeat */
1132 static PyMappingMethods BPy_IDGroup_Mapping = {
1133 (lenfunc)BPy_IDGroup_Map_Len, /*inquiry mp_length */
1134 (binaryfunc)BPy_IDGroup_Map_GetItem, /*binaryfunc mp_subscript */
1135 (objobjargproc)BPy_IDGroup_Map_SetItem, /*objobjargproc mp_ass_subscript */
1138 PyTypeObject BPy_IDGroup_Type = {
1139 PyVarObject_HEAD_INIT(NULL, 0)
1140 /* For printing, in format "<module>.<name>" */
1141 "IDPropertyGroup", /* char *tp_name; */
1142 sizeof(BPy_IDProperty), /* int tp_basicsize; */
1143 0, /* tp_itemsize; For allocation */
1145 /* Methods to implement standard operations */
1147 NULL, /* destructor tp_dealloc; */
1148 NULL, /* printfunc tp_print; */
1149 NULL, /* getattrfunc tp_getattr; */
1150 NULL, /* setattrfunc tp_setattr; */
1151 NULL, /* cmpfunc tp_compare; */
1152 (reprfunc)BPy_IDGroup_repr, /* reprfunc tp_repr; */
1154 /* Method suites for standard classes */
1156 NULL, /* PyNumberMethods *tp_as_number; */
1157 &BPy_IDGroup_Seq, /* PySequenceMethods *tp_as_sequence; */
1158 &BPy_IDGroup_Mapping, /* PyMappingMethods *tp_as_mapping; */
1160 /* More standard operations (here for binary compatibility) */
1162 (hashfunc)BPy_IDGroup_hash, /* hashfunc tp_hash; */
1163 NULL, /* ternaryfunc tp_call; */
1164 NULL, /* reprfunc tp_str; */
1165 NULL, /* getattrofunc tp_getattro; */
1166 NULL, /* setattrofunc tp_setattro; */
1168 /* Functions to access object as input/output buffer */
1169 NULL, /* PyBufferProcs *tp_as_buffer; */
1171 /*** Flags to define presence of optional/expanded features ***/
1172 Py_TPFLAGS_DEFAULT, /* long tp_flags; */
1174 NULL, /* char *tp_doc; Documentation string */
1175 /*** Assigned meaning in release 2.0 ***/
1176 /* call function for all accessible objects */
1177 NULL, /* traverseproc tp_traverse; */
1179 /* delete references to contained objects */
1180 NULL, /* inquiry tp_clear; */
1182 /*** Assigned meaning in release 2.1 ***/
1183 /*** rich comparisons ***/
1184 NULL, /* richcmpfunc tp_richcompare; */
1186 /*** weak reference enabler ***/
1187 0, /* long tp_weaklistoffset; */
1189 /*** Added in release 2.2 ***/
1191 (getiterfunc)BPy_IDGroup_iter, /* getiterfunc tp_iter; */
1192 NULL, /* iternextfunc tp_iternext; */
1193 /*** Attribute descriptor and subclassing stuff ***/
1194 BPy_IDGroup_methods, /* struct PyMethodDef *tp_methods; */
1195 NULL, /* struct PyMemberDef *tp_members; */
1196 BPy_IDGroup_getseters, /* struct PyGetSetDef *tp_getset; */
1199 /********Array Wrapper********/
1201 static PyTypeObject *idp_array_py_type(BPy_IDArray *self, bool *r_is_double)
1203 switch (self->prop->subtype) {
1205 *r_is_double = false;
1206 return &PyFloat_Type;
1208 *r_is_double = true;
1209 return &PyFloat_Type;
1211 *r_is_double = false;
1212 return &PyLong_Type;
1214 *r_is_double = false;
1219 static PyObject *BPy_IDArray_repr(BPy_IDArray *self)
1221 return PyUnicode_FromFormat("<bpy id property array [%d]>", self->prop->len);
1224 PyDoc_STRVAR(BPy_IDArray_get_typecode_doc,
1225 "The type of the data in the array {'f': float, 'd': double, 'i': int}."
1227 static PyObject *BPy_IDArray_get_typecode(BPy_IDArray *self)
1229 switch (self->prop->subtype) {
1230 case IDP_FLOAT: return PyUnicode_FromString("f");
1231 case IDP_DOUBLE: return PyUnicode_FromString("d");
1232 case IDP_INT: return PyUnicode_FromString("i");
1235 PyErr_Format(PyExc_RuntimeError,
1236 "%s: invalid/corrupt array type '%d'!",
1237 __func__, self->prop->subtype);
1242 static PyGetSetDef BPy_IDArray_getseters[] = {
1243 /* matches pythons array.typecode */
1244 {(char *)"typecode", (getter)BPy_IDArray_get_typecode, (setter)NULL, BPy_IDArray_get_typecode_doc, NULL},
1245 {NULL, NULL, NULL, NULL, NULL},
1248 PyDoc_STRVAR(BPy_IDArray_to_list_doc,
1249 ".. method:: to_list()\n"
1251 " Return the array as a list.\n"
1253 static PyObject *BPy_IDArray_to_list(BPy_IDArray *self)
1255 return BPy_IDGroup_MapDataToPy(self->prop);
1258 static PyMethodDef BPy_IDArray_methods[] = {
1259 {"to_list", (PyCFunction)BPy_IDArray_to_list, METH_NOARGS, BPy_IDArray_to_list_doc},
1260 {NULL, NULL, 0, NULL}
1263 static int BPy_IDArray_Len(BPy_IDArray *self)
1265 return self->prop->len;
1268 static PyObject *BPy_IDArray_GetItem(BPy_IDArray *self, int index)
1270 if (index < 0 || index >= self->prop->len) {
1271 PyErr_SetString(PyExc_IndexError, "index out of range!");
1275 switch (self->prop->subtype) {
1277 return PyFloat_FromDouble(((float *)IDP_Array(self->prop))[index]);
1279 return PyFloat_FromDouble(((double *)IDP_Array(self->prop))[index]);
1281 return PyLong_FromLong((long)((int *)IDP_Array(self->prop))[index]);
1284 PyErr_Format(PyExc_RuntimeError,
1285 "%s: invalid/corrupt array type '%d'!",
1286 __func__, self->prop->subtype);
1291 static int BPy_IDArray_SetItem(BPy_IDArray *self, int index, PyObject *value)
1293 if (index < 0 || index >= self->prop->len) {
1294 PyErr_SetString(PyExc_RuntimeError, "index out of range!");
1298 switch (self->prop->subtype) {
1301 const float f = (float)PyFloat_AsDouble(value);
1302 if (f == -1 && PyErr_Occurred()) {
1305 ((float *)IDP_Array(self->prop))[index] = f;
1310 const double d = PyFloat_AsDouble(value);
1311 if (d == -1 && PyErr_Occurred()) {
1314 ((double *)IDP_Array(self->prop))[index] = d;
1319 const int i = _PyLong_AsInt(value);
1320 if (i == -1 && PyErr_Occurred()) {
1324 ((int *)IDP_Array(self->prop))[index] = i;
1331 static PySequenceMethods BPy_IDArray_Seq = {
1332 (lenfunc) BPy_IDArray_Len, /* inquiry sq_length */
1333 NULL, /* binaryfunc sq_concat */
1334 NULL, /* intargfunc sq_repeat */
1335 (ssizeargfunc)BPy_IDArray_GetItem, /* intargfunc sq_item */
1336 NULL, /* intintargfunc sq_slice */
1337 (ssizeobjargproc)BPy_IDArray_SetItem, /* intobjargproc sq_ass_item */
1338 NULL, /* intintobjargproc sq_ass_slice */
1339 NULL, /* objobjproc sq_contains */
1340 /* Added in release 2.0 */
1341 NULL, /* binaryfunc sq_inplace_concat */
1342 NULL, /* intargfunc sq_inplace_repeat */
1347 /* sequence slice (get): idparr[a:b] */
1348 static PyObject *BPy_IDArray_slice(BPy_IDArray *self, int begin, int end)
1350 IDProperty *prop = self->prop;
1354 CLAMP(begin, 0, prop->len);
1355 if (end < 0) end = prop->len + end + 1;
1356 CLAMP(end, 0, prop->len);
1357 begin = MIN2(begin, end);
1359 tuple = PyTuple_New(end - begin);
1361 switch (prop->subtype) {
1364 const float *array = (float *)IDP_Array(prop);
1365 for (count = begin; count < end; count++) {
1366 PyTuple_SET_ITEM(tuple, count - begin, PyFloat_FromDouble(array[count]));
1372 const double *array = (double *)IDP_Array(prop);
1373 for (count = begin; count < end; count++) {
1374 PyTuple_SET_ITEM(tuple, count - begin, PyFloat_FromDouble(array[count]));
1380 const int *array = (int *)IDP_Array(prop);
1381 for (count = begin; count < end; count++) {
1382 PyTuple_SET_ITEM(tuple, count - begin, PyLong_FromLong(array[count]));
1390 /* sequence slice (set): idparr[a:b] = value */
1391 static int BPy_IDArray_ass_slice(BPy_IDArray *self, int begin, int end, PyObject *seq)
1393 IDProperty *prop = self->prop;
1395 const PyTypeObject *py_type = idp_array_py_type(self, &is_double);
1396 const size_t elem_size = is_double ? sizeof(double) : sizeof(float);
1401 CLAMP(begin, 0, prop->len);
1402 CLAMP(end, 0, prop->len);
1403 begin = MIN2(begin, end);
1405 size = (end - begin);
1406 alloc_len = size * elem_size;
1408 vec = MEM_mallocN(alloc_len, "array assignment"); /* NOTE: we count on int/float being the same size here */
1409 if (PyC_AsArray(vec, seq, size, py_type, is_double, "slice assignment: ") == -1) {
1414 memcpy((void *)(((char *)IDP_Array(prop)) + (begin * elem_size)), vec, alloc_len);
1420 static PyObject *BPy_IDArray_subscript(BPy_IDArray *self, PyObject *item)
1422 if (PyIndex_Check(item)) {
1424 i = PyNumber_AsSsize_t(item, PyExc_IndexError);
1425 if (i == -1 && PyErr_Occurred())
1428 i += self->prop->len;
1429 return BPy_IDArray_GetItem(self, i);
1431 else if (PySlice_Check(item)) {
1432 Py_ssize_t start, stop, step, slicelength;
1434 if (PySlice_GetIndicesEx(item, self->prop->len, &start, &stop, &step, &slicelength) < 0)
1437 if (slicelength <= 0) {
1438 return PyTuple_New(0);
1440 else if (step == 1) {
1441 return BPy_IDArray_slice(self, start, stop);
1444 PyErr_SetString(PyExc_TypeError, "slice steps not supported with vectors");
1449 PyErr_Format(PyExc_TypeError,
1450 "vector indices must be integers, not %.200s",
1451 __func__, Py_TYPE(item)->tp_name);
1456 static int BPy_IDArray_ass_subscript(BPy_IDArray *self, PyObject *item, PyObject *value)
1458 if (PyIndex_Check(item)) {
1459 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
1460 if (i == -1 && PyErr_Occurred())
1463 i += self->prop->len;
1464 return BPy_IDArray_SetItem(self, i, value);
1466 else if (PySlice_Check(item)) {
1467 Py_ssize_t start, stop, step, slicelength;
1469 if (PySlice_GetIndicesEx(item, self->prop->len, &start, &stop, &step, &slicelength) < 0)
1473 return BPy_IDArray_ass_slice(self, start, stop, value);
1475 PyErr_SetString(PyExc_TypeError, "slice steps not supported with vectors");
1480 PyErr_Format(PyExc_TypeError,
1481 "vector indices must be integers, not %.200s",
1482 Py_TYPE(item)->tp_name);
1487 static PyMappingMethods BPy_IDArray_AsMapping = {
1488 (lenfunc)BPy_IDArray_Len,
1489 (binaryfunc)BPy_IDArray_subscript,
1490 (objobjargproc)BPy_IDArray_ass_subscript
1493 static int itemsize_by_idarray_type(int array_type)
1495 if (array_type == IDP_INT) return sizeof(int);
1496 if (array_type == IDP_FLOAT) return sizeof(float);
1497 if (array_type == IDP_DOUBLE) return sizeof(double);
1498 return -1; /* should never happen */
1501 static int BPy_IDArray_getbuffer(BPy_IDArray *self, Py_buffer *view, int flags)
1503 IDProperty *prop = self->prop;
1504 int itemsize = itemsize_by_idarray_type(prop->subtype);
1505 int length = itemsize * prop->len;
1507 if (PyBuffer_FillInfo(view, (PyObject *)self, IDP_Array(prop), length, false, flags) == -1) {
1511 view->itemsize = itemsize;
1512 view->format = (char *)idp_format_from_array_type(prop->subtype);
1514 Py_ssize_t *shape = MEM_mallocN(sizeof(Py_ssize_t), __func__);
1515 shape[0] = prop->len;
1516 view->shape = shape;
1521 static void BPy_IDArray_releasebuffer(BPy_IDArray *UNUSED(self), Py_buffer *view)
1523 MEM_freeN(view->shape);
1526 static PyBufferProcs BPy_IDArray_Buffer = {
1527 (getbufferproc)BPy_IDArray_getbuffer,
1528 (releasebufferproc)BPy_IDArray_releasebuffer,
1532 PyTypeObject BPy_IDArray_Type = {
1533 PyVarObject_HEAD_INIT(NULL, 0)
1534 /* For printing, in format "<module>.<name>" */
1535 "IDPropertyArray", /* char *tp_name; */
1536 sizeof(BPy_IDArray), /* int tp_basicsize; */
1537 0, /* tp_itemsize; For allocation */
1539 /* Methods to implement standard operations */
1541 NULL, /* destructor tp_dealloc; */
1542 NULL, /* printfunc tp_print; */
1543 NULL, /* getattrfunc tp_getattr; */
1544 NULL, /* setattrfunc tp_setattr; */
1545 NULL, /* cmpfunc tp_compare; */
1546 (reprfunc)BPy_IDArray_repr, /* reprfunc tp_repr; */
1548 /* Method suites for standard classes */
1550 NULL, /* PyNumberMethods *tp_as_number; */
1551 &BPy_IDArray_Seq, /* PySequenceMethods *tp_as_sequence; */
1552 &BPy_IDArray_AsMapping, /* PyMappingMethods *tp_as_mapping; */
1554 /* More standard operations (here for binary compatibility) */
1556 NULL, /* hashfunc tp_hash; */
1557 NULL, /* ternaryfunc tp_call; */
1558 NULL, /* reprfunc tp_str; */
1559 NULL, /* getattrofunc tp_getattro; */
1560 NULL, /* setattrofunc tp_setattro; */
1562 /* Functions to access object as input/output buffer */
1563 &BPy_IDArray_Buffer, /* PyBufferProcs *tp_as_buffer; */
1565 /*** Flags to define presence of optional/expanded features ***/
1566 Py_TPFLAGS_DEFAULT, /* long tp_flags; */
1568 NULL, /* char *tp_doc; Documentation string */
1569 /*** Assigned meaning in release 2.0 ***/
1570 /* call function for all accessible objects */
1571 NULL, /* traverseproc tp_traverse; */
1573 /* delete references to contained objects */
1574 NULL, /* inquiry tp_clear; */
1576 /*** Assigned meaning in release 2.1 ***/
1577 /*** rich comparisons ***/
1578 NULL, /* richcmpfunc tp_richcompare; */
1580 /*** weak reference enabler ***/
1581 0, /* long tp_weaklistoffset; */
1583 /*** Added in release 2.2 ***/
1585 NULL, /* getiterfunc tp_iter; */
1586 NULL, /* iternextfunc tp_iternext; */
1588 /*** Attribute descriptor and subclassing stuff ***/
1589 BPy_IDArray_methods, /* struct PyMethodDef *tp_methods; */
1590 NULL, /* struct PyMemberDef *tp_members; */
1591 BPy_IDArray_getseters, /* struct PyGetSetDef *tp_getset; */
1592 NULL, /* struct _typeobject *tp_base; */
1593 NULL, /* PyObject *tp_dict; */
1594 NULL, /* descrgetfunc tp_descr_get; */
1595 NULL, /* descrsetfunc tp_descr_set; */
1596 0, /* long tp_dictoffset; */
1597 NULL, /* initproc tp_init; */
1598 NULL, /* allocfunc tp_alloc; */
1599 NULL, /* newfunc tp_new; */
1600 /* Low-level free-memory routine */
1601 NULL, /* freefunc tp_free; */
1602 /* For PyObject_IS_GC */
1603 NULL, /* inquiry tp_is_gc; */
1604 NULL, /* PyObject *tp_bases; */
1605 /* method resolution order */
1606 NULL, /* PyObject *tp_mro; */
1607 NULL, /* PyObject *tp_cache; */
1608 NULL, /* PyObject *tp_subclasses; */
1609 NULL, /* PyObject *tp_weaklist; */
1613 /*********** ID Property Group iterator ********/
1615 static PyObject *IDGroup_Iter_repr(BPy_IDGroup_Iter *self)
1617 return PyUnicode_FromFormat("(ID Property Group Iter \"%s\")", self->group->prop->name);
1620 static PyObject *BPy_Group_Iter_Next(BPy_IDGroup_Iter *self)
1628 self->cur = self->cur->next;
1630 if (self->mode == IDPROP_ITER_ITEMS) {
1631 ret = PyTuple_New(2);
1632 PyTuple_SET_ITEMS(ret,
1633 PyUnicode_FromString(cur->name),
1634 BPy_IDGroup_WrapData(self->group->id, cur, self->group->prop));
1638 return PyUnicode_FromString(cur->name);
1642 PyErr_SetNone(PyExc_StopIteration);
1647 PyTypeObject BPy_IDGroup_Iter_Type = {
1648 PyVarObject_HEAD_INIT(NULL, 0)
1649 /* For printing, in format "<module>.<name>" */
1650 "IDPropertyGroupIter", /* char *tp_name; */
1651 sizeof(BPy_IDGroup_Iter), /* int tp_basicsize; */
1652 0, /* tp_itemsize; For allocation */
1654 /* Methods to implement standard operations */
1656 NULL, /* destructor tp_dealloc; */
1657 NULL, /* printfunc tp_print; */
1658 NULL, /* getattrfunc tp_getattr; */
1659 NULL, /* setattrfunc tp_setattr; */
1660 NULL, /* cmpfunc tp_compare; */
1661 (reprfunc) IDGroup_Iter_repr, /* reprfunc tp_repr; */
1663 /* Method suites for standard classes */
1665 NULL, /* PyNumberMethods *tp_as_number; */
1666 NULL, /* PySequenceMethods *tp_as_sequence; */
1667 NULL, /* PyMappingMethods *tp_as_mapping; */
1669 /* More standard operations (here for binary compatibility) */
1671 NULL, /* hashfunc tp_hash; */
1672 NULL, /* ternaryfunc tp_call; */
1673 NULL, /* reprfunc tp_str; */
1674 NULL, /* getattrofunc tp_getattro; */
1675 NULL, /* setattrofunc tp_setattro; */
1677 /* Functions to access object as input/output buffer */
1678 NULL, /* PyBufferProcs *tp_as_buffer; */
1680 /*** Flags to define presence of optional/expanded features ***/
1681 Py_TPFLAGS_DEFAULT, /* long tp_flags; */
1683 NULL, /* char *tp_doc; Documentation string */
1684 /*** Assigned meaning in release 2.0 ***/
1685 /* call function for all accessible objects */
1686 NULL, /* traverseproc tp_traverse; */
1688 /* delete references to contained objects */
1689 NULL, /* inquiry tp_clear; */
1691 /*** Assigned meaning in release 2.1 ***/
1692 /*** rich comparisons ***/
1693 NULL, /* richcmpfunc tp_richcompare; */
1695 /*** weak reference enabler ***/
1696 0, /* long tp_weaklistoffset; */
1698 /*** Added in release 2.2 ***/
1700 PyObject_SelfIter, /* getiterfunc tp_iter; */
1701 (iternextfunc) BPy_Group_Iter_Next, /* iternextfunc tp_iternext; */
1704 void IDProp_Init_Types(void)
1706 PyType_Ready(&BPy_IDGroup_Type);
1707 PyType_Ready(&BPy_IDGroup_Iter_Type);
1708 PyType_Ready(&BPy_IDArray_Type);
1711 /*----------------------------MODULE INIT-------------------------*/
1715 static struct PyModuleDef IDProp_types_module_def = {
1716 PyModuleDef_HEAD_INIT,
1717 "idprop.types", /* m_name */
1720 NULL, /* m_methods */
1721 NULL, /* m_reload */
1722 NULL, /* m_traverse */
1727 static PyObject *BPyInit_idprop_types(void)
1729 PyObject *submodule;
1731 submodule = PyModule_Create(&IDProp_types_module_def);
1733 IDProp_Init_Types();
1735 #define MODULE_TYPE_ADD(s, t) \
1736 PyModule_AddObject(s, t.tp_name, (PyObject *)&t); Py_INCREF((PyObject *)&t)
1738 /* bmesh_py_types.c */
1739 MODULE_TYPE_ADD(submodule, BPy_IDGroup_Type);
1740 MODULE_TYPE_ADD(submodule, BPy_IDGroup_Iter_Type);
1741 MODULE_TYPE_ADD(submodule, BPy_IDArray_Type);
1743 #undef MODULE_TYPE_ADD
1750 static PyMethodDef IDProp_methods[] = {
1751 {NULL, NULL, 0, NULL}
1755 PyDoc_STRVAR(IDProp_module_doc,
1756 "This module provides access id property types (currently mainly for docs)."
1758 static struct PyModuleDef IDProp_module_def = {
1759 PyModuleDef_HEAD_INIT,
1760 "idprop", /* m_name */
1761 IDProp_module_doc, /* m_doc */
1763 IDProp_methods, /* m_methods */
1764 NULL, /* m_reload */
1765 NULL, /* m_traverse */
1770 PyObject *BPyInit_idprop(void)
1773 PyObject *submodule;
1774 PyObject *sys_modules = PyThreadState_GET()->interp->modules;
1776 mod = PyModule_Create(&IDProp_module_def);
1779 PyModule_AddObject(mod, "types", (submodule = BPyInit_idprop_types()));
1780 PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule);
1781 Py_INCREF(submodule);
1788 /* -------------------------------------------------------------------- */
1789 /* debug only function */
1791 void IDP_spit(IDProperty *prop)
1794 PyGILState_STATE gilstate;
1795 bool use_gil = true; /* !PyC_IsInterpreterActive(); */
1800 gilstate = PyGILState_Ensure();
1804 ret_dict = BPy_IDGroup_MapDataToPy(prop);
1805 ret_str = PyObject_Repr(ret_dict);
1806 Py_DECREF(ret_dict);
1808 printf("IDProperty(%p): %s\n", prop, _PyUnicode_AsString(ret_str));
1813 PyGILState_Release(gilstate);
1817 printf("IDProperty: <NIL>\n");