PyAPI: use iterators for ID property methods (keys, values & items)
- Matches changes in Python 3.x dictionary methods. - Iterating now raises a run-time error if the property-group changes size during iteration. - IDPropertyGroup.iteritems() has been removed. - IDPropertyGroup View & Iterator types have been added. - Some set functionality from dict_keys/values/items aren't yet supported (isdisjoint method and boolean set style operations). Proposed as part of T85675.
This commit is contained in:
@@ -42,6 +42,18 @@ extern bool pyrna_id_FromPyObject(PyObject *obj, ID **id);
|
||||
extern PyObject *pyrna_id_CreatePyObject(ID *id);
|
||||
extern bool pyrna_id_CheckPyObject(PyObject *obj);
|
||||
|
||||
/* Currently there is no need to expose this publicly. */
|
||||
static PyObject *BPy_IDGroup_IterKeys_CreatePyObject(BPy_IDProperty *group, const bool reversed);
|
||||
static PyObject *BPy_IDGroup_IterValues_CreatePyObject(BPy_IDProperty *group, const bool reversed);
|
||||
static PyObject *BPy_IDGroup_IterItems_CreatePyObject(BPy_IDProperty *group, const bool reversed);
|
||||
|
||||
static PyObject *BPy_IDGroup_ViewKeys_CreatePyObject(BPy_IDProperty *group);
|
||||
static PyObject *BPy_IDGroup_ViewValues_CreatePyObject(BPy_IDProperty *group);
|
||||
static PyObject *BPy_IDGroup_ViewItems_CreatePyObject(BPy_IDProperty *group);
|
||||
|
||||
static BPy_IDGroup_View *IDGroup_View_New_WithType(BPy_IDProperty *group, PyTypeObject *type);
|
||||
static int BPy_IDGroup_Contains(BPy_IDProperty *self, PyObject *value);
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Python from ID-Property (Internal Conversions)
|
||||
*
|
||||
@@ -756,13 +768,7 @@ static int BPy_IDGroup_Map_SetItem(BPy_IDProperty *self, PyObject *key, PyObject
|
||||
|
||||
static PyObject *BPy_IDGroup_iter(BPy_IDProperty *self)
|
||||
{
|
||||
BPy_IDGroup_Iter *iter = PyObject_GC_New(BPy_IDGroup_Iter, &BPy_IDGroup_Iter_Type);
|
||||
iter->group = self;
|
||||
Py_INCREF(self);
|
||||
iter->mode = IDPROP_ITER_KEYS;
|
||||
iter->cur = self->prop->data.group.first;
|
||||
PyObject_GC_Track(iter);
|
||||
return (PyObject *)iter;
|
||||
return BPy_IDGroup_ViewKeys_CreatePyObject(self);
|
||||
}
|
||||
|
||||
/* for simple, non nested types this is the same as BPy_IDGroup_WrapData */
|
||||
@@ -874,6 +880,370 @@ PyObject *BPy_IDGroup_MapDataToPy(IDProperty *prop)
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name ID-Property Group Iterator Type
|
||||
* \{ */
|
||||
|
||||
static PyObject *BPy_IDGroup_Iter_repr(BPy_IDGroup_Iter *self)
|
||||
{
|
||||
if (self->group == NULL) {
|
||||
return PyUnicode_FromFormat("<%s>", Py_TYPE(self)->tp_name);
|
||||
}
|
||||
return PyUnicode_FromFormat("<%s \"%s\">", Py_TYPE(self)->tp_name, self->group->prop->name);
|
||||
}
|
||||
|
||||
static void BPy_IDGroup_Iter_dealloc(BPy_IDGroup_Iter *self)
|
||||
{
|
||||
if (self->group != NULL) {
|
||||
PyObject_GC_UnTrack(self);
|
||||
}
|
||||
Py_CLEAR(self->group);
|
||||
PyObject_GC_Del(self);
|
||||
}
|
||||
|
||||
static int BPy_IDGroup_Iter_traverse(BPy_IDGroup_Iter *self, visitproc visit, void *arg)
|
||||
{
|
||||
Py_VISIT(self->group);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int BPy_IDGroup_Iter_clear(BPy_IDGroup_Iter *self)
|
||||
{
|
||||
Py_CLEAR(self->group);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool BPy_Group_Iter_same_size_or_raise_error(BPy_IDGroup_Iter *self)
|
||||
{
|
||||
if (self->len_init == self->group->prop->len) {
|
||||
return true;
|
||||
}
|
||||
PyErr_SetString(PyExc_RuntimeError, "IDPropertyGroup changed size during iteration");
|
||||
return false;
|
||||
}
|
||||
|
||||
static PyObject *BPy_Group_IterKeys_next(BPy_IDGroup_Iter *self)
|
||||
{
|
||||
if (self->cur != NULL) {
|
||||
/* When `cur` is set, `group` cannot be NULL. */
|
||||
if (!BPy_Group_Iter_same_size_or_raise_error(self)) {
|
||||
return NULL;
|
||||
}
|
||||
IDProperty *cur = self->cur;
|
||||
self->cur = self->reversed ? self->cur->prev : self->cur->next;
|
||||
return PyUnicode_FromString(cur->name);
|
||||
}
|
||||
PyErr_SetNone(PyExc_StopIteration);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static PyObject *BPy_Group_IterValues_next(BPy_IDGroup_Iter *self)
|
||||
{
|
||||
if (self->cur != NULL) {
|
||||
/* When `cur` is set, `group` cannot be NULL. */
|
||||
if (!BPy_Group_Iter_same_size_or_raise_error(self)) {
|
||||
return NULL;
|
||||
}
|
||||
IDProperty *cur = self->cur;
|
||||
self->cur = self->reversed ? self->cur->prev : self->cur->next;
|
||||
return BPy_IDGroup_WrapData(self->group->id, cur, self->group->prop);
|
||||
}
|
||||
PyErr_SetNone(PyExc_StopIteration);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static PyObject *BPy_Group_IterItems_next(BPy_IDGroup_Iter *self)
|
||||
{
|
||||
if (self->cur != NULL) {
|
||||
/* When `cur` is set, `group` cannot be NULL. */
|
||||
if (!BPy_Group_Iter_same_size_or_raise_error(self)) {
|
||||
return NULL;
|
||||
}
|
||||
IDProperty *cur = self->cur;
|
||||
self->cur = self->reversed ? self->cur->prev : self->cur->next;
|
||||
PyObject *ret = PyTuple_New(2);
|
||||
PyTuple_SET_ITEMS(ret,
|
||||
PyUnicode_FromString(cur->name),
|
||||
BPy_IDGroup_WrapData(self->group->id, cur, self->group->prop));
|
||||
return ret;
|
||||
}
|
||||
PyErr_SetNone(PyExc_StopIteration);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyTypeObject BPy_IDGroup_IterKeys_Type = {PyVarObject_HEAD_INIT(NULL, 0)};
|
||||
PyTypeObject BPy_IDGroup_IterValues_Type = {PyVarObject_HEAD_INIT(NULL, 0)};
|
||||
PyTypeObject BPy_IDGroup_IterItems_Type = {PyVarObject_HEAD_INIT(NULL, 0)};
|
||||
|
||||
/* ID Property Group Iterator. */
|
||||
static void IDGroup_Iter_init_type(void)
|
||||
{
|
||||
#define SHARED_MEMBER_SET(member, value) \
|
||||
{ \
|
||||
k_ty->member = v_ty->member = i_ty->member = value; \
|
||||
} \
|
||||
((void)0)
|
||||
|
||||
PyTypeObject *k_ty = &BPy_IDGroup_IterKeys_Type;
|
||||
PyTypeObject *v_ty = &BPy_IDGroup_IterValues_Type;
|
||||
PyTypeObject *i_ty = &BPy_IDGroup_IterItems_Type;
|
||||
|
||||
/* Unique members. */
|
||||
k_ty->tp_name = "IDPropertyGroupIterKeys";
|
||||
v_ty->tp_name = "IDPropertyGroupIterValues";
|
||||
i_ty->tp_name = "IDPropertyGroupIterItems";
|
||||
|
||||
k_ty->tp_iternext = (iternextfunc)BPy_Group_IterKeys_next;
|
||||
v_ty->tp_iternext = (iternextfunc)BPy_Group_IterValues_next;
|
||||
i_ty->tp_iternext = (iternextfunc)BPy_Group_IterItems_next;
|
||||
|
||||
/* Shared members. */
|
||||
SHARED_MEMBER_SET(tp_basicsize, sizeof(BPy_IDGroup_Iter));
|
||||
SHARED_MEMBER_SET(tp_dealloc, (destructor)BPy_IDGroup_Iter_dealloc);
|
||||
SHARED_MEMBER_SET(tp_repr, (reprfunc)BPy_IDGroup_Iter_repr);
|
||||
SHARED_MEMBER_SET(tp_flags, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC);
|
||||
SHARED_MEMBER_SET(tp_traverse, (traverseproc)BPy_IDGroup_Iter_traverse);
|
||||
SHARED_MEMBER_SET(tp_clear, (inquiry)BPy_IDGroup_Iter_clear);
|
||||
SHARED_MEMBER_SET(tp_iter, PyObject_SelfIter);
|
||||
|
||||
#undef SHARED_MEMBER_SET
|
||||
}
|
||||
|
||||
static PyObject *IDGroup_Iter_New_WithType(BPy_IDProperty *group,
|
||||
const bool reversed,
|
||||
PyTypeObject *type)
|
||||
{
|
||||
BLI_assert(group ? group->prop->type == IDP_GROUP : true);
|
||||
BPy_IDGroup_Iter *iter = PyObject_GC_New(BPy_IDGroup_Iter, type);
|
||||
iter->reversed = reversed;
|
||||
iter->group = group;
|
||||
if (group != NULL) {
|
||||
Py_INCREF(group);
|
||||
PyObject_GC_Track(iter);
|
||||
iter->cur = (reversed ? group->prop->data.group.last : group->prop->data.group.first);
|
||||
iter->len_init = group->prop->len;
|
||||
}
|
||||
else {
|
||||
iter->cur = NULL;
|
||||
iter->len_init = 0;
|
||||
}
|
||||
return (PyObject *)iter;
|
||||
}
|
||||
|
||||
static PyObject *BPy_IDGroup_IterKeys_CreatePyObject(BPy_IDProperty *group, const bool reversed)
|
||||
{
|
||||
return IDGroup_Iter_New_WithType(group, reversed, &BPy_IDGroup_IterKeys_Type);
|
||||
}
|
||||
|
||||
static PyObject *BPy_IDGroup_IterValues_CreatePyObject(BPy_IDProperty *group, const bool reversed)
|
||||
{
|
||||
return IDGroup_Iter_New_WithType(group, reversed, &BPy_IDGroup_IterValues_Type);
|
||||
}
|
||||
|
||||
static PyObject *BPy_IDGroup_IterItems_CreatePyObject(BPy_IDProperty *group, const bool reversed)
|
||||
{
|
||||
return IDGroup_Iter_New_WithType(group, reversed, &BPy_IDGroup_IterItems_Type);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name ID-Property Group View Types (Keys/Values/Items)
|
||||
*
|
||||
* This view types is a thin wrapper on keys/values/items, this matches Python's `dict_view` type.
|
||||
* The is returned by `property.keys()` and is separate from the iterator that loops over keys.
|
||||
*
|
||||
* There are some less common features this type could support (matching Python's `dict_view`)
|
||||
*
|
||||
* TODO:
|
||||
* - Efficient contains checks for values and items which currently convert to a list first.
|
||||
* - Missing `dict_views.isdisjoint`.
|
||||
* - Missing `tp_as_number` (`nb_subtract`, `nb_and`, `nb_xor`, `nb_or`).
|
||||
* \{ */
|
||||
|
||||
static PyObject *BPy_IDGroup_View_repr(BPy_IDGroup_View *self)
|
||||
{
|
||||
if (self->group == NULL) {
|
||||
return PyUnicode_FromFormat("<%s>", Py_TYPE(self)->tp_name);
|
||||
}
|
||||
return PyUnicode_FromFormat("<%s \"%s\">", Py_TYPE(self)->tp_name, self->group->prop->name);
|
||||
}
|
||||
|
||||
static void BPy_IDGroup_View_dealloc(BPy_IDGroup_View *self)
|
||||
{
|
||||
if (self->group != NULL) {
|
||||
PyObject_GC_UnTrack(self);
|
||||
}
|
||||
Py_CLEAR(self->group);
|
||||
PyObject_GC_Del(self);
|
||||
}
|
||||
|
||||
static int BPy_IDGroup_View_traverse(BPy_IDGroup_View *self, visitproc visit, void *arg)
|
||||
{
|
||||
Py_VISIT(self->group);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int BPy_IDGroup_View_clear(BPy_IDGroup_View *self)
|
||||
{
|
||||
Py_CLEAR(self->group);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* View Specific API's (Key/Value/Items). */
|
||||
|
||||
static PyObject *BPy_Group_ViewKeys_iter(BPy_IDGroup_View *self)
|
||||
{
|
||||
return BPy_IDGroup_IterKeys_CreatePyObject(self->group, self->reversed);
|
||||
}
|
||||
|
||||
static PyObject *BPy_Group_ViewValues_iter(BPy_IDGroup_View *self)
|
||||
{
|
||||
return BPy_IDGroup_IterValues_CreatePyObject(self->group, self->reversed);
|
||||
}
|
||||
|
||||
static PyObject *BPy_Group_ViewItems_iter(BPy_IDGroup_View *self)
|
||||
{
|
||||
return BPy_IDGroup_IterItems_CreatePyObject(self->group, self->reversed);
|
||||
}
|
||||
|
||||
static Py_ssize_t BPy_Group_View_len(BPy_IDGroup_View *self)
|
||||
{
|
||||
if (self->group == NULL) {
|
||||
return 0;
|
||||
}
|
||||
return self->group->prop->len;
|
||||
}
|
||||
|
||||
static int BPy_Group_ViewKeys_Contains(BPy_IDGroup_View *self, PyObject *value)
|
||||
{
|
||||
if (self->group == NULL) {
|
||||
return 0;
|
||||
}
|
||||
return BPy_IDGroup_Contains(self->group, value);
|
||||
}
|
||||
|
||||
static int BPy_Group_ViewValues_Contains(BPy_IDGroup_View *self, PyObject *value)
|
||||
{
|
||||
if (self->group == NULL) {
|
||||
return 0;
|
||||
}
|
||||
/* TODO: implement this without first converting to a list. */
|
||||
PyObject *list = PySequence_List((PyObject *)self);
|
||||
const int result = PySequence_Contains(list, value);
|
||||
Py_DECREF(list);
|
||||
return result;
|
||||
}
|
||||
|
||||
static int BPy_Group_ViewItems_Contains(BPy_IDGroup_View *self, PyObject *value)
|
||||
{
|
||||
if (self->group == NULL) {
|
||||
return 0;
|
||||
}
|
||||
/* TODO: implement this without first converting to a list. */
|
||||
PyObject *list = PySequence_List((PyObject *)self);
|
||||
const int result = PySequence_Contains(list, value);
|
||||
Py_DECREF(list);
|
||||
return result;
|
||||
}
|
||||
|
||||
static PySequenceMethods BPy_IDGroup_ViewKeys_as_sequence = {
|
||||
(lenfunc)BPy_Group_View_len, /* sq_length */
|
||||
0, /* sq_concat */
|
||||
0, /* sq_repeat */
|
||||
0, /* sq_item */
|
||||
0, /* sq_slice */
|
||||
0, /* sq_ass_item */
|
||||
0, /* sq_ass_slice */
|
||||
(objobjproc)BPy_Group_ViewKeys_Contains, /* sq_contains */
|
||||
};
|
||||
|
||||
static PySequenceMethods BPy_IDGroup_ViewValues_as_sequence = {
|
||||
(lenfunc)BPy_Group_View_len, /* sq_length */
|
||||
0, /* sq_concat */
|
||||
0, /* sq_repeat */
|
||||
0, /* sq_item */
|
||||
0, /* sq_slice */
|
||||
0, /* sq_ass_item */
|
||||
0, /* sq_ass_slice */
|
||||
(objobjproc)BPy_Group_ViewValues_Contains, /* sq_contains */
|
||||
};
|
||||
|
||||
static PySequenceMethods BPy_IDGroup_ViewItems_as_sequence = {
|
||||
(lenfunc)BPy_Group_View_len, /* sq_length */
|
||||
0, /* sq_concat */
|
||||
0, /* sq_repeat */
|
||||
0, /* sq_item */
|
||||
0, /* sq_slice */
|
||||
0, /* sq_ass_item */
|
||||
0, /* sq_ass_slice */
|
||||
(objobjproc)BPy_Group_ViewItems_Contains, /* sq_contains */
|
||||
};
|
||||
|
||||
/* Methods. */
|
||||
|
||||
PyDoc_STRVAR(BPy_IDGroup_View_reversed_doc,
|
||||
"Return a reverse iterator over the ID Property keys values or items.");
|
||||
|
||||
static PyObject *BPy_IDGroup_View_reversed(BPy_IDGroup_View *self, PyObject *UNUSED(ignored))
|
||||
{
|
||||
BPy_IDGroup_View *result = IDGroup_View_New_WithType(self->group, Py_TYPE(self));
|
||||
result->reversed = !self->reversed;
|
||||
return (PyObject *)result;
|
||||
}
|
||||
|
||||
static PyMethodDef BPy_IDGroup_View_methods[] = {
|
||||
{"__reversed__",
|
||||
(PyCFunction)(void (*)(void))BPy_IDGroup_View_reversed,
|
||||
METH_NOARGS,
|
||||
BPy_IDGroup_View_reversed_doc},
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
||||
PyTypeObject BPy_IDGroup_ViewKeys_Type = {PyVarObject_HEAD_INIT(NULL, 0)};
|
||||
PyTypeObject BPy_IDGroup_ViewValues_Type = {PyVarObject_HEAD_INIT(NULL, 0)};
|
||||
PyTypeObject BPy_IDGroup_ViewItems_Type = {PyVarObject_HEAD_INIT(NULL, 0)};
|
||||
|
||||
/* ID Property Group View. */
|
||||
static void IDGroup_View_init_type(void)
|
||||
{
|
||||
PyTypeObject *k_ty = &BPy_IDGroup_ViewKeys_Type;
|
||||
PyTypeObject *v_ty = &BPy_IDGroup_ViewValues_Type;
|
||||
PyTypeObject *i_ty = &BPy_IDGroup_ViewItems_Type;
|
||||
|
||||
/* Unique members. */
|
||||
k_ty->tp_name = "IDPropertyGroupViewKeys";
|
||||
v_ty->tp_name = "IDPropertyGroupViewValues";
|
||||
i_ty->tp_name = "IDPropertyGroupViewItems";
|
||||
|
||||
k_ty->tp_iter = (getiterfunc)BPy_Group_ViewKeys_iter;
|
||||
v_ty->tp_iter = (getiterfunc)BPy_Group_ViewValues_iter;
|
||||
i_ty->tp_iter = (getiterfunc)BPy_Group_ViewItems_iter;
|
||||
|
||||
k_ty->tp_as_sequence = &BPy_IDGroup_ViewKeys_as_sequence;
|
||||
v_ty->tp_as_sequence = &BPy_IDGroup_ViewValues_as_sequence;
|
||||
i_ty->tp_as_sequence = &BPy_IDGroup_ViewItems_as_sequence;
|
||||
|
||||
/* Shared members. */
|
||||
#define SHARED_MEMBER_SET(member, value) \
|
||||
{ \
|
||||
k_ty->member = v_ty->member = i_ty->member = value; \
|
||||
} \
|
||||
((void)0)
|
||||
|
||||
SHARED_MEMBER_SET(tp_basicsize, sizeof(BPy_IDGroup_View));
|
||||
SHARED_MEMBER_SET(tp_dealloc, (destructor)BPy_IDGroup_View_dealloc);
|
||||
SHARED_MEMBER_SET(tp_repr, (reprfunc)BPy_IDGroup_View_repr);
|
||||
SHARED_MEMBER_SET(tp_flags, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC);
|
||||
SHARED_MEMBER_SET(tp_traverse, (traverseproc)BPy_IDGroup_View_traverse);
|
||||
SHARED_MEMBER_SET(tp_clear, (inquiry)BPy_IDGroup_View_clear);
|
||||
SHARED_MEMBER_SET(tp_methods, BPy_IDGroup_View_methods);
|
||||
|
||||
#undef SHARED_MEMBER_SET
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name ID-Property Group Methods
|
||||
* \{ */
|
||||
@@ -923,22 +1293,6 @@ static PyObject *BPy_IDGroup_pop(BPy_IDProperty *self, PyObject *args)
|
||||
return pyform;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
BPy_IDGroup_iter_items_doc,
|
||||
".. method:: iteritems()\n"
|
||||
"\n"
|
||||
" Iterate through the items in the dict; behaves like dictionary method iteritems.\n");
|
||||
static PyObject *BPy_IDGroup_iter_items(BPy_IDProperty *self)
|
||||
{
|
||||
BPy_IDGroup_Iter *iter = PyObject_GC_New(BPy_IDGroup_Iter, &BPy_IDGroup_Iter_Type);
|
||||
iter->group = self;
|
||||
Py_INCREF(self);
|
||||
iter->mode = IDPROP_ITER_ITEMS;
|
||||
iter->cur = self->prop->data.group.first;
|
||||
PyObject_GC_Track(iter);
|
||||
return (PyObject *)iter;
|
||||
}
|
||||
|
||||
/* utility function */
|
||||
static void BPy_IDGroup_CorrectListLen(IDProperty *prop, PyObject *seq, int len, const char *func)
|
||||
{
|
||||
@@ -1023,13 +1377,37 @@ PyObject *BPy_Wrap_GetItems(ID *id, IDProperty *prop)
|
||||
return seq;
|
||||
}
|
||||
|
||||
PyObject *BPy_Wrap_GetKeys_View_WithID(ID *id, IDProperty *prop)
|
||||
{
|
||||
PyObject *self = prop ? idprop_py_from_idp_group(id, prop, NULL) : NULL;
|
||||
PyObject *ret = BPy_IDGroup_ViewKeys_CreatePyObject((BPy_IDProperty *)self);
|
||||
Py_XDECREF(self); /* Owned by `ret`. */
|
||||
return ret;
|
||||
}
|
||||
|
||||
PyObject *BPy_Wrap_GetValues_View_WithID(ID *id, IDProperty *prop)
|
||||
{
|
||||
PyObject *self = prop ? idprop_py_from_idp_group(id, prop, NULL) : NULL;
|
||||
PyObject *ret = BPy_IDGroup_ViewValues_CreatePyObject((BPy_IDProperty *)self);
|
||||
Py_XDECREF(self); /* Owned by `ret`. */
|
||||
return ret;
|
||||
}
|
||||
|
||||
PyObject *BPy_Wrap_GetItems_View_WithID(ID *id, IDProperty *prop)
|
||||
{
|
||||
PyObject *self = prop ? idprop_py_from_idp_group(id, prop, NULL) : NULL;
|
||||
PyObject *ret = BPy_IDGroup_ViewItems_CreatePyObject((BPy_IDProperty *)self);
|
||||
Py_XDECREF(self); /* Owned by `ret`. */
|
||||
return ret;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(BPy_IDGroup_keys_doc,
|
||||
".. method:: keys()\n"
|
||||
"\n"
|
||||
" Return the keys associated with this group as a list of strings.\n");
|
||||
static PyObject *BPy_IDGroup_keys(BPy_IDProperty *self)
|
||||
{
|
||||
return BPy_Wrap_GetKeys(self->prop);
|
||||
return BPy_IDGroup_ViewKeys_CreatePyObject(self);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(BPy_IDGroup_values_doc,
|
||||
@@ -1038,16 +1416,16 @@ PyDoc_STRVAR(BPy_IDGroup_values_doc,
|
||||
" Return the values associated with this group.\n");
|
||||
static PyObject *BPy_IDGroup_values(BPy_IDProperty *self)
|
||||
{
|
||||
return BPy_Wrap_GetValues(self->id, self->prop);
|
||||
return BPy_IDGroup_ViewValues_CreatePyObject(self);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(BPy_IDGroup_items_doc,
|
||||
".. method:: items()\n"
|
||||
"\n"
|
||||
" Return the items associated with this group.\n");
|
||||
" Iterate through the items in the dict; behaves like dictionary method items.\n");
|
||||
static PyObject *BPy_IDGroup_items(BPy_IDProperty *self)
|
||||
{
|
||||
return BPy_Wrap_GetItems(self->id, self->prop);
|
||||
return BPy_IDGroup_ViewItems_CreatePyObject(self);
|
||||
}
|
||||
|
||||
static int BPy_IDGroup_Contains(BPy_IDProperty *self, PyObject *value)
|
||||
@@ -1148,7 +1526,6 @@ static PyObject *BPy_IDGroup_get(BPy_IDProperty *self, PyObject *args)
|
||||
|
||||
static struct PyMethodDef BPy_IDGroup_methods[] = {
|
||||
{"pop", (PyCFunction)BPy_IDGroup_pop, METH_VARARGS, BPy_IDGroup_pop_doc},
|
||||
{"iteritems", (PyCFunction)BPy_IDGroup_iter_items, METH_NOARGS, BPy_IDGroup_iter_items_doc},
|
||||
{"keys", (PyCFunction)BPy_IDGroup_keys, METH_NOARGS, BPy_IDGroup_keys_doc},
|
||||
{"values", (PyCFunction)BPy_IDGroup_values, METH_NOARGS, BPy_IDGroup_values_doc},
|
||||
{"items", (PyCFunction)BPy_IDGroup_items, METH_NOARGS, BPy_IDGroup_items_doc},
|
||||
@@ -1678,120 +2055,59 @@ PyTypeObject BPy_IDArray_Type = {
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name ID-Property Group Iterator Type
|
||||
/** \name Initialize Types
|
||||
* \{ */
|
||||
|
||||
static PyObject *IDGroup_Iter_repr(BPy_IDGroup_Iter *self)
|
||||
{
|
||||
return PyUnicode_FromFormat("(ID Property Group Iter \"%s\")", self->group->prop->name);
|
||||
}
|
||||
|
||||
static void BPy_IDGroup_Iter_dealloc(BPy_IDGroup_Iter *self)
|
||||
{
|
||||
PyObject_GC_UnTrack(self);
|
||||
Py_CLEAR(self->group);
|
||||
PyObject_GC_Del(self);
|
||||
}
|
||||
|
||||
static int BPy_IDGroup_Iter_traverse(BPy_IDGroup_Iter *self, visitproc visit, void *arg)
|
||||
{
|
||||
Py_VISIT(self->group);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int BPy_IDGroup_Iter_clear(BPy_IDGroup_Iter *self)
|
||||
{
|
||||
Py_CLEAR(self->group);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PyObject *BPy_Group_Iter_Next(BPy_IDGroup_Iter *self)
|
||||
{
|
||||
|
||||
if (self->cur) {
|
||||
PyObject *ret;
|
||||
IDProperty *cur;
|
||||
|
||||
cur = self->cur;
|
||||
self->cur = self->cur->next;
|
||||
|
||||
if (self->mode == IDPROP_ITER_ITEMS) {
|
||||
ret = PyTuple_New(2);
|
||||
PyTuple_SET_ITEMS(ret,
|
||||
PyUnicode_FromString(cur->name),
|
||||
BPy_IDGroup_WrapData(self->group->id, cur, self->group->prop));
|
||||
return ret;
|
||||
}
|
||||
|
||||
return PyUnicode_FromString(cur->name);
|
||||
}
|
||||
|
||||
PyErr_SetNone(PyExc_StopIteration);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyTypeObject BPy_IDGroup_Iter_Type = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
/* For printing, in format "<module>.<name>" */
|
||||
"IDPropertyGroupIter", /* char *tp_name; */
|
||||
sizeof(BPy_IDGroup_Iter), /* int tp_basicsize; */
|
||||
0, /* tp_itemsize; For allocation */
|
||||
|
||||
/* Methods to implement standard operations */
|
||||
|
||||
(destructor)BPy_IDGroup_Iter_dealloc, /* tp_dealloc */
|
||||
0, /* tp_vectorcall_offset */
|
||||
NULL, /* getattrfunc tp_getattr; */
|
||||
NULL, /* setattrfunc tp_setattr; */
|
||||
NULL, /* cmpfunc tp_compare; */
|
||||
(reprfunc)IDGroup_Iter_repr, /* reprfunc tp_repr; */
|
||||
|
||||
/* Method suites for standard classes */
|
||||
|
||||
NULL, /* PyNumberMethods *tp_as_number; */
|
||||
NULL, /* PySequenceMethods *tp_as_sequence; */
|
||||
NULL, /* PyMappingMethods *tp_as_mapping; */
|
||||
|
||||
/* More standard operations (here for binary compatibility) */
|
||||
|
||||
NULL, /* hashfunc tp_hash; */
|
||||
NULL, /* ternaryfunc tp_call; */
|
||||
NULL, /* reprfunc tp_str; */
|
||||
NULL, /* getattrofunc tp_getattro; */
|
||||
NULL, /* setattrofunc tp_setattro; */
|
||||
|
||||
/* Functions to access object as input/output buffer */
|
||||
NULL, /* PyBufferProcs *tp_as_buffer; */
|
||||
|
||||
/*** Flags to define presence of optional/expanded features ***/
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* long tp_flags; */
|
||||
|
||||
NULL, /* char *tp_doc; Documentation string */
|
||||
/*** Assigned meaning in release 2.0 ***/
|
||||
/* call function for all accessible objects */
|
||||
(traverseproc)BPy_IDGroup_Iter_traverse, /* traverseproc tp_traverse; */
|
||||
|
||||
/* delete references to contained objects */
|
||||
(inquiry)BPy_IDGroup_Iter_clear, /* inquiry tp_clear; */
|
||||
|
||||
/*** Assigned meaning in release 2.1 ***/
|
||||
/*** rich comparisons ***/
|
||||
NULL, /* richcmpfunc tp_richcompare; */
|
||||
|
||||
/*** weak reference enabler ***/
|
||||
0, /* long tp_weaklistoffset; */
|
||||
|
||||
/*** Added in release 2.2 ***/
|
||||
/* Iterators */
|
||||
PyObject_SelfIter, /* getiterfunc tp_iter; */
|
||||
(iternextfunc)BPy_Group_Iter_Next, /* iternextfunc tp_iternext; */
|
||||
};
|
||||
|
||||
void IDProp_Init_Types(void)
|
||||
{
|
||||
IDGroup_Iter_init_type();
|
||||
IDGroup_View_init_type();
|
||||
|
||||
PyType_Ready(&BPy_IDGroup_Type);
|
||||
PyType_Ready(&BPy_IDGroup_Iter_Type);
|
||||
PyType_Ready(&BPy_IDArray_Type);
|
||||
|
||||
PyType_Ready(&BPy_IDGroup_IterKeys_Type);
|
||||
PyType_Ready(&BPy_IDGroup_IterValues_Type);
|
||||
PyType_Ready(&BPy_IDGroup_IterItems_Type);
|
||||
|
||||
PyType_Ready(&BPy_IDGroup_ViewKeys_Type);
|
||||
PyType_Ready(&BPy_IDGroup_ViewValues_Type);
|
||||
PyType_Ready(&BPy_IDGroup_ViewItems_Type);
|
||||
}
|
||||
|
||||
/**
|
||||
* \note `group` may be NULL, unlike most other uses of this argument.
|
||||
* This is supported so RNA keys/values/items methods returns an iterator with the expected type:
|
||||
* - Without having ID-properties.
|
||||
* - Without supporting #BPy_IDProperty.prop being NULL, which would incur many more checks.
|
||||
* Python's own dictionary-views also works this way too.
|
||||
*/
|
||||
static BPy_IDGroup_View *IDGroup_View_New_WithType(BPy_IDProperty *group, PyTypeObject *type)
|
||||
{
|
||||
BLI_assert(group ? group->prop->type == IDP_GROUP : true);
|
||||
BPy_IDGroup_View *iter = PyObject_GC_New(BPy_IDGroup_View, type);
|
||||
iter->reversed = false;
|
||||
iter->group = group;
|
||||
if (group != NULL) {
|
||||
Py_INCREF(group);
|
||||
PyObject_GC_Track(iter);
|
||||
}
|
||||
return iter;
|
||||
}
|
||||
|
||||
static PyObject *BPy_IDGroup_ViewKeys_CreatePyObject(BPy_IDProperty *group)
|
||||
{
|
||||
return (PyObject *)IDGroup_View_New_WithType(group, &BPy_IDGroup_ViewKeys_Type);
|
||||
}
|
||||
|
||||
static PyObject *BPy_IDGroup_ViewValues_CreatePyObject(BPy_IDProperty *group)
|
||||
{
|
||||
return (PyObject *)IDGroup_View_New_WithType(group, &BPy_IDGroup_ViewValues_Type);
|
||||
}
|
||||
|
||||
static PyObject *BPy_IDGroup_ViewItems_CreatePyObject(BPy_IDProperty *group)
|
||||
{
|
||||
return (PyObject *)IDGroup_View_New_WithType(group, &BPy_IDGroup_ViewItems_Type);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
@@ -1822,7 +2138,15 @@ static PyObject *BPyInit_idprop_types(void)
|
||||
|
||||
/* bmesh_py_types.c */
|
||||
PyModule_AddType(submodule, &BPy_IDGroup_Type);
|
||||
PyModule_AddType(submodule, &BPy_IDGroup_Iter_Type);
|
||||
|
||||
PyModule_AddType(submodule, &BPy_IDGroup_ViewKeys_Type);
|
||||
PyModule_AddType(submodule, &BPy_IDGroup_ViewValues_Type);
|
||||
PyModule_AddType(submodule, &BPy_IDGroup_ViewItems_Type);
|
||||
|
||||
PyModule_AddType(submodule, &BPy_IDGroup_IterKeys_Type);
|
||||
PyModule_AddType(submodule, &BPy_IDGroup_IterValues_Type);
|
||||
PyModule_AddType(submodule, &BPy_IDGroup_IterItems_Type);
|
||||
|
||||
PyModule_AddType(submodule, &BPy_IDArray_Type);
|
||||
|
||||
return submodule;
|
||||
|
Reference in New Issue
Block a user