Blender  V3.3
idprop_py_api.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
7 #include <Python.h>
8 
9 #include "MEM_guardedalloc.h"
10 
11 #include "BLI_utildefines.h"
12 
13 #include "idprop_py_api.h"
14 #include "idprop_py_ui_api.h"
15 
16 #include "BKE_idprop.h"
17 
18 #include "DNA_ID.h" /* ID property definitions. */
19 
20 #define USE_STRING_COERCE
21 
22 #ifdef USE_STRING_COERCE
23 # include "py_capi_utils.h"
24 #endif
25 
26 #include "python_utildefines.h"
27 
28 extern bool pyrna_id_FromPyObject(PyObject *obj, ID **id);
29 extern PyObject *pyrna_id_CreatePyObject(ID *id);
30 extern bool pyrna_id_CheckPyObject(PyObject *obj);
31 
32 /* Currently there is no need to expose this publicly. */
33 static PyObject *BPy_IDGroup_IterKeys_CreatePyObject(BPy_IDProperty *group, const bool reversed);
34 static PyObject *BPy_IDGroup_IterValues_CreatePyObject(BPy_IDProperty *group, const bool reversed);
35 static PyObject *BPy_IDGroup_IterItems_CreatePyObject(BPy_IDProperty *group, const bool reversed);
36 
40 
41 static BPy_IDGroup_View *IDGroup_View_New_WithType(BPy_IDProperty *group, PyTypeObject *type);
42 static int BPy_IDGroup_Contains(BPy_IDProperty *self, PyObject *value);
43 
44 /* -------------------------------------------------------------------- */
50 static PyObject *idprop_py_from_idp_string(const IDProperty *prop)
51 {
52  if (prop->subtype == IDP_STRING_SUB_BYTE) {
53  return PyBytes_FromStringAndSize(IDP_String(prop), prop->len);
54  }
55 
56 #ifdef USE_STRING_COERCE
57  return PyC_UnicodeFromByteAndSize(IDP_Array(prop), prop->len - 1);
58 #else
59  return PyUnicode_FromStringAndSize(IDP_String(prop), prop->len - 1);
60 #endif
61 }
62 
63 static PyObject *idprop_py_from_idp_int(const IDProperty *prop)
64 {
65  return PyLong_FromLong((long)IDP_Int(prop));
66 }
67 
68 static PyObject *idprop_py_from_idp_float(const IDProperty *prop)
69 {
70  return PyFloat_FromDouble((double)IDP_Float(prop));
71 }
72 
73 static PyObject *idprop_py_from_idp_double(const IDProperty *prop)
74 {
75  return PyFloat_FromDouble(IDP_Double(prop));
76 }
77 
78 static PyObject *idprop_py_from_idp_group(ID *id, IDProperty *prop, IDProperty *parent)
79 {
80  BPy_IDProperty *group = PyObject_New(BPy_IDProperty, &BPy_IDGroup_Type);
81  group->owner_id = id;
82  group->prop = prop;
83  group->parent = parent; /* can be NULL */
84  return (PyObject *)group;
85 }
86 
87 static PyObject *idprop_py_from_idp_id(IDProperty *prop)
88 {
89  return pyrna_id_CreatePyObject(prop->data.pointer);
90 }
91 
92 static PyObject *idprop_py_from_idp_array(ID *id, IDProperty *prop)
93 {
95  array->owner_id = id;
96  array->prop = prop;
97  return (PyObject *)array;
98 }
99 
100 static PyObject *idprop_py_from_idp_idparray(ID *id, IDProperty *prop)
101 {
102  PyObject *seq = PyList_New(prop->len);
103  IDProperty *array = IDP_IDPArray(prop);
104  int i;
105 
106  if (!seq) {
107  PyErr_Format(
108  PyExc_RuntimeError, "%s: IDP_IDPARRAY: PyList_New(%d) failed", __func__, prop->len);
109  return NULL;
110  }
111 
112  for (i = 0; i < prop->len; i++) {
113  PyObject *wrap = BPy_IDGroup_WrapData(id, array++, prop);
114 
115  /* BPy_IDGroup_MapDataToPy sets the error */
116  if (UNLIKELY(wrap == NULL)) {
117  Py_DECREF(seq);
118  return NULL;
119  }
120 
121  PyList_SET_ITEM(seq, i, wrap);
122  }
123 
124  return seq;
125 }
126 
129 /* -------------------------------------------------------------------- */
133 /* use for both array and group */
134 static Py_hash_t BPy_IDGroup_hash(BPy_IDProperty *self)
135 {
136  return _Py_HashPointer(self->prop);
137 }
138 
139 static PyObject *BPy_IDGroup_repr(BPy_IDProperty *self)
140 {
141  return PyUnicode_FromFormat("<bpy id prop: owner=\"%s\", name=\"%s\", address=%p>",
142  self->owner_id ? self->owner_id->name : "<NONE>",
143  self->prop->name,
144  self->prop);
145 }
146 
147 PyObject *BPy_IDGroup_WrapData(ID *id, IDProperty *prop, IDProperty *parent)
148 {
149  switch (prop->type) {
150  case IDP_STRING:
151  return idprop_py_from_idp_string(prop);
152  case IDP_INT:
153  return idprop_py_from_idp_int(prop);
154  case IDP_FLOAT:
155  return idprop_py_from_idp_float(prop);
156  case IDP_DOUBLE:
157  return idprop_py_from_idp_double(prop);
158  case IDP_GROUP:
159  return idprop_py_from_idp_group(id, prop, parent);
160  case IDP_ARRAY:
161  return idprop_py_from_idp_array(id, prop);
162  case IDP_IDPARRAY:
163  return idprop_py_from_idp_idparray(id, prop); /* this could be better a internal type */
164  case IDP_ID:
165  return idprop_py_from_idp_id(prop);
166  default:
167  Py_RETURN_NONE;
168  }
169 }
170 
171 /* UNUSED, currently assignment overwrites into new properties, rather than setting in-place. */
172 #if 0
173 static int BPy_IDGroup_SetData(BPy_IDProperty *self, IDProperty *prop, PyObject *value)
174 {
175  switch (prop->type) {
176  case IDP_STRING: {
177  char *st;
178  if (!PyUnicode_Check(value)) {
179  PyErr_SetString(PyExc_TypeError, "expected a string!");
180  return -1;
181  }
182  /* NOTE: if this code is enabled, bytes support needs to be added */
183 # ifdef USE_STRING_COERCE
184  {
185  int alloc_len;
186  PyObject *value_coerce = NULL;
187 
188  st = (char *)PyC_UnicodeAsByte(value, &value_coerce);
189  alloc_len = strlen(st) + 1;
190 
191  st = PyUnicode_AsUTF8(value);
192  IDP_ResizeArray(prop, alloc_len);
193  memcpy(IDP_Array(prop), st, alloc_len);
194  Py_XDECREF(value_coerce);
195  }
196 # else
197  st = PyUnicode_AsUTF8(value);
198  IDP_ResizeArray(prop, strlen(st) + 1);
199  strcpy(IDP_Array(prop), st);
200 # endif
201 
202  return 0;
203  }
204 
205  case IDP_INT: {
206  int ivalue = PyLong_AsSsize_t(value);
207  if (ivalue == -1 && PyErr_Occurred()) {
208  PyErr_SetString(PyExc_TypeError, "expected an int type");
209  return -1;
210  }
211  IDP_Int(prop) = ivalue;
212  break;
213  }
214  case IDP_FLOAT: {
215  float fvalue = (float)PyFloat_AsDouble(value);
216  if (fvalue == -1 && PyErr_Occurred()) {
217  PyErr_SetString(PyExc_TypeError, "expected a float");
218  return -1;
219  }
220  IDP_Float(self->prop) = fvalue;
221  break;
222  }
223  case IDP_DOUBLE: {
224  double dvalue = PyFloat_AsDouble(value);
225  if (dvalue == -1 && PyErr_Occurred()) {
226  PyErr_SetString(PyExc_TypeError, "expected a float");
227  return -1;
228  }
229  IDP_Double(self->prop) = dvalue;
230  break;
231  }
232  default:
233  PyErr_SetString(PyExc_AttributeError, "attempt to set read-only attribute!");
234  return -1;
235  }
236  return 0;
237 }
238 #endif
239 
240 static PyObject *BPy_IDGroup_GetName(BPy_IDProperty *self, void *UNUSED(closure))
241 {
242  return PyUnicode_FromString(self->prop->name);
243 }
244 
245 static int BPy_IDGroup_SetName(BPy_IDProperty *self, PyObject *value, void *UNUSED(closure))
246 {
247  const char *name;
248  Py_ssize_t name_size;
249 
250  if (!PyUnicode_Check(value)) {
251  PyErr_SetString(PyExc_TypeError, "expected a string!");
252  return -1;
253  }
254 
255  name = PyUnicode_AsUTF8AndSize(value, &name_size);
256 
257  if (name_size + 1 > MAX_IDPROP_NAME) {
258  PyErr_SetString(PyExc_TypeError, "string length cannot exceed 63 characters!");
259  return -1;
260  }
261 
262  memcpy(self->prop->name, name, name_size + 1);
263  return 0;
264 }
265 
266 #if 0
267 static PyObject *BPy_IDGroup_GetType(BPy_IDProperty *self)
268 {
269  return PyLong_FromLong(self->prop->type);
270 }
271 #endif
272 
273 static PyGetSetDef BPy_IDGroup_getseters[] = {
274  {"name",
275  (getter)BPy_IDGroup_GetName,
276  (setter)BPy_IDGroup_SetName,
277  "The name of this Group.",
278  NULL},
279  {NULL, NULL, NULL, NULL, NULL},
280 };
281 
282 static Py_ssize_t BPy_IDGroup_Map_Len(BPy_IDProperty *self)
283 {
284  if (self->prop->type != IDP_GROUP) {
285  PyErr_SetString(PyExc_TypeError, "len() of unsized object");
286  return -1;
287  }
288 
289  return self->prop->len;
290 }
291 
292 static PyObject *BPy_IDGroup_Map_GetItem(BPy_IDProperty *self, PyObject *item)
293 {
294  IDProperty *idprop;
295  const char *name;
296 
297  if (self->prop->type != IDP_GROUP) {
298  PyErr_SetString(PyExc_TypeError, "unsubscriptable object");
299  return NULL;
300  }
301 
302  name = PyUnicode_AsUTF8(item);
303 
304  if (name == NULL) {
305  PyErr_SetString(PyExc_TypeError, "only strings are allowed as keys of ID properties");
306  return NULL;
307  }
308 
309  idprop = IDP_GetPropertyFromGroup(self->prop, name);
310 
311  if (idprop == NULL) {
312  PyErr_SetString(PyExc_KeyError, "key not in subgroup dict");
313  return NULL;
314  }
315 
316  return BPy_IDGroup_WrapData(self->owner_id, idprop, self->prop);
317 }
318 
319 /* returns NULL on success, error string on failure */
320 static char idp_sequence_type(PyObject *seq_fast)
321 {
322  PyObject **seq_fast_items = PySequence_Fast_ITEMS(seq_fast);
323  PyObject *item;
324  char type = IDP_INT;
325 
326  Py_ssize_t i, len = PySequence_Fast_GET_SIZE(seq_fast);
327 
328  for (i = 0; i < len; i++) {
329  item = seq_fast_items[i];
330  if (PyFloat_Check(item)) {
331  if (type == IDP_IDPARRAY) { /* mixed dict/int */
332  return -1;
333  }
334  type = IDP_DOUBLE;
335  }
336  else if (PyLong_Check(item)) {
337  if (type == IDP_IDPARRAY) { /* mixed dict/int */
338  return -1;
339  }
340  }
341  else if (PyMapping_Check(item)) {
342  if (i != 0 && (type != IDP_IDPARRAY)) { /* mixed dict/int */
343  return -1;
344  }
345  type = IDP_IDPARRAY;
346  }
347  else {
348  return -1;
349  }
350  }
351 
352  return type;
353 }
354 
355 static const char *idp_try_read_name(PyObject *name_obj)
356 {
357  const char *name = NULL;
358  if (name_obj) {
359  Py_ssize_t name_size;
360  name = PyUnicode_AsUTF8AndSize(name_obj, &name_size);
361 
362  if (name == NULL) {
363  PyErr_Format(PyExc_KeyError,
364  "invalid id-property key, expected a string, not a %.200s",
365  Py_TYPE(name_obj)->tp_name);
366  return NULL;
367  }
368 
369  if (name_size >= MAX_IDPROP_NAME) {
370  PyErr_SetString(PyExc_KeyError,
371  "the length of IDProperty names is limited to 63 characters");
372  return NULL;
373  }
374  }
375  else {
376  name = "";
377  }
378  return name;
379 }
380 
383 /* -------------------------------------------------------------------- */
392 static IDProperty *idp_from_PyFloat(const char *name, PyObject *ob)
393 {
394  IDPropertyTemplate val = {0};
395  val.d = PyFloat_AsDouble(ob);
396  return IDP_New(IDP_DOUBLE, &val, name);
397 }
398 
399 static IDProperty *idp_from_PyLong(const char *name, PyObject *ob)
400 {
401  IDPropertyTemplate val = {0};
402  val.i = PyC_Long_AsI32(ob);
403  if (val.i == -1 && PyErr_Occurred()) {
404  return NULL;
405  }
406  return IDP_New(IDP_INT, &val, name);
407 }
408 
409 static IDProperty *idp_from_PyUnicode(const char *name, PyObject *ob)
410 {
411  IDProperty *prop;
412  IDPropertyTemplate val = {0};
413 #ifdef USE_STRING_COERCE
414  Py_ssize_t value_size;
415  PyObject *value_coerce = NULL;
416  val.string.str = PyC_UnicodeAsByteAndSize(ob, &value_size, &value_coerce);
417  val.string.len = (int)value_size + 1;
419  prop = IDP_New(IDP_STRING, &val, name);
420  Py_XDECREF(value_coerce);
421 #else
422  val.str = PyUnicode_AsUTF8(ob);
423  prop = IDP_New(IDP_STRING, val, name);
424 #endif
425  return prop;
426 }
427 
428 static IDProperty *idp_from_PyBytes(const char *name, PyObject *ob)
429 {
430  IDPropertyTemplate val = {0};
431  val.string.str = PyBytes_AS_STRING(ob);
432  val.string.len = PyBytes_GET_SIZE(ob);
434  return IDP_New(IDP_STRING, &val, name);
435 }
436 
437 static int idp_array_type_from_formatstr_and_size(const char *typestr, Py_ssize_t itemsize)
438 {
439  const char format = PyC_StructFmt_type_from_str(typestr);
440 
442  if (itemsize == 4) {
443  return IDP_FLOAT;
444  }
445  if (itemsize == 8) {
446  return IDP_DOUBLE;
447  }
448  }
450  if (itemsize == 4) {
451  return IDP_INT;
452  }
453  }
454 
455  return -1;
456 }
457 
458 static const char *idp_format_from_array_type(int type)
459 {
460  if (type == IDP_INT) {
461  return "i";
462  }
463  if (type == IDP_FLOAT) {
464  return "f";
465  }
466  if (type == IDP_DOUBLE) {
467  return "d";
468  }
469  return NULL;
470 }
471 
472 static IDProperty *idp_from_PySequence_Buffer(const char *name, Py_buffer *buffer)
473 {
474  IDProperty *prop;
475  IDPropertyTemplate val = {0};
476 
477  const int id_type = idp_array_type_from_formatstr_and_size(buffer->format, buffer->itemsize);
478  if (id_type == -1) {
479  /* should never happen as the type has been checked before */
480  return NULL;
481  }
482 
483  val.array.type = id_type;
484  val.array.len = buffer->len / buffer->itemsize;
485 
486  prop = IDP_New(IDP_ARRAY, &val, name);
487  memcpy(IDP_Array(prop), buffer->buf, buffer->len);
488  return prop;
489 }
490 
491 static IDProperty *idp_from_PySequence_Fast(const char *name, PyObject *ob)
492 {
493  IDProperty *prop;
494  IDPropertyTemplate val = {0};
495 
496  PyObject **ob_seq_fast_items;
497  PyObject *item;
498  int i;
499 
500  ob_seq_fast_items = PySequence_Fast_ITEMS(ob);
501 
502  if ((val.array.type = idp_sequence_type(ob)) == (char)-1) {
503  PyErr_SetString(PyExc_TypeError,
504  "only floats, ints and dicts are allowed in ID property arrays");
505  return NULL;
506  }
507 
508  /* validate sequence and derive type.
509  * we assume IDP_INT unless we hit a float
510  * number; then we assume it's */
511 
512  val.array.len = PySequence_Fast_GET_SIZE(ob);
513 
514  switch (val.array.type) {
515  case IDP_DOUBLE: {
516  double *prop_data;
517  prop = IDP_New(IDP_ARRAY, &val, name);
518  prop_data = IDP_Array(prop);
519  for (i = 0; i < val.array.len; i++) {
520  item = ob_seq_fast_items[i];
521  if (((prop_data[i] = PyFloat_AsDouble(item)) == -1.0) && PyErr_Occurred()) {
522  IDP_FreeProperty(prop);
523  return NULL;
524  }
525  }
526  break;
527  }
528  case IDP_INT: {
529  int *prop_data;
530  prop = IDP_New(IDP_ARRAY, &val, name);
531  prop_data = IDP_Array(prop);
532  for (i = 0; i < val.array.len; i++) {
533  item = ob_seq_fast_items[i];
534  if (((prop_data[i] = PyC_Long_AsI32(item)) == -1) && PyErr_Occurred()) {
535  IDP_FreeProperty(prop);
536  return NULL;
537  }
538  }
539  break;
540  }
541  case IDP_IDPARRAY: {
542  prop = IDP_NewIDPArray(name);
543  for (i = 0; i < val.array.len; i++) {
544  item = ob_seq_fast_items[i];
545  if (BPy_IDProperty_Map_ValidateAndCreate(NULL, prop, item) == false) {
546  IDP_FreeProperty(prop);
547  return NULL;
548  }
549  }
550  break;
551  }
552  default:
553  /* should never happen */
554  PyErr_SetString(PyExc_RuntimeError, "internal error with idp array.type");
555  return NULL;
556  }
557  return prop;
558 }
559 
560 static IDProperty *idp_from_PySequence(const char *name, PyObject *ob)
561 {
562  Py_buffer buffer;
563  bool use_buffer = false;
564 
565  if (PyObject_CheckBuffer(ob)) {
566  PyObject_GetBuffer(ob, &buffer, PyBUF_SIMPLE | PyBUF_FORMAT);
567  const char format = PyC_StructFmt_type_from_str(buffer.format);
569  (PyC_StructFmt_type_is_int_any(format) && buffer.itemsize == 4)) {
570  use_buffer = true;
571  }
572  else {
573  PyBuffer_Release(&buffer);
574  }
575  }
576 
577  if (use_buffer) {
579  PyBuffer_Release(&buffer);
580  return prop;
581  }
582 
583  PyObject *ob_seq_fast = PySequence_Fast(ob, "py -> idprop");
584  if (ob_seq_fast != NULL) {
585  IDProperty *prop = idp_from_PySequence_Fast(name, ob_seq_fast);
586  Py_DECREF(ob_seq_fast);
587  return prop;
588  }
589 
590  return NULL;
591 }
592 
593 static IDProperty *idp_from_PyMapping(const char *name, PyObject *ob)
594 {
595  IDProperty *prop;
596  const IDPropertyTemplate val = {0};
597 
598  PyObject *keys, *vals, *key, *pval;
599  int i, len;
600  /* yay! we get into recursive stuff now! */
601  keys = PyMapping_Keys(ob);
602  vals = PyMapping_Values(ob);
603 
604  /* We allocate the group first; if we hit any invalid data,
605  * we can delete it easily enough. */
606  prop = IDP_New(IDP_GROUP, &val, name);
607  len = PyMapping_Length(ob);
608  for (i = 0; i < len; i++) {
609  key = PySequence_GetItem(keys, i);
610  pval = PySequence_GetItem(vals, i);
611  if (BPy_IDProperty_Map_ValidateAndCreate(key, prop, pval) == false) {
612  IDP_FreeProperty(prop);
613  Py_XDECREF(keys);
614  Py_XDECREF(vals);
615  Py_XDECREF(key);
616  Py_XDECREF(pval);
617  /* error is already set */
618  return NULL;
619  }
620  Py_XDECREF(key);
621  Py_XDECREF(pval);
622  }
623  Py_XDECREF(keys);
624  Py_XDECREF(vals);
625  return prop;
626 }
627 
628 static IDProperty *idp_from_DatablockPointer(const char *name, PyObject *ob)
629 {
630  IDPropertyTemplate val = {0};
631  pyrna_id_FromPyObject(ob, &val.id);
632  return IDP_New(IDP_ID, &val, name);
633 }
634 
635 static IDProperty *idp_from_PyObject(PyObject *name_obj, PyObject *ob)
636 {
637  const char *name = idp_try_read_name(name_obj);
638  if (name == NULL) {
639  return NULL;
640  }
641 
642  if (PyFloat_Check(ob)) {
643  return idp_from_PyFloat(name, ob);
644  }
645  if (PyLong_Check(ob)) {
646  return idp_from_PyLong(name, ob);
647  }
648  if (PyUnicode_Check(ob)) {
649  return idp_from_PyUnicode(name, ob);
650  }
651  if (PyBytes_Check(ob)) {
652  return idp_from_PyBytes(name, ob);
653  }
654  if (PySequence_Check(ob)) {
655  return idp_from_PySequence(name, ob);
656  }
657  if (ob == Py_None || pyrna_id_CheckPyObject(ob)) {
658  return idp_from_DatablockPointer(name, ob);
659  }
660  if (PyMapping_Check(ob)) {
661  return idp_from_PyMapping(name, ob);
662  }
663 
664  PyErr_Format(
665  PyExc_TypeError, "invalid id-property type %.200s not supported", Py_TYPE(ob)->tp_name);
666  return NULL;
667 }
668 
671 /* -------------------------------------------------------------------- */
675 bool BPy_IDProperty_Map_ValidateAndCreate(PyObject *name_obj, IDProperty *group, PyObject *ob)
676 {
677  IDProperty *prop = idp_from_PyObject(name_obj, ob);
678  if (prop == NULL) {
679  return false;
680  }
681 
682  if (group->type == IDP_IDPARRAY) {
683  IDP_AppendArray(group, prop);
684  /* IDP_AppendArray does a shallow copy (memcpy), only free memory */
685  MEM_freeN(prop);
686  }
687  else {
688  IDProperty *prop_exist;
689 
690  /* avoid freeing when types match in case they are referenced by the UI, see: T37073
691  * obviously this isn't a complete solution, but helps for common cases. */
692  prop_exist = IDP_GetPropertyFromGroup(group, prop->name);
693  if ((prop_exist != NULL) && (prop_exist->type == prop->type) &&
694  (prop_exist->subtype == prop->subtype)) {
695  /* Preserve prev/next links!!! See T42593. */
696  prop->prev = prop_exist->prev;
697  prop->next = prop_exist->next;
698  prop->flag = prop_exist->flag;
699 
700  /* Don't free and reset the existing property's UI data, since this only assigns a value. */
701  IDPropertyUIData *ui_data = prop_exist->ui_data;
702  prop_exist->ui_data = NULL;
703  IDP_FreePropertyContent(prop_exist);
704  *prop_exist = *prop;
705  prop_exist->ui_data = ui_data;
706  MEM_freeN(prop);
707  }
708  else {
709  IDP_ReplaceInGroup_ex(group, prop, prop_exist);
710  }
711  }
712 
713  return true;
714 }
715 
716 int BPy_Wrap_SetMapItem(IDProperty *prop, PyObject *key, PyObject *val)
717 {
718  if (prop->type != IDP_GROUP) {
719  PyErr_SetString(PyExc_TypeError, "unsubscriptable object");
720  return -1;
721  }
722 
723  if (val == NULL) { /* del idprop[key] */
724  IDProperty *pkey;
725  const char *name = PyUnicode_AsUTF8(key);
726 
727  if (name == NULL) {
728  PyErr_Format(PyExc_KeyError, "expected a string, not %.200s", Py_TYPE(key)->tp_name);
729  return -1;
730  }
731 
732  pkey = IDP_GetPropertyFromGroup(prop, name);
733  if (pkey) {
734  IDP_FreeFromGroup(prop, pkey);
735  return 0;
736  }
737 
738  PyErr_SetString(PyExc_KeyError, "property not found in group");
739  return -1;
740  }
741 
742  bool ok;
743 
744  ok = BPy_IDProperty_Map_ValidateAndCreate(key, prop, val);
745  if (ok == false) {
746  return -1;
747  }
748 
749  return 0;
750 }
751 
752 static int BPy_IDGroup_Map_SetItem(BPy_IDProperty *self, PyObject *key, PyObject *val)
753 {
754  return BPy_Wrap_SetMapItem(self->prop, key, val);
755 }
756 
757 static PyObject *BPy_IDGroup_iter(BPy_IDProperty *self)
758 {
759  PyObject *iterable = BPy_IDGroup_ViewKeys_CreatePyObject(self);
760  PyObject *ret;
761  if (iterable) {
762  ret = PyObject_GetIter(iterable);
763  Py_DECREF(iterable);
764  }
765  else {
766  ret = NULL;
767  }
768  return ret;
769 }
770 
772 {
773  switch (prop->type) {
774  case IDP_STRING:
775  return idprop_py_from_idp_string(prop);
776  case IDP_INT:
777  return idprop_py_from_idp_int(prop);
778  case IDP_FLOAT:
779  return idprop_py_from_idp_float(prop);
780  case IDP_DOUBLE:
781  return idprop_py_from_idp_double(prop);
782  case IDP_ID:
783  return idprop_py_from_idp_id(prop);
784  case IDP_ARRAY: {
785  PyObject *seq = PyList_New(prop->len);
786  int i;
787 
788  if (!seq) {
789  PyErr_Format(
790  PyExc_RuntimeError, "%s: IDP_ARRAY: PyList_New(%d) failed", __func__, prop->len);
791  return NULL;
792  }
793 
794  switch (prop->subtype) {
795  case IDP_FLOAT: {
796  const float *array = (float *)IDP_Array(prop);
797  for (i = 0; i < prop->len; i++) {
798  PyList_SET_ITEM(seq, i, PyFloat_FromDouble(array[i]));
799  }
800  break;
801  }
802  case IDP_DOUBLE: {
803  const double *array = (double *)IDP_Array(prop);
804  for (i = 0; i < prop->len; i++) {
805  PyList_SET_ITEM(seq, i, PyFloat_FromDouble(array[i]));
806  }
807  break;
808  }
809  case IDP_INT: {
810  const int *array = (int *)IDP_Array(prop);
811  for (i = 0; i < prop->len; i++) {
812  PyList_SET_ITEM(seq, i, PyLong_FromLong(array[i]));
813  }
814  break;
815  }
816  default:
817  PyErr_Format(
818  PyExc_RuntimeError, "%s: invalid/corrupt array type '%d'!", __func__, prop->subtype);
819  Py_DECREF(seq);
820  return NULL;
821  }
822 
823  return seq;
824  }
825  case IDP_IDPARRAY: {
826  PyObject *seq = PyList_New(prop->len);
827  IDProperty *array = IDP_IDPArray(prop);
828  int i;
829 
830  if (!seq) {
831  PyErr_Format(
832  PyExc_RuntimeError, "%s: IDP_IDPARRAY: PyList_New(%d) failed", __func__, prop->len);
833  return NULL;
834  }
835 
836  for (i = 0; i < prop->len; i++) {
837  PyObject *wrap = BPy_IDGroup_MapDataToPy(array++);
838 
839  /* BPy_IDGroup_MapDataToPy sets the error */
840  if (UNLIKELY(wrap == NULL)) {
841  Py_DECREF(seq);
842  return NULL;
843  }
844 
845  PyList_SET_ITEM(seq, i, wrap);
846  }
847  return seq;
848  }
849  case IDP_GROUP: {
850  PyObject *dict = _PyDict_NewPresized(prop->len);
851  IDProperty *loop;
852 
853  for (loop = prop->data.group.first; loop; loop = loop->next) {
854  PyObject *wrap = BPy_IDGroup_MapDataToPy(loop);
855 
856  /* BPy_IDGroup_MapDataToPy sets the error */
857  if (UNLIKELY(wrap == NULL)) {
858  Py_DECREF(dict);
859  return NULL;
860  }
861 
862  PyDict_SetItemString(dict, loop->name, wrap);
863  Py_DECREF(wrap);
864  }
865  return dict;
866  }
867  }
868 
869  PyErr_Format(PyExc_RuntimeError,
870  "%s ERROR: '%s' property exists with a bad type code '%d'!",
871  __func__,
872  prop->name,
873  prop->type);
874  return NULL;
875 }
876 
879 /* -------------------------------------------------------------------- */
884 {
885  if (self->group == NULL) {
886  return PyUnicode_FromFormat("<%s>", Py_TYPE(self)->tp_name);
887  }
888  return PyUnicode_FromFormat("<%s \"%s\">", Py_TYPE(self)->tp_name, self->group->prop->name);
889 }
890 
892 {
893  if (self->group != NULL) {
894  PyObject_GC_UnTrack(self);
895  }
896  Py_CLEAR(self->group);
897  PyObject_GC_Del(self);
898 }
899 
900 static int BPy_IDGroup_Iter_traverse(BPy_IDGroup_Iter *self, visitproc visit, void *arg)
901 {
902  Py_VISIT(self->group);
903  return 0;
904 }
905 
907 {
908  Py_CLEAR(self->group);
909  return 0;
910 }
911 
913 {
914  if (self->len_init == self->group->prop->len) {
915  return true;
916  }
917  PyErr_SetString(PyExc_RuntimeError, "IDPropertyGroup changed size during iteration");
918  return false;
919 }
920 
922 {
923  if (self->cur != NULL) {
924  /* When `cur` is set, `group` cannot be NULL. */
926  return NULL;
927  }
928  IDProperty *cur = self->cur;
929  self->cur = self->reversed ? self->cur->prev : self->cur->next;
930  return PyUnicode_FromString(cur->name);
931  }
932  PyErr_SetNone(PyExc_StopIteration);
933  return NULL;
934 }
935 
937 {
938  if (self->cur != NULL) {
939  /* When `cur` is set, `group` cannot be NULL. */
941  return NULL;
942  }
943  IDProperty *cur = self->cur;
944  self->cur = self->reversed ? self->cur->prev : self->cur->next;
945  return BPy_IDGroup_WrapData(self->group->owner_id, cur, self->group->prop);
946  }
947  PyErr_SetNone(PyExc_StopIteration);
948  return NULL;
949 }
950 
952 {
953  if (self->cur != NULL) {
954  /* When `cur` is set, `group` cannot be NULL. */
956  return NULL;
957  }
958  IDProperty *cur = self->cur;
959  self->cur = self->reversed ? self->cur->prev : self->cur->next;
960  PyObject *ret = PyTuple_New(2);
962  PyUnicode_FromString(cur->name),
963  BPy_IDGroup_WrapData(self->group->owner_id, cur, self->group->prop));
964  return ret;
965  }
966  PyErr_SetNone(PyExc_StopIteration);
967  return NULL;
968 }
969 
970 PyTypeObject BPy_IDGroup_IterKeys_Type = {PyVarObject_HEAD_INIT(NULL, 0)};
971 PyTypeObject BPy_IDGroup_IterValues_Type = {PyVarObject_HEAD_INIT(NULL, 0)};
972 PyTypeObject BPy_IDGroup_IterItems_Type = {PyVarObject_HEAD_INIT(NULL, 0)};
973 
974 /* ID Property Group Iterator. */
975 static void IDGroup_Iter_init_type(void)
976 {
977 #define SHARED_MEMBER_SET(member, value) \
978  { \
979  k_ty->member = v_ty->member = i_ty->member = value; \
980  } \
981  ((void)0)
982 
983  PyTypeObject *k_ty = &BPy_IDGroup_IterKeys_Type;
984  PyTypeObject *v_ty = &BPy_IDGroup_IterValues_Type;
985  PyTypeObject *i_ty = &BPy_IDGroup_IterItems_Type;
986 
987  /* Unique members. */
988  k_ty->tp_name = "IDPropertyGroupIterKeys";
989  v_ty->tp_name = "IDPropertyGroupIterValues";
990  i_ty->tp_name = "IDPropertyGroupIterItems";
991 
992  k_ty->tp_iternext = (iternextfunc)BPy_Group_IterKeys_next;
993  v_ty->tp_iternext = (iternextfunc)BPy_Group_IterValues_next;
994  i_ty->tp_iternext = (iternextfunc)BPy_Group_IterItems_next;
995 
996  /* Shared members. */
997  SHARED_MEMBER_SET(tp_basicsize, sizeof(BPy_IDGroup_Iter));
998  SHARED_MEMBER_SET(tp_dealloc, (destructor)BPy_IDGroup_Iter_dealloc);
999  SHARED_MEMBER_SET(tp_repr, (reprfunc)BPy_IDGroup_Iter_repr);
1000  SHARED_MEMBER_SET(tp_flags, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC);
1001  SHARED_MEMBER_SET(tp_traverse, (traverseproc)BPy_IDGroup_Iter_traverse);
1002  SHARED_MEMBER_SET(tp_clear, (inquiry)BPy_IDGroup_Iter_clear);
1003  SHARED_MEMBER_SET(tp_iter, PyObject_SelfIter);
1004 
1005 #undef SHARED_MEMBER_SET
1006 }
1007 
1009  const bool reversed,
1010  PyTypeObject *type)
1011 {
1012  BLI_assert(group ? group->prop->type == IDP_GROUP : true);
1013  BPy_IDGroup_Iter *iter = PyObject_GC_New(BPy_IDGroup_Iter, type);
1014  iter->reversed = reversed;
1015  iter->group = group;
1016  if (group != NULL) {
1017  Py_INCREF(group);
1018  PyObject_GC_Track(iter);
1019  iter->cur = (reversed ? group->prop->data.group.last : group->prop->data.group.first);
1020  iter->len_init = group->prop->len;
1021  }
1022  else {
1023  iter->cur = NULL;
1024  iter->len_init = 0;
1025  }
1026  return (PyObject *)iter;
1027 }
1028 
1029 static PyObject *BPy_IDGroup_IterKeys_CreatePyObject(BPy_IDProperty *group, const bool reversed)
1030 {
1031  return IDGroup_Iter_New_WithType(group, reversed, &BPy_IDGroup_IterKeys_Type);
1032 }
1033 
1034 static PyObject *BPy_IDGroup_IterValues_CreatePyObject(BPy_IDProperty *group, const bool reversed)
1035 {
1036  return IDGroup_Iter_New_WithType(group, reversed, &BPy_IDGroup_IterValues_Type);
1037 }
1038 
1039 static PyObject *BPy_IDGroup_IterItems_CreatePyObject(BPy_IDProperty *group, const bool reversed)
1040 {
1041  return IDGroup_Iter_New_WithType(group, reversed, &BPy_IDGroup_IterItems_Type);
1042 }
1043 
1046 /* -------------------------------------------------------------------- */
1061 {
1062  if (self->group == NULL) {
1063  return PyUnicode_FromFormat("<%s>", Py_TYPE(self)->tp_name);
1064  }
1065  return PyUnicode_FromFormat("<%s \"%s\">", Py_TYPE(self)->tp_name, self->group->prop->name);
1066 }
1067 
1069 {
1070  if (self->group != NULL) {
1071  PyObject_GC_UnTrack(self);
1072  }
1073  Py_CLEAR(self->group);
1074  PyObject_GC_Del(self);
1075 }
1076 
1077 static int BPy_IDGroup_View_traverse(BPy_IDGroup_View *self, visitproc visit, void *arg)
1078 {
1079  Py_VISIT(self->group);
1080  return 0;
1081 }
1082 
1084 {
1085  Py_CLEAR(self->group);
1086  return 0;
1087 }
1088 
1089 /* View Specific API's (Key/Value/Items). */
1090 
1092 {
1093  return BPy_IDGroup_IterKeys_CreatePyObject(self->group, self->reversed);
1094 }
1095 
1097 {
1098  return BPy_IDGroup_IterValues_CreatePyObject(self->group, self->reversed);
1099 }
1100 
1102 {
1103  return BPy_IDGroup_IterItems_CreatePyObject(self->group, self->reversed);
1104 }
1105 
1106 static Py_ssize_t BPy_Group_View_len(BPy_IDGroup_View *self)
1107 {
1108  if (self->group == NULL) {
1109  return 0;
1110  }
1111  return self->group->prop->len;
1112 }
1113 
1114 static int BPy_Group_ViewKeys_Contains(BPy_IDGroup_View *self, PyObject *value)
1115 {
1116  if (self->group == NULL) {
1117  return 0;
1118  }
1119  return BPy_IDGroup_Contains(self->group, value);
1120 }
1121 
1122 static int BPy_Group_ViewValues_Contains(BPy_IDGroup_View *self, PyObject *value)
1123 {
1124  if (self->group == NULL) {
1125  return 0;
1126  }
1127  /* TODO: implement this without first converting to a list. */
1128  PyObject *list = PySequence_List((PyObject *)self);
1129  const int result = PySequence_Contains(list, value);
1130  Py_DECREF(list);
1131  return result;
1132 }
1133 
1134 static int BPy_Group_ViewItems_Contains(BPy_IDGroup_View *self, PyObject *value)
1135 {
1136  if (self->group == NULL) {
1137  return 0;
1138  }
1139  /* TODO: implement this without first converting to a list. */
1140  PyObject *list = PySequence_List((PyObject *)self);
1141  const int result = PySequence_Contains(list, value);
1142  Py_DECREF(list);
1143  return result;
1144 }
1145 
1146 static PySequenceMethods BPy_IDGroup_ViewKeys_as_sequence = {
1147  (lenfunc)BPy_Group_View_len, /* sq_length */
1148  0, /* sq_concat */
1149  0, /* sq_repeat */
1150  0, /* sq_item */
1151  0, /* sq_slice */
1152  0, /* sq_ass_item */
1153  0, /* sq_ass_slice */
1154  (objobjproc)BPy_Group_ViewKeys_Contains, /* sq_contains */
1155 };
1156 
1157 static PySequenceMethods BPy_IDGroup_ViewValues_as_sequence = {
1158  (lenfunc)BPy_Group_View_len, /* sq_length */
1159  0, /* sq_concat */
1160  0, /* sq_repeat */
1161  0, /* sq_item */
1162  0, /* sq_slice */
1163  0, /* sq_ass_item */
1164  0, /* sq_ass_slice */
1165  (objobjproc)BPy_Group_ViewValues_Contains, /* sq_contains */
1166 };
1167 
1168 static PySequenceMethods BPy_IDGroup_ViewItems_as_sequence = {
1169  (lenfunc)BPy_Group_View_len, /* sq_length */
1170  0, /* sq_concat */
1171  0, /* sq_repeat */
1172  0, /* sq_item */
1173  0, /* sq_slice */
1174  0, /* sq_ass_item */
1175  0, /* sq_ass_slice */
1176  (objobjproc)BPy_Group_ViewItems_Contains, /* sq_contains */
1177 };
1178 
1179 /* Methods. */
1180 
1181 PyDoc_STRVAR(BPy_IDGroup_View_reversed_doc,
1182  "Return a reverse iterator over the ID Property keys values or items.");
1183 
1184 static PyObject *BPy_IDGroup_View_reversed(BPy_IDGroup_View *self, PyObject *UNUSED(ignored))
1185 {
1186  BPy_IDGroup_View *result = IDGroup_View_New_WithType(self->group, Py_TYPE(self));
1187  result->reversed = !self->reversed;
1188  return (PyObject *)result;
1189 }
1190 
1191 static PyMethodDef BPy_IDGroup_View_methods[] = {
1192  {"__reversed__",
1193  (PyCFunction)(void (*)(void))BPy_IDGroup_View_reversed,
1194  METH_NOARGS,
1195  BPy_IDGroup_View_reversed_doc},
1196  {NULL, NULL},
1197 };
1198 
1199 PyTypeObject BPy_IDGroup_ViewKeys_Type = {PyVarObject_HEAD_INIT(NULL, 0)};
1200 PyTypeObject BPy_IDGroup_ViewValues_Type = {PyVarObject_HEAD_INIT(NULL, 0)};
1201 PyTypeObject BPy_IDGroup_ViewItems_Type = {PyVarObject_HEAD_INIT(NULL, 0)};
1202 
1203 /* ID Property Group View. */
1204 static void IDGroup_View_init_type(void)
1205 {
1206  PyTypeObject *k_ty = &BPy_IDGroup_ViewKeys_Type;
1207  PyTypeObject *v_ty = &BPy_IDGroup_ViewValues_Type;
1208  PyTypeObject *i_ty = &BPy_IDGroup_ViewItems_Type;
1209 
1210  /* Unique members. */
1211  k_ty->tp_name = "IDPropertyGroupViewKeys";
1212  v_ty->tp_name = "IDPropertyGroupViewValues";
1213  i_ty->tp_name = "IDPropertyGroupViewItems";
1214 
1215  k_ty->tp_iter = (getiterfunc)BPy_Group_ViewKeys_iter;
1216  v_ty->tp_iter = (getiterfunc)BPy_Group_ViewValues_iter;
1217  i_ty->tp_iter = (getiterfunc)BPy_Group_ViewItems_iter;
1218 
1219  k_ty->tp_as_sequence = &BPy_IDGroup_ViewKeys_as_sequence;
1220  v_ty->tp_as_sequence = &BPy_IDGroup_ViewValues_as_sequence;
1221  i_ty->tp_as_sequence = &BPy_IDGroup_ViewItems_as_sequence;
1222 
1223  /* Shared members. */
1224 #define SHARED_MEMBER_SET(member, value) \
1225  { \
1226  k_ty->member = v_ty->member = i_ty->member = value; \
1227  } \
1228  ((void)0)
1229 
1230  SHARED_MEMBER_SET(tp_basicsize, sizeof(BPy_IDGroup_View));
1231  SHARED_MEMBER_SET(tp_dealloc, (destructor)BPy_IDGroup_View_dealloc);
1232  SHARED_MEMBER_SET(tp_repr, (reprfunc)BPy_IDGroup_View_repr);
1233  SHARED_MEMBER_SET(tp_flags, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC);
1234  SHARED_MEMBER_SET(tp_traverse, (traverseproc)BPy_IDGroup_View_traverse);
1235  SHARED_MEMBER_SET(tp_clear, (inquiry)BPy_IDGroup_View_clear);
1237 
1238 #undef SHARED_MEMBER_SET
1239 }
1240 
1243 /* -------------------------------------------------------------------- */
1248  BPy_IDGroup_pop_doc,
1249  ".. method:: pop(key, default)\n"
1250  "\n"
1251  " Remove an item from the group, returning a Python representation.\n"
1252  "\n"
1253  " :raises KeyError: When the item doesn't exist.\n"
1254  "\n"
1255  " :arg key: Name of item to remove.\n"
1256  " :type key: string\n"
1257  " :arg default: Value to return when key isn't found, otherwise raise an exception.\n"
1258  " :type default: Undefined\n");
1259 static PyObject *BPy_IDGroup_pop(BPy_IDProperty *self, PyObject *args)
1260 {
1261  IDProperty *idprop;
1262  PyObject *pyform;
1263 
1264  char *key;
1265  PyObject *def = NULL;
1266 
1267  if (!PyArg_ParseTuple(args, "s|O:get", &key, &def)) {
1268  return NULL;
1269  }
1270 
1271  idprop = IDP_GetPropertyFromGroup(self->prop, key);
1272  if (idprop == NULL) {
1273  if (def == NULL) {
1274  PyErr_SetString(PyExc_KeyError, "item not in group");
1275  return NULL;
1276  }
1277  return Py_INCREF_RET(def);
1278  }
1279 
1280  pyform = BPy_IDGroup_MapDataToPy(idprop);
1281  if (pyform == NULL) {
1282  /* Ok something bad happened with the #PyObject, so don't remove the prop from the group.
1283  * if `pyform` is NULL, then it already should have raised an exception. */
1284  return NULL;
1285  }
1286 
1287  IDP_FreeFromGroup(self->prop, idprop);
1288  return pyform;
1289 }
1290 
1291 /* utility function */
1292 static void BPy_IDGroup_CorrectListLen(IDProperty *prop, PyObject *seq, int len, const char *func)
1293 {
1294  int j;
1295 
1296  printf("%s: ID Property Error found and corrected!\n", func);
1297 
1298  /* fill rest of list with valid references to None */
1299  for (j = len; j < prop->len; j++) {
1300  PyList_SET_ITEM(seq, j, Py_INCREF_RET(Py_None));
1301  }
1302 
1303  /* Set correct group length. */
1304  prop->len = len;
1305 }
1306 
1308 {
1309  PyObject *list = PyList_New(prop->len);
1310  IDProperty *loop;
1311  int i;
1312 
1313  for (i = 0, loop = prop->data.group.first; loop && (i < prop->len); loop = loop->next, i++) {
1314  PyList_SET_ITEM(list, i, PyUnicode_FromString(loop->name));
1315  }
1316 
1317  /* if the id prop is corrupt, count the remaining */
1318  for (; loop; loop = loop->next, i++) {
1319  /* pass */
1320  }
1321 
1322  if (i != prop->len) { /* if the loop didn't finish, we know the length is wrong */
1323  BPy_IDGroup_CorrectListLen(prop, list, i, __func__);
1324  Py_DECREF(list); /* Free the list. */
1325  /* Call self again. */
1326  return BPy_Wrap_GetKeys(prop);
1327  }
1328 
1329  return list;
1330 }
1331 
1332 PyObject *BPy_Wrap_GetValues(ID *id, IDProperty *prop)
1333 {
1334  PyObject *list = PyList_New(prop->len);
1335  IDProperty *loop;
1336  int i;
1337 
1338  for (i = 0, loop = prop->data.group.first; loop; loop = loop->next, i++) {
1339  PyList_SET_ITEM(list, i, BPy_IDGroup_WrapData(id, loop, prop));
1340  }
1341 
1342  if (i != prop->len) {
1343  BPy_IDGroup_CorrectListLen(prop, list, i, __func__);
1344  Py_DECREF(list); /* Free the list. */
1345  /* Call self again. */
1346  return BPy_Wrap_GetValues(id, prop);
1347  }
1348 
1349  return list;
1350 }
1351 
1352 PyObject *BPy_Wrap_GetItems(ID *id, IDProperty *prop)
1353 {
1354  PyObject *seq = PyList_New(prop->len);
1355  IDProperty *loop;
1356  int i;
1357 
1358  for (i = 0, loop = prop->data.group.first; loop; loop = loop->next, i++) {
1359  PyObject *item = PyTuple_New(2);
1361  item, PyUnicode_FromString(loop->name), BPy_IDGroup_WrapData(id, loop, prop));
1362  PyList_SET_ITEM(seq, i, item);
1363  }
1364 
1365  if (i != prop->len) {
1366  BPy_IDGroup_CorrectListLen(prop, seq, i, __func__);
1367  Py_DECREF(seq); /* Free the list. */
1368  /* Call self again. */
1369  return BPy_Wrap_GetItems(id, prop);
1370  }
1371 
1372  return seq;
1373 }
1374 
1376 {
1377  PyObject *self = prop ? idprop_py_from_idp_group(id, prop, NULL) : NULL;
1379  Py_XDECREF(self); /* Owned by `ret`. */
1380  return ret;
1381 }
1382 
1384 {
1385  PyObject *self = prop ? idprop_py_from_idp_group(id, prop, NULL) : NULL;
1387  Py_XDECREF(self); /* Owned by `ret`. */
1388  return ret;
1389 }
1390 
1392 {
1393  PyObject *self = prop ? idprop_py_from_idp_group(id, prop, NULL) : NULL;
1395  Py_XDECREF(self); /* Owned by `ret`. */
1396  return ret;
1397 }
1398 
1399 PyDoc_STRVAR(BPy_IDGroup_keys_doc,
1400  ".. method:: keys()\n"
1401  "\n"
1402  " Return the keys associated with this group as a list of strings.\n");
1403 static PyObject *BPy_IDGroup_keys(BPy_IDProperty *self)
1404 {
1406 }
1407 
1408 PyDoc_STRVAR(BPy_IDGroup_values_doc,
1409  ".. method:: values()\n"
1410  "\n"
1411  " Return the values associated with this group.\n");
1412 static PyObject *BPy_IDGroup_values(BPy_IDProperty *self)
1413 {
1415 }
1416 
1417 PyDoc_STRVAR(BPy_IDGroup_items_doc,
1418  ".. method:: items()\n"
1419  "\n"
1420  " Iterate through the items in the dict; behaves like dictionary method items.\n");
1421 static PyObject *BPy_IDGroup_items(BPy_IDProperty *self)
1422 {
1424 }
1425 
1426 static int BPy_IDGroup_Contains(BPy_IDProperty *self, PyObject *value)
1427 {
1428  const char *name = PyUnicode_AsUTF8(value);
1429 
1430  if (!name) {
1431  PyErr_Format(PyExc_TypeError, "expected a string, not a %.200s", Py_TYPE(value)->tp_name);
1432  return -1;
1433  }
1434 
1435  return IDP_GetPropertyFromGroup(self->prop, name) ? 1 : 0;
1436 }
1437 
1438 PyDoc_STRVAR(BPy_IDGroup_update_doc,
1439  ".. method:: update(other)\n"
1440  "\n"
1441  " Update key, values.\n"
1442  "\n"
1443  " :arg other: Updates the values in the group with this.\n"
1444  " :type other: :class:`IDPropertyGroup` or dict\n");
1445 static PyObject *BPy_IDGroup_update(BPy_IDProperty *self, PyObject *value)
1446 {
1447  PyObject *pkey, *pval;
1448  Py_ssize_t i = 0;
1449 
1450  if (BPy_IDGroup_Check(value)) {
1451  BPy_IDProperty *other = (BPy_IDProperty *)value;
1452  if (UNLIKELY(self->prop == other->prop)) {
1453  Py_RETURN_NONE;
1454  }
1455 
1456  /* XXX, possible one is inside the other */
1457  IDP_MergeGroup(self->prop, other->prop, true);
1458  }
1459  else if (PyDict_Check(value)) {
1460  while (PyDict_Next(value, &i, &pkey, &pval)) {
1461  BPy_IDGroup_Map_SetItem(self, pkey, pval);
1462  if (PyErr_Occurred()) {
1463  return NULL;
1464  }
1465  }
1466  }
1467  else {
1468  PyErr_Format(PyExc_TypeError,
1469  "expected a dict or an IDPropertyGroup type, not a %.200s",
1470  Py_TYPE(value)->tp_name);
1471  return NULL;
1472  }
1473 
1474  Py_RETURN_NONE;
1475 }
1476 
1477 PyDoc_STRVAR(BPy_IDGroup_to_dict_doc,
1478  ".. method:: to_dict()\n"
1479  "\n"
1480  " Return a purely python version of the group.\n");
1481 static PyObject *BPy_IDGroup_to_dict(BPy_IDProperty *self)
1482 {
1483  return BPy_IDGroup_MapDataToPy(self->prop);
1484 }
1485 
1486 PyDoc_STRVAR(BPy_IDGroup_clear_doc,
1487  ".. method:: clear()\n"
1488  "\n"
1489  " Clear all members from this group.\n");
1490 static PyObject *BPy_IDGroup_clear(BPy_IDProperty *self)
1491 {
1492  IDP_ClearProperty(self->prop);
1493  Py_RETURN_NONE;
1494 }
1495 
1496 PyDoc_STRVAR(BPy_IDGroup_get_doc,
1497  ".. method:: get(key, default=None)\n"
1498  "\n"
1499  " Return the value for key, if it exists, else default.\n");
1500 static PyObject *BPy_IDGroup_get(BPy_IDProperty *self, PyObject *args)
1501 {
1502  IDProperty *idprop;
1503  const char *key;
1504  PyObject *def = Py_None;
1505 
1506  if (!PyArg_ParseTuple(args, "s|O:get", &key, &def)) {
1507  return NULL;
1508  }
1509 
1510  idprop = IDP_GetPropertyFromGroup(self->prop, key);
1511  if (idprop) {
1512  PyObject *pyobj = BPy_IDGroup_WrapData(self->owner_id, idprop, self->prop);
1513  if (pyobj) {
1514  return pyobj;
1515  }
1516  }
1517 
1518  Py_INCREF(def);
1519  return def;
1520 }
1521 
1522 static struct PyMethodDef BPy_IDGroup_methods[] = {
1523  {"pop", (PyCFunction)BPy_IDGroup_pop, METH_VARARGS, BPy_IDGroup_pop_doc},
1524  {"keys", (PyCFunction)BPy_IDGroup_keys, METH_NOARGS, BPy_IDGroup_keys_doc},
1525  {"values", (PyCFunction)BPy_IDGroup_values, METH_NOARGS, BPy_IDGroup_values_doc},
1526  {"items", (PyCFunction)BPy_IDGroup_items, METH_NOARGS, BPy_IDGroup_items_doc},
1527  {"update", (PyCFunction)BPy_IDGroup_update, METH_O, BPy_IDGroup_update_doc},
1528  {"get", (PyCFunction)BPy_IDGroup_get, METH_VARARGS, BPy_IDGroup_get_doc},
1529  {"to_dict", (PyCFunction)BPy_IDGroup_to_dict, METH_NOARGS, BPy_IDGroup_to_dict_doc},
1530  {"clear", (PyCFunction)BPy_IDGroup_clear, METH_NOARGS, BPy_IDGroup_clear_doc},
1531  {NULL, NULL, 0, NULL},
1532 };
1533 
1536 /* -------------------------------------------------------------------- */
1540 static PySequenceMethods BPy_IDGroup_Seq = {
1541  (lenfunc)BPy_IDGroup_Map_Len, /* lenfunc sq_length */
1542  NULL, /* binaryfunc sq_concat */
1543  NULL, /* ssizeargfunc sq_repeat */
1544  NULL,
1545  /* ssizeargfunc sq_item */ /* TODO: setting this will allow PySequence_Check to return True. */
1546  NULL, /* intintargfunc ***was_sq_slice*** */
1547  NULL, /* intobjargproc sq_ass_item */
1548  NULL, /* ssizeobjargproc ***was_sq_ass_slice*** */
1549  (objobjproc)BPy_IDGroup_Contains, /* objobjproc sq_contains */
1550  NULL, /* binaryfunc sq_inplace_concat */
1551  NULL, /* ssizeargfunc sq_inplace_repeat */
1552 };
1553 
1554 static PyMappingMethods BPy_IDGroup_Mapping = {
1555  (lenfunc)BPy_IDGroup_Map_Len, /* inquiry mp_length */
1556  (binaryfunc)BPy_IDGroup_Map_GetItem, /* binaryfunc mp_subscript */
1557  (objobjargproc)BPy_IDGroup_Map_SetItem, /* objobjargproc mp_ass_subscript */
1558 };
1559 
1560 PyTypeObject BPy_IDGroup_Type = {
1561  PyVarObject_HEAD_INIT(NULL, 0)
1562  /* For printing, in format "<module>.<name>" */
1563  "IDPropertyGroup", /* char *tp_name; */
1564  sizeof(BPy_IDProperty), /* int tp_basicsize; */
1565  0, /* tp_itemsize; For allocation */
1566 
1567  /* Methods to implement standard operations */
1568 
1569  NULL, /* destructor tp_dealloc; */
1570  0, /* tp_vectorcall_offset */
1571  NULL, /* getattrfunc tp_getattr; */
1572  NULL, /* setattrfunc tp_setattr; */
1573  NULL, /* cmpfunc tp_compare; */
1574  (reprfunc)BPy_IDGroup_repr, /* reprfunc tp_repr; */
1575 
1576  /* Method suites for standard classes */
1577 
1578  NULL, /* PyNumberMethods *tp_as_number; */
1579  &BPy_IDGroup_Seq, /* PySequenceMethods *tp_as_sequence; */
1580  &BPy_IDGroup_Mapping, /* PyMappingMethods *tp_as_mapping; */
1581 
1582  /* More standard operations (here for binary compatibility) */
1583 
1584  (hashfunc)BPy_IDGroup_hash, /* hashfunc tp_hash; */
1585  NULL, /* ternaryfunc tp_call; */
1586  NULL, /* reprfunc tp_str; */
1587  NULL, /* getattrofunc tp_getattro; */
1588  NULL, /* setattrofunc tp_setattro; */
1589 
1590  /* Functions to access object as input/output buffer */
1591  NULL, /* PyBufferProcs *tp_as_buffer; */
1592 
1593  /*** Flags to define presence of optional/expanded features ***/
1594  Py_TPFLAGS_DEFAULT, /* long tp_flags; */
1595 
1596  NULL, /* char *tp_doc; Documentation string */
1597  /*** Assigned meaning in release 2.0 ***/
1598  /* call function for all accessible objects */
1599  NULL, /* traverseproc tp_traverse; */
1600 
1601  /* delete references to contained objects */
1602  NULL, /* inquiry tp_clear; */
1603 
1604  /*** Assigned meaning in release 2.1 ***/
1605  /*** rich comparisons ***/
1606  NULL, /* richcmpfunc tp_richcompare; */
1607 
1608  /*** weak reference enabler ***/
1609  0, /* long tp_weaklistoffset; */
1610 
1611  /*** Added in release 2.2 ***/
1612  /* Iterators */
1613  (getiterfunc)BPy_IDGroup_iter, /* getiterfunc tp_iter; */
1614  NULL, /* iternextfunc tp_iternext; */
1615  /*** Attribute descriptor and subclassing stuff ***/
1616  BPy_IDGroup_methods, /* struct PyMethodDef *tp_methods; */
1617  NULL, /* struct PyMemberDef *tp_members; */
1618  BPy_IDGroup_getseters, /* struct PyGetSetDef *tp_getset; */
1619 };
1620 
1623 /* -------------------------------------------------------------------- */
1627 static PyTypeObject *idp_array_py_type(BPy_IDArray *self, bool *r_is_double)
1628 {
1629  switch (self->prop->subtype) {
1630  case IDP_FLOAT:
1631  *r_is_double = false;
1632  return &PyFloat_Type;
1633  case IDP_DOUBLE:
1634  *r_is_double = true;
1635  return &PyFloat_Type;
1636  case IDP_INT:
1637  *r_is_double = false;
1638  return &PyLong_Type;
1639  default:
1640  *r_is_double = false;
1641  return NULL;
1642  }
1643 }
1644 
1645 static PyObject *BPy_IDArray_repr(BPy_IDArray *self)
1646 {
1647  return PyUnicode_FromFormat("<bpy id property array [%d]>", self->prop->len);
1648 }
1649 
1650 PyDoc_STRVAR(BPy_IDArray_get_typecode_doc,
1651  "The type of the data in the array {'f': float, 'd': double, 'i': int}.");
1652 static PyObject *BPy_IDArray_get_typecode(BPy_IDArray *self)
1653 {
1654  switch (self->prop->subtype) {
1655  case IDP_FLOAT:
1656  return PyUnicode_FromString("f");
1657  case IDP_DOUBLE:
1658  return PyUnicode_FromString("d");
1659  case IDP_INT:
1660  return PyUnicode_FromString("i");
1661  }
1662 
1663  PyErr_Format(
1664  PyExc_RuntimeError, "%s: invalid/corrupt array type '%d'!", __func__, self->prop->subtype);
1665 
1666  return NULL;
1667 }
1668 
1669 static PyGetSetDef BPy_IDArray_getseters[] = {
1670  /* matches pythons array.typecode */
1671  {"typecode",
1672  (getter)BPy_IDArray_get_typecode,
1673  (setter)NULL,
1674  BPy_IDArray_get_typecode_doc,
1675  NULL},
1676  {NULL, NULL, NULL, NULL, NULL},
1677 };
1678 
1679 PyDoc_STRVAR(BPy_IDArray_to_list_doc,
1680  ".. method:: to_list()\n"
1681  "\n"
1682  " Return the array as a list.\n");
1683 static PyObject *BPy_IDArray_to_list(BPy_IDArray *self)
1684 {
1685  return BPy_IDGroup_MapDataToPy(self->prop);
1686 }
1687 
1688 static PyMethodDef BPy_IDArray_methods[] = {
1689  {"to_list", (PyCFunction)BPy_IDArray_to_list, METH_NOARGS, BPy_IDArray_to_list_doc},
1690  {NULL, NULL, 0, NULL},
1691 };
1692 
1693 static int BPy_IDArray_Len(BPy_IDArray *self)
1694 {
1695  return self->prop->len;
1696 }
1697 
1698 static PyObject *BPy_IDArray_GetItem(BPy_IDArray *self, int index)
1699 {
1700  if (index < 0 || index >= self->prop->len) {
1701  PyErr_SetString(PyExc_IndexError, "index out of range!");
1702  return NULL;
1703  }
1704 
1705  switch (self->prop->subtype) {
1706  case IDP_FLOAT:
1707  return PyFloat_FromDouble(((float *)IDP_Array(self->prop))[index]);
1708  case IDP_DOUBLE:
1709  return PyFloat_FromDouble(((double *)IDP_Array(self->prop))[index]);
1710  case IDP_INT:
1711  return PyLong_FromLong((long)((int *)IDP_Array(self->prop))[index]);
1712  }
1713 
1714  PyErr_Format(
1715  PyExc_RuntimeError, "%s: invalid/corrupt array type '%d'!", __func__, self->prop->subtype);
1716 
1717  return NULL;
1718 }
1719 
1720 static int BPy_IDArray_SetItem(BPy_IDArray *self, int index, PyObject *value)
1721 {
1722  if (index < 0 || index >= self->prop->len) {
1723  PyErr_SetString(PyExc_RuntimeError, "index out of range!");
1724  return -1;
1725  }
1726 
1727  switch (self->prop->subtype) {
1728  case IDP_FLOAT: {
1729  const float f = (float)PyFloat_AsDouble(value);
1730  if (f == -1 && PyErr_Occurred()) {
1731  return -1;
1732  }
1733  ((float *)IDP_Array(self->prop))[index] = f;
1734  break;
1735  }
1736  case IDP_DOUBLE: {
1737  const double d = PyFloat_AsDouble(value);
1738  if (d == -1 && PyErr_Occurred()) {
1739  return -1;
1740  }
1741  ((double *)IDP_Array(self->prop))[index] = d;
1742  break;
1743  }
1744  case IDP_INT: {
1745  const int i = PyC_Long_AsI32(value);
1746  if (i == -1 && PyErr_Occurred()) {
1747  return -1;
1748  }
1749 
1750  ((int *)IDP_Array(self->prop))[index] = i;
1751  break;
1752  }
1753  }
1754  return 0;
1755 }
1756 
1757 static PySequenceMethods BPy_IDArray_Seq = {
1758  (lenfunc)BPy_IDArray_Len, /* inquiry sq_length */
1759  NULL, /* binaryfunc sq_concat */
1760  NULL, /* intargfunc sq_repeat */
1761  (ssizeargfunc)BPy_IDArray_GetItem, /* intargfunc sq_item */
1762  NULL, /* intintargfunc sq_slice */
1763  (ssizeobjargproc)BPy_IDArray_SetItem, /* intobjargproc sq_ass_item */
1764  NULL, /* intintobjargproc sq_ass_slice */
1765  NULL, /* objobjproc sq_contains */
1766  /* Added in release 2.0 */
1767  NULL, /* binaryfunc sq_inplace_concat */
1768  NULL, /* intargfunc sq_inplace_repeat */
1769 };
1770 
1771 /* sequence slice (get): idparr[a:b] */
1772 static PyObject *BPy_IDArray_slice(BPy_IDArray *self, int begin, int end)
1773 {
1774  IDProperty *prop = self->prop;
1775  PyObject *tuple;
1776  int count;
1777 
1778  CLAMP(begin, 0, prop->len);
1779  if (end < 0) {
1780  end = prop->len + end + 1;
1781  }
1782  CLAMP(end, 0, prop->len);
1783  begin = MIN2(begin, end);
1784 
1785  tuple = PyTuple_New(end - begin);
1786 
1787  switch (prop->subtype) {
1788  case IDP_FLOAT: {
1789  const float *array = (float *)IDP_Array(prop);
1790  for (count = begin; count < end; count++) {
1791  PyTuple_SET_ITEM(tuple, count - begin, PyFloat_FromDouble(array[count]));
1792  }
1793  break;
1794  }
1795  case IDP_DOUBLE: {
1796  const double *array = (double *)IDP_Array(prop);
1797  for (count = begin; count < end; count++) {
1798  PyTuple_SET_ITEM(tuple, count - begin, PyFloat_FromDouble(array[count]));
1799  }
1800  break;
1801  }
1802  case IDP_INT: {
1803  const int *array = (int *)IDP_Array(prop);
1804  for (count = begin; count < end; count++) {
1805  PyTuple_SET_ITEM(tuple, count - begin, PyLong_FromLong(array[count]));
1806  }
1807  break;
1808  }
1809  }
1810 
1811  return tuple;
1812 }
1813 /* sequence slice (set): idparr[a:b] = value */
1814 static int BPy_IDArray_ass_slice(BPy_IDArray *self, int begin, int end, PyObject *seq)
1815 {
1816  IDProperty *prop = self->prop;
1817  bool is_double;
1818  const PyTypeObject *py_type = idp_array_py_type(self, &is_double);
1819  const size_t elem_size = is_double ? sizeof(double) : sizeof(float);
1820  size_t alloc_len;
1821  size_t size;
1822  void *vec;
1823 
1824  CLAMP(begin, 0, prop->len);
1825  CLAMP(end, 0, prop->len);
1826  begin = MIN2(begin, end);
1827 
1828  size = (end - begin);
1829  alloc_len = size * elem_size;
1830 
1831  /* NOTE: we count on int/float being the same size here */
1832  vec = MEM_mallocN(alloc_len, "array assignment");
1833 
1834  if (PyC_AsArray(vec, elem_size, seq, size, py_type, "slice assignment: ") == -1) {
1835  MEM_freeN(vec);
1836  return -1;
1837  }
1838 
1839  memcpy((void *)(((char *)IDP_Array(prop)) + (begin * elem_size)), vec, alloc_len);
1840 
1841  MEM_freeN(vec);
1842  return 0;
1843 }
1844 
1845 static PyObject *BPy_IDArray_subscript(BPy_IDArray *self, PyObject *item)
1846 {
1847  if (PyIndex_Check(item)) {
1848  Py_ssize_t i;
1849  i = PyNumber_AsSsize_t(item, PyExc_IndexError);
1850  if (i == -1 && PyErr_Occurred()) {
1851  return NULL;
1852  }
1853  if (i < 0) {
1854  i += self->prop->len;
1855  }
1856  return BPy_IDArray_GetItem(self, i);
1857  }
1858  if (PySlice_Check(item)) {
1859  Py_ssize_t start, stop, step, slicelength;
1860 
1861  if (PySlice_GetIndicesEx(item, self->prop->len, &start, &stop, &step, &slicelength) < 0) {
1862  return NULL;
1863  }
1864 
1865  if (slicelength <= 0) {
1866  return PyTuple_New(0);
1867  }
1868  if (step == 1) {
1869  return BPy_IDArray_slice(self, start, stop);
1870  }
1871 
1872  PyErr_SetString(PyExc_TypeError, "slice steps not supported with vectors");
1873  return NULL;
1874  }
1875 
1876  PyErr_Format(PyExc_TypeError,
1877  "vector indices must be integers, not %.200s",
1878  __func__,
1879  Py_TYPE(item)->tp_name);
1880  return NULL;
1881 }
1882 
1883 static int BPy_IDArray_ass_subscript(BPy_IDArray *self, PyObject *item, PyObject *value)
1884 {
1885  if (PyIndex_Check(item)) {
1886  Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
1887  if (i == -1 && PyErr_Occurred()) {
1888  return -1;
1889  }
1890  if (i < 0) {
1891  i += self->prop->len;
1892  }
1893  return BPy_IDArray_SetItem(self, i, value);
1894  }
1895  if (PySlice_Check(item)) {
1896  Py_ssize_t start, stop, step, slicelength;
1897 
1898  if (PySlice_GetIndicesEx(item, self->prop->len, &start, &stop, &step, &slicelength) < 0) {
1899  return -1;
1900  }
1901 
1902  if (step == 1) {
1903  return BPy_IDArray_ass_slice(self, start, stop, value);
1904  }
1905 
1906  PyErr_SetString(PyExc_TypeError, "slice steps not supported with vectors");
1907  return -1;
1908  }
1909 
1910  PyErr_Format(
1911  PyExc_TypeError, "vector indices must be integers, not %.200s", Py_TYPE(item)->tp_name);
1912  return -1;
1913 }
1914 
1915 static PyMappingMethods BPy_IDArray_AsMapping = {
1916  (lenfunc)BPy_IDArray_Len,
1917  (binaryfunc)BPy_IDArray_subscript,
1918  (objobjargproc)BPy_IDArray_ass_subscript,
1919 };
1920 
1921 static int itemsize_by_idarray_type(int array_type)
1922 {
1923  if (array_type == IDP_INT) {
1924  return sizeof(int);
1925  }
1926  if (array_type == IDP_FLOAT) {
1927  return sizeof(float);
1928  }
1929  if (array_type == IDP_DOUBLE) {
1930  return sizeof(double);
1931  }
1932  return -1; /* should never happen */
1933 }
1934 
1935 static int BPy_IDArray_getbuffer(BPy_IDArray *self, Py_buffer *view, int flags)
1936 {
1937  IDProperty *prop = self->prop;
1938  const int itemsize = itemsize_by_idarray_type(prop->subtype);
1939  const int length = itemsize * prop->len;
1940 
1941  if (PyBuffer_FillInfo(view, (PyObject *)self, IDP_Array(prop), length, false, flags) == -1) {
1942  return -1;
1943  }
1944 
1945  view->itemsize = itemsize;
1946  view->format = (char *)idp_format_from_array_type(prop->subtype);
1947 
1948  Py_ssize_t *shape = MEM_mallocN(sizeof(Py_ssize_t), __func__);
1949  shape[0] = prop->len;
1950  view->shape = shape;
1951 
1952  return 0;
1953 }
1954 
1955 static void BPy_IDArray_releasebuffer(BPy_IDArray *UNUSED(self), Py_buffer *view)
1956 {
1957  MEM_freeN(view->shape);
1958 }
1959 
1960 static PyBufferProcs BPy_IDArray_Buffer = {
1961  (getbufferproc)BPy_IDArray_getbuffer,
1962  (releasebufferproc)BPy_IDArray_releasebuffer,
1963 };
1964 
1967 /* -------------------------------------------------------------------- */
1971 PyTypeObject BPy_IDArray_Type = {
1972  PyVarObject_HEAD_INIT(NULL, 0)
1973  /* For printing, in format "<module>.<name>" */
1974  "IDPropertyArray", /* char *tp_name; */
1975  sizeof(BPy_IDArray), /* int tp_basicsize; */
1976  0, /* tp_itemsize; For allocation */
1977 
1978  /* Methods to implement standard operations */
1979 
1980  NULL, /* destructor tp_dealloc; */
1981  0, /* tp_vectorcall_offset */
1982  NULL, /* getattrfunc tp_getattr; */
1983  NULL, /* setattrfunc tp_setattr; */
1984  NULL, /* cmpfunc tp_compare; */
1985  (reprfunc)BPy_IDArray_repr, /* reprfunc tp_repr; */
1986 
1987  /* Method suites for standard classes */
1988 
1989  NULL, /* PyNumberMethods *tp_as_number; */
1990  &BPy_IDArray_Seq, /* PySequenceMethods *tp_as_sequence; */
1991  &BPy_IDArray_AsMapping, /* PyMappingMethods *tp_as_mapping; */
1992 
1993  /* More standard operations (here for binary compatibility) */
1994 
1995  NULL, /* hashfunc tp_hash; */
1996  NULL, /* ternaryfunc tp_call; */
1997  NULL, /* reprfunc tp_str; */
1998  NULL, /* getattrofunc tp_getattro; */
1999  NULL, /* setattrofunc tp_setattro; */
2000 
2001  /* Functions to access object as input/output buffer */
2002  &BPy_IDArray_Buffer, /* PyBufferProcs *tp_as_buffer; */
2003 
2004  /*** Flags to define presence of optional/expanded features ***/
2005  Py_TPFLAGS_DEFAULT, /* long tp_flags; */
2006 
2007  NULL, /* char *tp_doc; Documentation string */
2008  /*** Assigned meaning in release 2.0 ***/
2009  /* call function for all accessible objects */
2010  NULL, /* traverseproc tp_traverse; */
2011 
2012  /* delete references to contained objects */
2013  NULL, /* inquiry tp_clear; */
2014 
2015  /*** Assigned meaning in release 2.1 ***/
2016  /*** rich comparisons ***/
2017  NULL, /* richcmpfunc tp_richcompare; */
2018 
2019  /*** weak reference enabler ***/
2020  0, /* long tp_weaklistoffset; */
2021 
2022  /*** Added in release 2.2 ***/
2023  /* Iterators */
2024  NULL, /* getiterfunc tp_iter; */
2025  NULL, /* iternextfunc tp_iternext; */
2026 
2027  /*** Attribute descriptor and subclassing stuff ***/
2028  BPy_IDArray_methods, /* struct PyMethodDef *tp_methods; */
2029  NULL, /* struct PyMemberDef *tp_members; */
2030  BPy_IDArray_getseters, /* struct PyGetSetDef *tp_getset; */
2031  NULL, /* struct _typeobject *tp_base; */
2032  NULL, /* PyObject *tp_dict; */
2033  NULL, /* descrgetfunc tp_descr_get; */
2034  NULL, /* descrsetfunc tp_descr_set; */
2035  0, /* long tp_dictoffset; */
2036  NULL, /* initproc tp_init; */
2037  NULL, /* allocfunc tp_alloc; */
2038  NULL, /* newfunc tp_new; */
2039  /* Low-level free-memory routine */
2040  NULL, /* freefunc tp_free; */
2041  /* For PyObject_IS_GC */
2042  NULL, /* inquiry tp_is_gc; */
2043  NULL, /* PyObject *tp_bases; */
2044  /* method resolution order */
2045  NULL, /* PyObject *tp_mro; */
2046  NULL, /* PyObject *tp_cache; */
2047  NULL, /* PyObject *tp_subclasses; */
2048  NULL, /* PyObject *tp_weaklist; */
2049  NULL,
2050 };
2051 
2054 /* -------------------------------------------------------------------- */
2059 {
2062 
2063  PyType_Ready(&BPy_IDGroup_Type);
2064  PyType_Ready(&BPy_IDArray_Type);
2065 
2066  PyType_Ready(&BPy_IDGroup_IterKeys_Type);
2067  PyType_Ready(&BPy_IDGroup_IterValues_Type);
2068  PyType_Ready(&BPy_IDGroup_IterItems_Type);
2069 
2070  PyType_Ready(&BPy_IDGroup_ViewKeys_Type);
2071  PyType_Ready(&BPy_IDGroup_ViewValues_Type);
2072  PyType_Ready(&BPy_IDGroup_ViewItems_Type);
2073 }
2074 
2083 {
2084  BLI_assert(group ? group->prop->type == IDP_GROUP : true);
2085  BPy_IDGroup_View *iter = PyObject_GC_New(BPy_IDGroup_View, type);
2086  iter->reversed = false;
2087  iter->group = group;
2088  if (group != NULL) {
2089  Py_INCREF(group);
2090  PyObject_GC_Track(iter);
2091  }
2092  return iter;
2093 }
2094 
2096 {
2097  return (PyObject *)IDGroup_View_New_WithType(group, &BPy_IDGroup_ViewKeys_Type);
2098 }
2099 
2101 {
2102  return (PyObject *)IDGroup_View_New_WithType(group, &BPy_IDGroup_ViewValues_Type);
2103 }
2104 
2106 {
2107  return (PyObject *)IDGroup_View_New_WithType(group, &BPy_IDGroup_ViewItems_Type);
2108 }
2109 
2112 /* -------------------------------------------------------------------- */
2116 static struct PyModuleDef IDProp_types_module_def = {
2117  PyModuleDef_HEAD_INIT,
2118  "idprop.types", /* m_name */
2119  NULL, /* m_doc */
2120  0, /* m_size */
2121  NULL, /* m_methods */
2122  NULL, /* m_reload */
2123  NULL, /* m_traverse */
2124  NULL, /* m_clear */
2125  NULL, /* m_free */
2126 };
2127 
2128 static PyObject *BPyInit_idprop_types(void)
2129 {
2130  PyObject *submodule;
2131 
2132  submodule = PyModule_Create(&IDProp_types_module_def);
2133 
2136 
2137  /* bmesh_py_types.c */
2138  PyModule_AddType(submodule, &BPy_IDGroup_Type);
2139 
2140  PyModule_AddType(submodule, &BPy_IDGroup_ViewKeys_Type);
2141  PyModule_AddType(submodule, &BPy_IDGroup_ViewValues_Type);
2142  PyModule_AddType(submodule, &BPy_IDGroup_ViewItems_Type);
2143 
2144  PyModule_AddType(submodule, &BPy_IDGroup_IterKeys_Type);
2145  PyModule_AddType(submodule, &BPy_IDGroup_IterValues_Type);
2146  PyModule_AddType(submodule, &BPy_IDGroup_IterItems_Type);
2147 
2148  PyModule_AddType(submodule, &BPy_IDArray_Type);
2149 
2150  return submodule;
2151 }
2152 
2155 /* -------------------------------------------------------------------- */
2159 static PyMethodDef IDProp_methods[] = {
2160  {NULL, NULL, 0, NULL},
2161 };
2162 
2163 PyDoc_STRVAR(IDProp_module_doc,
2164  "This module provides access id property types (currently mainly for docs).");
2165 static struct PyModuleDef IDProp_module_def = {
2166  PyModuleDef_HEAD_INIT,
2167  "idprop", /* m_name */
2168  IDProp_module_doc, /* m_doc */
2169  0, /* m_size */
2170  IDProp_methods, /* m_methods */
2171  NULL, /* m_reload */
2172  NULL, /* m_traverse */
2173  NULL, /* m_clear */
2174  NULL, /* m_free */
2175 };
2176 
2177 PyObject *BPyInit_idprop(void)
2178 {
2179  PyObject *mod;
2180  PyObject *submodule;
2181  PyObject *sys_modules = PyImport_GetModuleDict();
2182 
2183  mod = PyModule_Create(&IDProp_module_def);
2184 
2185  /* idprop.types */
2186  PyModule_AddObject(mod, "types", (submodule = BPyInit_idprop_types()));
2187  PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule);
2188 
2189  return mod;
2190 }
2191 
typedef float(TangentPoint)[2]
#define IDP_Float(prop)
Definition: BKE_idprop.h:269
#define IDP_IDPArray(prop)
Definition: BKE_idprop.h:272
#define IDP_Int(prop)
Definition: BKE_idprop.h:244
void IDP_AppendArray(struct IDProperty *prop, struct IDProperty *item)
Definition: idprop.c:133
void IDP_FreePropertyContent(struct IDProperty *prop)
Definition: idprop.c:1082
struct IDProperty * IDP_New(char type, const IDPropertyTemplate *val, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: idprop.c:887
struct IDProperty * IDP_NewIDPArray(const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: idprop.c:63
void IDP_ReplaceInGroup_ex(struct IDProperty *group, struct IDProperty *prop, struct IDProperty *prop_exist)
Definition: idprop.c:563
#define IDP_String(prop)
Definition: BKE_idprop.h:271
#define IDP_Double(prop)
Definition: BKE_idprop.h:270
void IDP_MergeGroup(struct IDProperty *dest, const struct IDProperty *src, bool do_overwrite) ATTR_NONNULL()
void IDP_FreeProperty(struct IDProperty *prop)
Definition: idprop.c:1093
void IDP_ResizeArray(struct IDProperty *prop, int newlen)
Definition: idprop.c:211
struct IDProperty * IDP_GetPropertyFromGroup(const struct IDProperty *prop, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
void IDP_FreeFromGroup(struct IDProperty *group, struct IDProperty *prop) ATTR_NONNULL()
Definition: idprop.c:666
void IDP_ClearProperty(struct IDProperty *prop)
Definition: idprop.c:1099
#define IDP_Array(prop)
Definition: BKE_idprop.h:245
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define UNUSED(x)
#define UNLIKELY(x)
#define MIN2(a, b)
typedef double(DMatrix)[4][4]
ID and Library types, which are fundamental for sdna.
@ IDP_STRING_SUB_UTF8
Definition: DNA_ID.h:164
@ IDP_STRING_SUB_BYTE
Definition: DNA_ID.h:165
@ IDP_DOUBLE
Definition: DNA_ID.h:143
@ IDP_FLOAT
Definition: DNA_ID.h:138
@ IDP_STRING
Definition: DNA_ID.h:136
@ IDP_IDPARRAY
Definition: DNA_ID.h:144
@ IDP_INT
Definition: DNA_ID.h:137
@ IDP_GROUP
Definition: DNA_ID.h:141
@ IDP_ARRAY
Definition: DNA_ID.h:140
@ IDP_ID
Definition: DNA_ID.h:142
#define MAX_IDPROP_NAME
Definition: DNA_ID.h:131
static AppView * view
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
Read Guarded memory(de)allocation.
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Bright Control the brightness and contrast of the input color Vector Map an input vectors to used to fine tune the interpolation of the input Camera Retrieve information about the camera and how it relates to the current shading point s position CLAMP
PyObject * self
Definition: bpy_driver.c:165
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
SyclQueue void void size_t num_bytes void
int len
Definition: draw_manager.c:108
void IDProp_Init_Types(void)
static PyMethodDef IDProp_methods[]
static int BPy_Group_ViewItems_Contains(BPy_IDGroup_View *self, PyObject *value)
static PySequenceMethods BPy_IDGroup_ViewItems_as_sequence
PyTypeObject BPy_IDGroup_ViewItems_Type
static PyGetSetDef BPy_IDGroup_getseters[]
PyDoc_STRVAR(BPy_IDGroup_View_reversed_doc, "Return a reverse iterator over the ID Property keys values or items.")
PyTypeObject BPy_IDGroup_ViewValues_Type
static struct PyModuleDef IDProp_module_def
static PyObject * BPy_IDGroup_IterItems_CreatePyObject(BPy_IDProperty *group, const bool reversed)
static int BPy_Group_ViewKeys_Contains(BPy_IDGroup_View *self, PyObject *value)
static PyObject * BPy_IDGroup_pop(BPy_IDProperty *self, PyObject *args)
static PyObject * BPy_IDGroup_View_reversed(BPy_IDGroup_View *self, PyObject *UNUSED(ignored))
static PyObject * BPy_IDArray_slice(BPy_IDArray *self, int begin, int end)
static PyObject * BPy_IDGroup_get(BPy_IDProperty *self, PyObject *args)
static PyObject * BPy_IDGroup_IterValues_CreatePyObject(BPy_IDProperty *group, const bool reversed)
static PyObject * BPy_IDGroup_keys(BPy_IDProperty *self)
static PyObject * BPyInit_idprop_types(void)
static struct PyMethodDef BPy_IDGroup_methods[]
PyTypeObject BPy_IDGroup_ViewKeys_Type
static IDProperty * idp_from_PyBytes(const char *name, PyObject *ob)
bool pyrna_id_CheckPyObject(PyObject *obj)
Definition: bpy_rna.c:7668
static void IDGroup_Iter_init_type(void)
static PyObject * BPy_IDArray_GetItem(BPy_IDArray *self, int index)
static PyObject * BPy_IDGroup_IterKeys_CreatePyObject(BPy_IDProperty *group, const bool reversed)
static PyMethodDef BPy_IDGroup_View_methods[]
static PyObject * BPy_Group_IterItems_next(BPy_IDGroup_Iter *self)
static PyGetSetDef BPy_IDArray_getseters[]
static PyObject * BPy_IDGroup_values(BPy_IDProperty *self)
static PyObject * BPy_IDGroup_View_repr(BPy_IDGroup_View *self)
int BPy_Wrap_SetMapItem(IDProperty *prop, PyObject *key, PyObject *val)
static PyObject * IDGroup_Iter_New_WithType(BPy_IDProperty *group, const bool reversed, PyTypeObject *type)
static void BPy_IDGroup_Iter_dealloc(BPy_IDGroup_Iter *self)
PyObject * BPy_IDGroup_MapDataToPy(IDProperty *prop)
static int BPy_IDGroup_View_traverse(BPy_IDGroup_View *self, visitproc visit, void *arg)
static IDProperty * idp_from_PyLong(const char *name, PyObject *ob)
static PyObject * BPy_Group_IterValues_next(BPy_IDGroup_Iter *self)
static PyObject * BPy_Group_ViewValues_iter(BPy_IDGroup_View *self)
static PyMethodDef BPy_IDArray_methods[]
static Py_ssize_t BPy_Group_View_len(BPy_IDGroup_View *self)
static IDProperty * idp_from_PyFloat(const char *name, PyObject *ob)
static PyObject * BPy_IDGroup_GetName(BPy_IDProperty *self, void *UNUSED(closure))
static int BPy_IDArray_ass_subscript(BPy_IDArray *self, PyObject *item, PyObject *value)
static const char * idp_format_from_array_type(int type)
static BPy_IDGroup_View * IDGroup_View_New_WithType(BPy_IDProperty *group, PyTypeObject *type)
static PyObject * BPy_IDArray_repr(BPy_IDArray *self)
PyObject * BPy_Wrap_GetItems(ID *id, IDProperty *prop)
PyTypeObject BPy_IDGroup_IterKeys_Type
static PyObject * BPy_IDArray_subscript(BPy_IDArray *self, PyObject *item)
static PyTypeObject * idp_array_py_type(BPy_IDArray *self, bool *r_is_double)
static PyObject * BPy_IDArray_to_list(BPy_IDArray *self)
PyObject * BPy_Wrap_GetKeys_View_WithID(ID *id, IDProperty *prop)
static PyObject * BPy_IDGroup_repr(BPy_IDProperty *self)
static int itemsize_by_idarray_type(int array_type)
static PyObject * idprop_py_from_idp_double(const IDProperty *prop)
Definition: idprop_py_api.c:73
static PyObject * BPy_Group_ViewItems_iter(BPy_IDGroup_View *self)
static const char * idp_try_read_name(PyObject *name_obj)
static PyObject * BPy_IDGroup_clear(BPy_IDProperty *self)
static void BPy_IDArray_releasebuffer(BPy_IDArray *UNUSED(self), Py_buffer *view)
static PySequenceMethods BPy_IDGroup_ViewValues_as_sequence
PyTypeObject BPy_IDGroup_Type
bool BPy_IDProperty_Map_ValidateAndCreate(PyObject *name_obj, IDProperty *group, PyObject *ob)
PyTypeObject BPy_IDArray_Type
PyObject * BPy_Wrap_GetValues(ID *id, IDProperty *prop)
static int BPy_IDGroup_Iter_clear(BPy_IDGroup_Iter *self)
static void IDGroup_View_init_type(void)
static PyObject * idprop_py_from_idp_array(ID *id, IDProperty *prop)
Definition: idprop_py_api.c:92
static PyObject * BPy_Group_IterKeys_next(BPy_IDGroup_Iter *self)
static PySequenceMethods BPy_IDGroup_Seq
static int BPy_IDGroup_Contains(BPy_IDProperty *self, PyObject *value)
PyTypeObject BPy_IDGroup_IterValues_Type
static PyObject * BPy_Group_ViewKeys_iter(BPy_IDGroup_View *self)
static int BPy_Group_ViewValues_Contains(BPy_IDGroup_View *self, PyObject *value)
PyObject * BPy_Wrap_GetKeys(IDProperty *prop)
static PyBufferProcs BPy_IDArray_Buffer
static bool BPy_Group_Iter_same_size_or_raise_error(BPy_IDGroup_Iter *self)
static PyObject * BPy_IDArray_get_typecode(BPy_IDArray *self)
static PyObject * idprop_py_from_idp_idparray(ID *id, IDProperty *prop)
static IDProperty * idp_from_PySequence(const char *name, PyObject *ob)
static void BPy_IDGroup_View_dealloc(BPy_IDGroup_View *self)
static void BPy_IDGroup_CorrectListLen(IDProperty *prop, PyObject *seq, int len, const char *func)
PyObject * BPy_IDGroup_WrapData(ID *id, IDProperty *prop, IDProperty *parent)
static PySequenceMethods BPy_IDArray_Seq
static PyObject * BPy_IDGroup_Map_GetItem(BPy_IDProperty *self, PyObject *item)
static PyObject * BPy_IDGroup_ViewKeys_CreatePyObject(BPy_IDProperty *group)
static IDProperty * idp_from_PyMapping(const char *name, PyObject *ob)
static PyMappingMethods BPy_IDArray_AsMapping
static IDProperty * idp_from_PyObject(PyObject *name_obj, PyObject *ob)
static IDProperty * idp_from_PySequence_Fast(const char *name, PyObject *ob)
static PyObject * BPy_IDGroup_ViewItems_CreatePyObject(BPy_IDProperty *group)
PyObject * BPyInit_idprop(void)
PyObject * BPy_Wrap_GetValues_View_WithID(ID *id, IDProperty *prop)
static PyObject * idprop_py_from_idp_float(const IDProperty *prop)
Definition: idprop_py_api.c:68
static int BPy_IDArray_Len(BPy_IDArray *self)
static PyObject * idprop_py_from_idp_string(const IDProperty *prop)
Definition: idprop_py_api.c:50
static PySequenceMethods BPy_IDGroup_ViewKeys_as_sequence
static PyObject * idprop_py_from_idp_group(ID *id, IDProperty *prop, IDProperty *parent)
Definition: idprop_py_api.c:78
static Py_ssize_t BPy_IDGroup_Map_Len(BPy_IDProperty *self)
static IDProperty * idp_from_PySequence_Buffer(const char *name, Py_buffer *buffer)
static char idp_sequence_type(PyObject *seq_fast)
static PyObject * idprop_py_from_idp_id(IDProperty *prop)
Definition: idprop_py_api.c:87
static int BPy_IDArray_SetItem(BPy_IDArray *self, int index, PyObject *value)
static int BPy_IDGroup_Map_SetItem(BPy_IDProperty *self, PyObject *key, PyObject *val)
static int BPy_IDGroup_View_clear(BPy_IDGroup_View *self)
PyObject * pyrna_id_CreatePyObject(ID *id)
Definition: bpy_rna.c:7646
static PyObject * BPy_IDGroup_items(BPy_IDProperty *self)
static PyObject * idprop_py_from_idp_int(const IDProperty *prop)
Definition: idprop_py_api.c:63
static int BPy_IDArray_ass_slice(BPy_IDArray *self, int begin, int end, PyObject *seq)
static struct PyModuleDef IDProp_types_module_def
bool pyrna_id_FromPyObject(PyObject *obj, ID **id)
Definition: bpy_rna.c:7657
static PyObject * BPy_IDGroup_iter(BPy_IDProperty *self)
static int BPy_IDArray_getbuffer(BPy_IDArray *self, Py_buffer *view, int flags)
static PyObject * BPy_IDGroup_to_dict(BPy_IDProperty *self)
static PyObject * BPy_IDGroup_update(BPy_IDProperty *self, PyObject *value)
PyTypeObject BPy_IDGroup_IterItems_Type
static PyObject * BPy_IDGroup_Iter_repr(BPy_IDGroup_Iter *self)
static PyObject * BPy_IDGroup_ViewValues_CreatePyObject(BPy_IDProperty *group)
static Py_hash_t BPy_IDGroup_hash(BPy_IDProperty *self)
static int idp_array_type_from_formatstr_and_size(const char *typestr, Py_ssize_t itemsize)
static int BPy_IDGroup_Iter_traverse(BPy_IDGroup_Iter *self, visitproc visit, void *arg)
static IDProperty * idp_from_DatablockPointer(const char *name, PyObject *ob)
static IDProperty * idp_from_PyUnicode(const char *name, PyObject *ob)
#define SHARED_MEMBER_SET(member, value)
PyObject * BPy_Wrap_GetItems_View_WithID(ID *id, IDProperty *prop)
static int BPy_IDGroup_SetName(BPy_IDProperty *self, PyObject *value, void *UNUSED(closure))
static PyMappingMethods BPy_IDGroup_Mapping
#define BPy_IDGroup_Check(v)
Definition: idprop_py_api.h:26
struct BPy_IDProperty BPy_IDProperty
struct BPy_IDArray BPy_IDArray
void IDPropertyUIData_Init_Types()
int count
ccl_global float * buffer
format
Definition: logImageCore.h:38
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
static struct PartialUpdateUser * wrap(PartialUpdateUserImpl *user)
T length(const vec_base< T, Size > &a)
static const pxr::TfToken st("st", pxr::TfToken::Immortal)
char PyC_StructFmt_type_from_str(const char *typestr)
const char * PyC_UnicodeAsByte(PyObject *py_str, PyObject **coerce)
PyObject * PyC_UnicodeFromByteAndSize(const char *str, Py_ssize_t size)
bool PyC_StructFmt_type_is_int_any(char format)
int PyC_AsArray(void *array, const size_t array_item_size, PyObject *value, const Py_ssize_t length, const PyTypeObject *type, const char *error_prefix)
const char * PyC_UnicodeAsByteAndSize(PyObject *py_str, Py_ssize_t *size, PyObject **coerce)
bool PyC_StructFmt_type_is_float_any(char format)
header-only utilities
#define PyTuple_SET_ITEMS(op_arg,...)
return ret
struct IDProperty * cur
Definition: idprop_py_api.h:59
PyObject_VAR_HEAD BPy_IDProperty * group
Definition: idprop_py_api.h:58
PyObject_VAR_HEAD BPy_IDProperty * group
Definition: idprop_py_api.h:70
PyObject_VAR_HEAD struct ID * owner_id
Definition: idprop_py_api.h:45
struct IDProperty * parent
Definition: idprop_py_api.h:47
struct IDProperty * prop
Definition: idprop_py_api.h:46
ListBase group
Definition: DNA_ID.h:101
void * pointer
Definition: DNA_ID.h:100
short flag
Definition: DNA_ID.h:109
int len
Definition: DNA_ID.h:121
struct IDProperty * next
Definition: DNA_ID.h:107
IDPropertyUIData * ui_data
Definition: DNA_ID.h:128
char name[64]
Definition: DNA_ID.h:111
IDPropertyData data
Definition: DNA_ID.h:117
struct IDProperty * prev
Definition: DNA_ID.h:107
char subtype
Definition: DNA_ID.h:108
char type
Definition: DNA_ID.h:108
Definition: DNA_ID.h:368
void * last
Definition: DNA_listBase.h:31
void * first
Definition: DNA_listBase.h:31
struct IDPropertyTemplate::@27 array
const char * str
Definition: BKE_idprop.h:29
struct ID * id
Definition: BKE_idprop.h:33
struct IDPropertyTemplate::@26 string
ccl_device_inline int mod(int x, int m)
Definition: util/math.h:490