Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/blender/python/intern/bpy_props.c92
-rw-r--r--source/blender/python/intern/bpy_props.h10
-rw-r--r--source/blender/python/intern/bpy_rna.c125
3 files changed, 135 insertions, 92 deletions
diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c
index 878bf4aec5d..c596f81a91c 100644
--- a/source/blender/python/intern/bpy_props.c
+++ b/source/blender/python/intern/bpy_props.c
@@ -193,6 +193,71 @@ static const EnumPropertyItem property_subtype_array_items[] = {
"'XYZ', 'XYZ_LENGTH', 'COLOR_GAMMA', 'COORDINATES', 'LAYER', 'LAYER_MEMBER', 'NONE'].\n" \
" :type subtype: string\n"
+/* -------------------------------------------------------------------- */
+/** \name Deferred Property Type
+ *
+ * Operators and classes use this so it can store the arguments given but defer
+ * running it until the operator runs where these values are used to setup
+ * the default arguments for that operator instance.
+ * \{ */
+
+static void bpy_prop_deferred_dealloc(BPy_PropDeferred *self)
+{
+ if (self->kw) {
+ PyObject_GC_UnTrack(self);
+ Py_CLEAR(self->kw);
+ }
+ PyObject_GC_Del(self);
+}
+
+static int bpy_prop_deferred_traverse(BPy_PropDeferred *self, visitproc visit, void *arg)
+{
+ Py_VISIT(self->kw);
+ return 0;
+}
+
+static int bpy_prop_deferred_clear(BPy_PropDeferred *self)
+{
+ Py_CLEAR(self->kw);
+ return 0;
+}
+
+static PyObject *bpy_prop_deferred_repr(BPy_PropDeferred *self)
+{
+ return PyUnicode_FromFormat("<%.200s, %R, %R>", Py_TYPE(self)->tp_name, self->fn, self->kw);
+}
+
+PyTypeObject bpy_prop_deferred_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+
+ .tp_name = "bpy_prop_deferred",
+ .tp_basicsize = sizeof(BPy_PropDeferred),
+ .tp_dealloc = (destructor)bpy_prop_deferred_dealloc,
+ .tp_repr = (reprfunc)bpy_prop_deferred_repr,
+
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
+
+ .tp_traverse = (traverseproc)bpy_prop_deferred_traverse,
+ .tp_clear = (inquiry)bpy_prop_deferred_clear,
+};
+
+static PyObject *bpy_prop_deferred_data_CreatePyObject(PyObject *fn, PyObject *kw)
+{
+ BPy_PropDeferred *self = PyObject_GC_New(BPy_PropDeferred, &bpy_prop_deferred_Type);
+ self->fn = fn;
+ if (kw == NULL) {
+ kw = PyDict_New();
+ }
+ else {
+ Py_INCREF(kw);
+ }
+ self->kw = kw;
+ PyObject_GC_Track(self);
+ return (PyObject *)self;
+}
+
+/** \} */
+
/* PyObject's */
static PyObject *pymeth_BoolProperty = NULL;
static PyObject *pymeth_BoolVectorProperty = NULL;
@@ -248,27 +313,6 @@ static void bpy_prop_assign_flag_override(PropertyRNA *prop, const int flag_over
RNA_def_property_override_flag(prop, flag_override);
}
-/* operators and classes use this so it can store the args given but defer
- * running it until the operator runs where these values are used to setup
- * the default args for that operator instance */
-static PyObject *bpy_prop_deferred_return(PyObject *func, PyObject *kw)
-{
- PyObject *ret = PyTuple_New(2);
- PyTuple_SET_ITEM(ret, 0, func);
- Py_INCREF(func);
-
- if (kw == NULL) {
- kw = PyDict_New();
- }
- else {
- Py_INCREF(kw);
- }
-
- PyTuple_SET_ITEM(ret, 1, kw);
-
- return ret;
-}
-
/* callbacks */
static void bpy_prop_update_cb(struct bContext *C,
struct PointerRNA *ptr,
@@ -1997,7 +2041,7 @@ static void bpy_prop_callback_assign_enum(struct PropertyRNA *prop,
if (PyErr_Occurred()) { \
return NULL; \
} \
- return bpy_prop_deferred_return(pymeth_##_func, kw); \
+ return bpy_prop_deferred_data_CreatePyObject(pymeth_##_func, kw); \
} \
(void)0
@@ -3668,5 +3712,9 @@ PyObject *BPY_rna_props(void)
ASSIGN_STATIC(CollectionProperty);
ASSIGN_STATIC(RemoveProperty);
+ if (PyType_Ready(&bpy_prop_deferred_Type) < 0) {
+ return NULL;
+ }
+
return submodule;
}
diff --git a/source/blender/python/intern/bpy_props.h b/source/blender/python/intern/bpy_props.h
index 3d7860dcdd8..6cebf82d373 100644
--- a/source/blender/python/intern/bpy_props.h
+++ b/source/blender/python/intern/bpy_props.h
@@ -30,6 +30,16 @@ PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw);
PyObject *BPy_CollectionProperty(PyObject *self, PyObject *args, PyObject *kw);
StructRNA *pointer_type_from_py(PyObject *value, const char *error_prefix);
+typedef struct {
+ PyObject_HEAD
+ /* This isn't GC tracked, it's a function from `bpy.props` so it's not going away. */
+ void *fn;
+ PyObject *kw;
+} BPy_PropDeferred;
+
+extern PyTypeObject bpy_prop_deferred_Type;
+#define BPy_PropDeferred_CheckTypeExact(v) (Py_TYPE(v) == &bpy_prop_deferred_Type)
+
#define PYRNA_STACK_ARRAY RNA_STACK_ARRAY
#ifdef __cplusplus
diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c
index 311a7afef01..0c091d7cd7c 100644
--- a/source/blender/python/intern/bpy_rna.c
+++ b/source/blender/python/intern/bpy_rna.c
@@ -4356,12 +4356,6 @@ static int pyrna_struct_pydict_contains(PyObject *self, PyObject *pyname)
#endif
/* --------------- setattr------------------------------------------- */
-static bool pyrna_is_deferred_prop(const PyObject *value)
-{
- return PyTuple_CheckExact(value) && PyTuple_GET_SIZE(value) == 2 &&
- PyCFunction_Check(PyTuple_GET_ITEM(value, 0)) &&
- PyDict_CheckExact(PyTuple_GET_ITEM(value, 1));
-}
#if 0
static PyObject *pyrna_struct_meta_idprop_getattro(PyObject *cls, PyObject *attr)
@@ -4373,12 +4367,12 @@ static PyObject *pyrna_struct_meta_idprop_getattro(PyObject *cls, PyObject *attr
* >>> bpy.types.Scene.foo
* <bpy_struct, BoolProperty("foo")>
* ...rather than returning the deferred class register tuple
- * as checked by pyrna_is_deferred_prop()
+ * as checked by BPy_PropDeferred_CheckTypeExact()
*
* Disable for now,
* this is faking internal behavior in a way that's too tricky to maintain well. */
# if 0
- if ((ret == NULL) /* || pyrna_is_deferred_prop(ret) */ ) {
+ if ((ret == NULL) /* || BPy_PropDeferred_CheckTypeExact(ret) */ ) {
StructRNA *srna = srna_from_self(cls, "StructRNA.__getattr__");
if (srna) {
PropertyRNA *prop = RNA_struct_type_find_property(srna, PyUnicode_AsUTF8(attr));
@@ -4399,7 +4393,7 @@ static PyObject *pyrna_struct_meta_idprop_getattro(PyObject *cls, PyObject *attr
static int pyrna_struct_meta_idprop_setattro(PyObject *cls, PyObject *attr, PyObject *value)
{
StructRNA *srna = srna_from_self(cls, "StructRNA.__setattr__");
- const bool is_deferred_prop = (value && pyrna_is_deferred_prop(value));
+ const bool is_deferred_prop = (value && BPy_PropDeferred_CheckTypeExact(value));
const char *attr_str = PyUnicode_AsUTF8(attr);
if (srna && !pyrna_write_check() &&
@@ -7873,78 +7867,69 @@ StructRNA *srna_from_self(PyObject *self, const char *error_prefix)
static int deferred_register_prop(StructRNA *srna, PyObject *key, PyObject *item)
{
+ if (!BPy_PropDeferred_CheckTypeExact(item)) {
+ /* No error, ignoring. */
+ return 0;
+ }
+
/* We only care about results from C which
* are for sure types, save some time with error */
- if (pyrna_is_deferred_prop(item)) {
+ PyObject *py_func = ((BPy_PropDeferred *)item)->fn;
+ PyObject *py_kw = ((BPy_PropDeferred *)item)->kw;
+ PyObject *py_srna_cobject, *py_ret;
- PyObject *py_func, *py_kw, *py_srna_cobject, *py_ret;
+ PyObject *args_fake;
- if (PyArg_ParseTuple(item, "OO!", &py_func, &PyDict_Type, &py_kw)) {
- PyObject *args_fake;
-
- if (*PyUnicode_AsUTF8(key) == '_') {
- PyErr_Format(PyExc_ValueError,
- "bpy_struct \"%.200s\" registration error: "
- "%.200s could not register because the property starts with an '_'\n",
- RNA_struct_identifier(srna),
- PyUnicode_AsUTF8(key));
- return -1;
- }
- py_srna_cobject = PyCapsule_New(srna, NULL, NULL);
+ if (*PyUnicode_AsUTF8(key) == '_') {
+ PyErr_Format(PyExc_ValueError,
+ "bpy_struct \"%.200s\" registration error: "
+ "%.200s could not register because the property starts with an '_'\n",
+ RNA_struct_identifier(srna),
+ PyUnicode_AsUTF8(key));
+ return -1;
+ }
+ py_srna_cobject = PyCapsule_New(srna, NULL, NULL);
- /* Not 100% nice :/, modifies the dict passed, should be ok. */
- PyDict_SetItem(py_kw, bpy_intern_str_attr, key);
+ /* Not 100% nice :/, modifies the dict passed, should be ok. */
+ PyDict_SetItem(py_kw, bpy_intern_str_attr, key);
- args_fake = PyTuple_New(1);
- PyTuple_SET_ITEM(args_fake, 0, py_srna_cobject);
+ args_fake = PyTuple_New(1);
+ PyTuple_SET_ITEM(args_fake, 0, py_srna_cobject);
- PyObject *type = PyDict_GetItemString(py_kw, "type");
- StructRNA *type_srna = srna_from_self(type, "");
- if (type_srna) {
- if (!RNA_struct_idprops_datablock_allowed(srna) &&
- (*(PyCFunctionWithKeywords)PyCFunction_GET_FUNCTION(py_func) == BPy_PointerProperty ||
- *(PyCFunctionWithKeywords)PyCFunction_GET_FUNCTION(py_func) ==
- BPy_CollectionProperty) &&
- RNA_struct_idprops_contains_datablock(type_srna)) {
- PyErr_Format(PyExc_ValueError,
- "bpy_struct \"%.200s\" doesn't support datablock properties\n",
- RNA_struct_identifier(srna));
- return -1;
- }
- }
+ PyObject *type = PyDict_GetItemString(py_kw, "type");
+ StructRNA *type_srna = srna_from_self(type, "");
+ if (type_srna) {
+ if (!RNA_struct_idprops_datablock_allowed(srna) &&
+ (*(PyCFunctionWithKeywords)PyCFunction_GET_FUNCTION(py_func) == BPy_PointerProperty ||
+ *(PyCFunctionWithKeywords)PyCFunction_GET_FUNCTION(py_func) == BPy_CollectionProperty) &&
+ RNA_struct_idprops_contains_datablock(type_srna)) {
+ PyErr_Format(PyExc_ValueError,
+ "bpy_struct \"%.200s\" doesn't support datablock properties\n",
+ RNA_struct_identifier(srna));
+ return -1;
+ }
+ }
- py_ret = PyObject_Call(py_func, args_fake, py_kw);
+ py_ret = PyObject_Call(py_func, args_fake, py_kw);
- if (py_ret) {
- Py_DECREF(py_ret);
- Py_DECREF(args_fake); /* Free's py_srna_cobject too. */
- }
- else {
- /* _must_ print before decreffing args_fake. */
- PyErr_Print();
- PyErr_Clear();
+ if (py_ret) {
+ Py_DECREF(py_ret);
+ Py_DECREF(args_fake); /* Free's py_srna_cobject too. */
+ }
+ else {
+ /* _must_ print before decreffing args_fake. */
+ PyErr_Print();
+ PyErr_Clear();
- Py_DECREF(args_fake); /* Free's py_srna_cobject too. */
+ Py_DECREF(args_fake); /* Free's py_srna_cobject too. */
- // PyC_LineSpit();
- PyErr_Format(PyExc_ValueError,
- "bpy_struct \"%.200s\" registration error: "
- "%.200s could not register\n",
- RNA_struct_identifier(srna),
- PyUnicode_AsUTF8(key));
- return -1;
- }
- }
- else {
- /* Since this is a class dict, ignore args that can't be passed. */
-
- /* For testing only. */
-#if 0
- PyC_ObSpit("Why doesn't this work??", item);
- PyErr_Print();
-#endif
- PyErr_Clear();
- }
+ // PyC_LineSpit();
+ PyErr_Format(PyExc_ValueError,
+ "bpy_struct \"%.200s\" registration error: "
+ "%.200s could not register\n",
+ RNA_struct_identifier(srna),
+ PyUnicode_AsUTF8(key));
+ return -1;
}
return 0;