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