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:
authorCampbell Barton <ideasman42@gmail.com>2021-03-16 04:18:56 +0300
committerCampbell Barton <ideasman42@gmail.com>2021-03-16 07:17:45 +0300
commite125305af41a7360c52b9a38024b7e24fde06d70 (patch)
tree89670ef582473388c7c87fe42f4ae81f0a44132d
parentbe51d671b500e8b6881295778de7272a70504b71 (diff)
Fix T86332: Error using lambda in annotations in Python 3.10
Callbacks used in `bpy.props` didn't hold a references to the functions they used. While this has been the case since early 2.5x it didn't cause any problems as long as the class held a reference. With Python 3.10 or when using `from __future__ import annotations`, the annotations are no longer owned by the class once evaluated. Resolve this by holding a reference in the module, which now supports traverse & clear callbacks so the objects are visible to Python's garbage collector. Also refactor storage of Python data, moving from an array into a struct.
-rw-r--r--source/blender/makesrna/RNA_access.h1
-rw-r--r--source/blender/makesrna/RNA_define.h5
-rw-r--r--source/blender/makesrna/intern/makesrna.c2
-rw-r--r--source/blender/makesrna/intern/rna_access.c9
-rw-r--r--source/blender/makesrna/intern/rna_define.c23
-rw-r--r--source/blender/makesrna/intern/rna_internal_types.h1
-rw-r--r--source/blender/python/intern/bpy_interface.c4
-rw-r--r--source/blender/python/intern/bpy_props.c339
-rw-r--r--source/blender/python/intern/bpy_props.h1
9 files changed, 245 insertions, 140 deletions
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index 4c60ffe4f16..d41220eb22c 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -1021,7 +1021,6 @@ int RNA_property_string_default_length(PointerRNA *ptr, PropertyRNA *prop);
int RNA_property_enum_get(PointerRNA *ptr, PropertyRNA *prop);
void RNA_property_enum_set(PointerRNA *ptr, PropertyRNA *prop, int value);
int RNA_property_enum_get_default(PointerRNA *ptr, PropertyRNA *prop);
-void *RNA_property_enum_py_data_get(PropertyRNA *prop);
int RNA_property_enum_step(
const struct bContext *C, PointerRNA *ptr, PropertyRNA *prop, int from_value, int step);
diff --git a/source/blender/makesrna/RNA_define.h b/source/blender/makesrna/RNA_define.h
index c49a52ceed7..bc1a8f52b8d 100644
--- a/source/blender/makesrna/RNA_define.h
+++ b/source/blender/makesrna/RNA_define.h
@@ -465,8 +465,6 @@ void RNA_def_property_string_funcs_runtime(PropertyRNA *prop,
StringPropertyLengthFunc lengthfunc,
StringPropertySetFunc setfunc);
-void RNA_def_property_enum_py_data(PropertyRNA *prop, void *py_data);
-
void RNA_def_property_translation_context(PropertyRNA *prop, const char *context);
/* Function */
@@ -507,6 +505,9 @@ void RNA_def_property_duplicate_pointers(StructOrFunctionRNA *cont_, PropertyRNA
void RNA_def_property_free_pointers(PropertyRNA *prop);
int RNA_def_property_free_identifier(StructOrFunctionRNA *cont_, const char *identifier);
+void RNA_def_property_free_pointers_set_py_data_callback(
+ void (*py_data_clear_fn)(PropertyRNA *prop));
+
/* utilities */
const char *RNA_property_typename(PropertyType type);
#define IS_DNATYPE_FLOAT_COMPAT(_str) (strcmp(_str, "float") == 0 || strcmp(_str, "double") == 0)
diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c
index 1f887c2eec3..6940e475f39 100644
--- a/source/blender/makesrna/intern/makesrna.c
+++ b/source/blender/makesrna/intern/makesrna.c
@@ -3989,7 +3989,7 @@ static void rna_generate_property(FILE *f, StructRNA *srna, const char *nest, Pr
case PROP_ENUM: {
EnumPropertyRNA *eprop = (EnumPropertyRNA *)prop;
fprintf(f,
- "\t%s, %s, %s, %s, %s, NULL, ",
+ "\t%s, %s, %s, %s, %s, ",
rna_function_string(eprop->get),
rna_function_string(eprop->set),
rna_function_string(eprop->item_fn),
diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c
index 8e5e70642cc..f94dc38ddfe 100644
--- a/source/blender/makesrna/intern/rna_access.c
+++ b/source/blender/makesrna/intern/rna_access.c
@@ -3598,15 +3598,6 @@ int RNA_property_enum_get_default(PointerRNA *UNUSED(ptr), PropertyRNA *prop)
return eprop->defaultvalue;
}
-void *RNA_property_enum_py_data_get(PropertyRNA *prop)
-{
- EnumPropertyRNA *eprop = (EnumPropertyRNA *)prop;
-
- BLI_assert(RNA_property_type(prop) == PROP_ENUM);
-
- return eprop->py_data;
-}
-
/**
* Get the value of the item that is \a step items away from \a from_value.
*
diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c
index 5e188285e39..019823a7de3 100644
--- a/source/blender/makesrna/intern/rna_define.c
+++ b/source/blender/makesrna/intern/rna_define.c
@@ -3305,12 +3305,6 @@ void RNA_def_property_enum_funcs_runtime(PropertyRNA *prop,
}
}
-void RNA_def_property_enum_py_data(PropertyRNA *prop, void *py_data)
-{
- EnumPropertyRNA *eprop = (EnumPropertyRNA *)prop;
- eprop->py_data = py_data;
-}
-
void RNA_def_property_string_funcs(PropertyRNA *prop,
const char *get,
const char *length,
@@ -4632,11 +4626,28 @@ void RNA_def_property_duplicate_pointers(StructOrFunctionRNA *cont_, PropertyRNA
prop->flag_internal |= PROP_INTERN_FREE_POINTERS;
}
+static void (*g_py_data_clear_fn)(PropertyRNA *prop) = NULL;
+
+/**
+ * Set the callback used to decrement the user count of a property.
+ *
+ * This function is called when freeing each dynamically defined property.
+ */
+void RNA_def_property_free_pointers_set_py_data_callback(
+ void (*py_data_clear_fn)(PropertyRNA *prop))
+{
+ g_py_data_clear_fn = py_data_clear_fn;
+}
+
void RNA_def_property_free_pointers(PropertyRNA *prop)
{
if (prop->flag_internal & PROP_INTERN_FREE_POINTERS) {
int a;
+ if (g_py_data_clear_fn) {
+ g_py_data_clear_fn(prop);
+ }
+
if (prop->identifier) {
MEM_freeN((void *)prop->identifier);
}
diff --git a/source/blender/makesrna/intern/rna_internal_types.h b/source/blender/makesrna/intern/rna_internal_types.h
index 1dd08bb1074..0c0260c889c 100644
--- a/source/blender/makesrna/intern/rna_internal_types.h
+++ b/source/blender/makesrna/intern/rna_internal_types.h
@@ -457,7 +457,6 @@ typedef struct EnumPropertyRNA {
PropEnumGetFuncEx get_ex;
PropEnumSetFuncEx set_ex;
- void *py_data; /* store py callback here */
const EnumPropertyItem *item;
int totitem;
diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c
index 331884c0bd2..5f31e0bb74d 100644
--- a/source/blender/python/intern/bpy_interface.c
+++ b/source/blender/python/intern/bpy_interface.c
@@ -45,6 +45,7 @@
#include "bpy_capi_utils.h"
#include "bpy_intern_string.h"
#include "bpy_path.h"
+#include "bpy_props.h"
#include "bpy_rna.h"
#include "bpy_traceback.h"
@@ -523,6 +524,9 @@ void BPY_python_end(void)
/* finalizing, no need to grab the state, except when we are a module */
gilstate = PyGILState_Ensure();
+ /* Decrement user counts of all callback functions. */
+ BPY_rna_props_clear_all();
+
/* free other python data. */
pyrna_free_types();
diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c
index 246387486be..6224f84c5fc 100644
--- a/source/blender/python/intern/bpy_props.c
+++ b/source/blender/python/intern/bpy_props.c
@@ -29,6 +29,7 @@
#include "RNA_types.h"
+#include "BLI_listbase.h"
#include "BLI_utildefines.h"
#include "bpy_capi_utils.h"
@@ -47,14 +48,7 @@
#include "../generic/py_capi_utils.h"
-/* initial definition of callback slots we'll probably have more than 1 */
-enum {
- BPY_DATA_CB_SLOT_UPDATE = 0,
- BPY_DATA_CB_SLOT_GET = 1,
- BPY_DATA_CB_SLOT_SET = 2,
- BPY_DATA_CB_SLOT_POLL = 3,
- BPY_DATA_CB_SLOT_SIZE = 4,
-};
+static struct BPyPropStore *bpy_prop_py_data_ensure(struct PropertyRNA *prop);
static const EnumPropertyItem property_flag_items[] = {
{PROP_HIDDEN, "HIDDEN", 0, "Hidden", ""},
@@ -194,6 +188,83 @@ static const EnumPropertyItem property_subtype_array_items[] = {
" :type subtype: string\n"
/* -------------------------------------------------------------------- */
+/** \name Python Property Storage API
+ *
+ * Functionality needed to use Python native callbacks from generic C RNA callbacks.
+ * \{ */
+
+/**
+ * Slots for #PyObject slots stored in #PropertyRNA.py_data (these hold a reference).
+ * #bpy_prop_callback_free_py_data manages decrementing.
+ */
+struct BPyPropStore {
+ struct BPyPropStore *next, *prev;
+
+ /**
+ * Only store #PyObject types, can be cast to an an array and operated on.
+ * NULL members are ignored/skipped. */
+ struct {
+ PyObject *update_fn;
+ PyObject *get_fn;
+ PyObject *set_fn;
+ PyObject *poll_fn;
+ /** Arguments by type. */
+ union {
+ struct {
+ PyObject *itemf_fn;
+ } enum_data;
+ };
+ } py_data;
+};
+
+#define BPY_PROP_STORE_PY_DATA_SIZE \
+ (sizeof(((struct BPyPropStore *)NULL)->py_data) / sizeof(PyObject *))
+
+#define ASSIGN_PYOBJECT_INCREF(a, b) \
+ { \
+ BLI_assert((a) == NULL); \
+ Py_INCREF(b); \
+ a = b; \
+ } \
+ ((void)0)
+
+/**
+ * Maintain a list of Python defined properties, so the GC can visit them,
+ * and so they can be cleared on exit.
+ */
+static ListBase g_bpy_prop_store_list = {NULL, NULL};
+
+static struct BPyPropStore *bpy_prop_py_data_ensure(struct PropertyRNA *prop)
+{
+ struct BPyPropStore *prop_store = RNA_property_py_data_get(prop);
+ if (prop_store == NULL) {
+ prop_store = MEM_callocN(sizeof(*prop_store), __func__);
+ RNA_def_py_data(prop, prop_store);
+ BLI_addtail(&g_bpy_prop_store_list, prop_store);
+ }
+ return prop_store;
+}
+
+/**
+ * Perform all removal actions except for freeing, which is handled by RNA.
+ */
+static void bpy_prop_py_data_remove(PropertyRNA *prop)
+{
+ struct BPyPropStore *prop_store = RNA_property_py_data_get(prop);
+ if (prop_store == NULL) {
+ return;
+ }
+
+ PyObject **py_data = (PyObject **)&prop_store->py_data;
+ for (int i = 0; i < BPY_PROP_STORE_PY_DATA_SIZE; i++) {
+ Py_XDECREF(py_data[i]);
+ }
+ BLI_remlink(&g_bpy_prop_store_list, prop_store);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Deferred Property Type
*
* Operators and classes use this so it can store the arguments given but defer
@@ -371,15 +442,15 @@ static void bpy_prop_update_cb(struct bContext *C,
struct PointerRNA *ptr,
struct PropertyRNA *prop)
{
+ struct BPyPropStore *prop_store = RNA_property_py_data_get(prop);
PyGILState_STATE gilstate;
- PyObject **py_data = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
PyObject *ret;
const bool is_write_ok = pyrna_write_check();
- BLI_assert(py_data != NULL);
+ BLI_assert(prop_store != NULL);
if (!is_write_ok) {
pyrna_write_set(true);
@@ -387,7 +458,7 @@ static void bpy_prop_update_cb(struct bContext *C,
bpy_context_set(C, &gilstate);
- py_func = py_data[BPY_DATA_CB_SLOT_UPDATE];
+ py_func = prop_store->py_data.update_fn;
args = PyTuple_New(2);
self = pyrna_struct_as_instance(ptr);
@@ -421,7 +492,7 @@ static void bpy_prop_update_cb(struct bContext *C,
static bool bpy_prop_boolean_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop)
{
- PyObject **py_data = RNA_property_py_data_get(prop);
+ struct BPyPropStore *prop_store = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -431,7 +502,7 @@ static bool bpy_prop_boolean_get_cb(struct PointerRNA *ptr, struct PropertyRNA *
const bool is_write_ok = pyrna_write_check();
bool value;
- BLI_assert(py_data != NULL);
+ BLI_assert(prop_store != NULL);
if (!is_write_ok) {
pyrna_write_set(true);
@@ -443,7 +514,7 @@ static bool bpy_prop_boolean_get_cb(struct PointerRNA *ptr, struct PropertyRNA *
gilstate = PyGILState_Ensure();
}
- py_func = py_data[BPY_DATA_CB_SLOT_GET];
+ py_func = prop_store->py_data.get_fn;
args = PyTuple_New(1);
self = pyrna_struct_as_instance(ptr);
@@ -484,7 +555,7 @@ static bool bpy_prop_boolean_get_cb(struct PointerRNA *ptr, struct PropertyRNA *
static void bpy_prop_boolean_set_cb(struct PointerRNA *ptr, struct PropertyRNA *prop, bool value)
{
- PyObject **py_data = RNA_property_py_data_get(prop);
+ struct BPyPropStore *prop_store = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -493,7 +564,7 @@ static void bpy_prop_boolean_set_cb(struct PointerRNA *ptr, struct PropertyRNA *
bool use_gil;
const bool is_write_ok = pyrna_write_check();
- BLI_assert(py_data != NULL);
+ BLI_assert(prop_store != NULL);
if (!is_write_ok) {
pyrna_write_set(true);
@@ -505,7 +576,7 @@ static void bpy_prop_boolean_set_cb(struct PointerRNA *ptr, struct PropertyRNA *
gilstate = PyGILState_Ensure();
}
- py_func = py_data[BPY_DATA_CB_SLOT_SET];
+ py_func = prop_store->py_data.set_fn;
args = PyTuple_New(2);
self = pyrna_struct_as_instance(ptr);
@@ -542,10 +613,10 @@ static bool bpy_prop_poll_cb(struct PointerRNA *self,
PointerRNA candidate,
struct PropertyRNA *prop)
{
+ struct BPyPropStore *prop_store = RNA_property_py_data_get(prop);
PyObject *py_self;
PyObject *py_candidate;
PyObject *py_func;
- PyObject **py_data = RNA_property_py_data_get(prop);
PyObject *args;
PyObject *ret;
bool result;
@@ -556,7 +627,7 @@ static bool bpy_prop_poll_cb(struct PointerRNA *self,
py_self = pyrna_struct_as_instance(self);
py_candidate = pyrna_struct_as_instance(&candidate);
- py_func = py_data[BPY_DATA_CB_SLOT_POLL];
+ py_func = prop_store->py_data.poll_fn;
if (!is_write_ok) {
pyrna_write_set(true);
@@ -591,7 +662,7 @@ static void bpy_prop_boolean_array_get_cb(struct PointerRNA *ptr,
struct PropertyRNA *prop,
bool *values)
{
- PyObject **py_data = RNA_property_py_data_get(prop);
+ struct BPyPropStore *prop_store = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -601,7 +672,7 @@ static void bpy_prop_boolean_array_get_cb(struct PointerRNA *ptr,
const bool is_write_ok = pyrna_write_check();
int i, len = RNA_property_array_length(ptr, prop);
- BLI_assert(py_data != NULL);
+ BLI_assert(prop_store != NULL);
if (!is_write_ok) {
pyrna_write_set(true);
@@ -613,7 +684,7 @@ static void bpy_prop_boolean_array_get_cb(struct PointerRNA *ptr,
gilstate = PyGILState_Ensure();
}
- py_func = py_data[BPY_DATA_CB_SLOT_GET];
+ py_func = prop_store->py_data.get_fn;
args = PyTuple_New(1);
self = pyrna_struct_as_instance(ptr);
@@ -658,7 +729,7 @@ static void bpy_prop_boolean_array_set_cb(struct PointerRNA *ptr,
struct PropertyRNA *prop,
const bool *values)
{
- PyObject **py_data = RNA_property_py_data_get(prop);
+ struct BPyPropStore *prop_store = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -669,7 +740,7 @@ static void bpy_prop_boolean_array_set_cb(struct PointerRNA *ptr,
const bool is_write_ok = pyrna_write_check();
const int len = RNA_property_array_length(ptr, prop);
- BLI_assert(py_data != NULL);
+ BLI_assert(prop_store != NULL);
if (!is_write_ok) {
pyrna_write_set(true);
@@ -681,7 +752,7 @@ static void bpy_prop_boolean_array_set_cb(struct PointerRNA *ptr,
gilstate = PyGILState_Ensure();
}
- py_func = py_data[BPY_DATA_CB_SLOT_SET];
+ py_func = prop_store->py_data.set_fn;
args = PyTuple_New(2);
self = pyrna_struct_as_instance(ptr);
@@ -717,7 +788,7 @@ static void bpy_prop_boolean_array_set_cb(struct PointerRNA *ptr,
static int bpy_prop_int_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop)
{
- PyObject **py_data = RNA_property_py_data_get(prop);
+ struct BPyPropStore *prop_store = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -727,7 +798,7 @@ static int bpy_prop_int_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop)
const bool is_write_ok = pyrna_write_check();
int value;
- BLI_assert(py_data != NULL);
+ BLI_assert(prop_store != NULL);
if (!is_write_ok) {
pyrna_write_set(true);
@@ -739,7 +810,7 @@ static int bpy_prop_int_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop)
gilstate = PyGILState_Ensure();
}
- py_func = py_data[BPY_DATA_CB_SLOT_GET];
+ py_func = prop_store->py_data.get_fn;
args = PyTuple_New(1);
self = pyrna_struct_as_instance(ptr);
@@ -777,7 +848,7 @@ static int bpy_prop_int_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop)
static void bpy_prop_int_set_cb(struct PointerRNA *ptr, struct PropertyRNA *prop, int value)
{
- PyObject **py_data = RNA_property_py_data_get(prop);
+ struct BPyPropStore *prop_store = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -786,7 +857,7 @@ static void bpy_prop_int_set_cb(struct PointerRNA *ptr, struct PropertyRNA *prop
bool use_gil;
const bool is_write_ok = pyrna_write_check();
- BLI_assert(py_data != NULL);
+ BLI_assert(prop_store != NULL);
if (!is_write_ok) {
pyrna_write_set(true);
@@ -798,7 +869,7 @@ static void bpy_prop_int_set_cb(struct PointerRNA *ptr, struct PropertyRNA *prop
gilstate = PyGILState_Ensure();
}
- py_func = py_data[BPY_DATA_CB_SLOT_SET];
+ py_func = prop_store->py_data.set_fn;
args = PyTuple_New(2);
self = pyrna_struct_as_instance(ptr);
@@ -835,7 +906,7 @@ static void bpy_prop_int_array_get_cb(struct PointerRNA *ptr,
struct PropertyRNA *prop,
int *values)
{
- PyObject **py_data = RNA_property_py_data_get(prop);
+ struct BPyPropStore *prop_store = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -845,7 +916,7 @@ static void bpy_prop_int_array_get_cb(struct PointerRNA *ptr,
const bool is_write_ok = pyrna_write_check();
int i, len = RNA_property_array_length(ptr, prop);
- BLI_assert(py_data != NULL);
+ BLI_assert(prop_store != NULL);
if (!is_write_ok) {
pyrna_write_set(true);
@@ -857,7 +928,7 @@ static void bpy_prop_int_array_get_cb(struct PointerRNA *ptr,
gilstate = PyGILState_Ensure();
}
- py_func = py_data[BPY_DATA_CB_SLOT_GET];
+ py_func = prop_store->py_data.get_fn;
args = PyTuple_New(1);
self = pyrna_struct_as_instance(ptr);
@@ -902,7 +973,7 @@ static void bpy_prop_int_array_set_cb(struct PointerRNA *ptr,
struct PropertyRNA *prop,
const int *values)
{
- PyObject **py_data = RNA_property_py_data_get(prop);
+ struct BPyPropStore *prop_store = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -913,7 +984,7 @@ static void bpy_prop_int_array_set_cb(struct PointerRNA *ptr,
const bool is_write_ok = pyrna_write_check();
const int len = RNA_property_array_length(ptr, prop);
- BLI_assert(py_data != NULL);
+ BLI_assert(prop_store != NULL);
if (!is_write_ok) {
pyrna_write_set(true);
@@ -925,7 +996,7 @@ static void bpy_prop_int_array_set_cb(struct PointerRNA *ptr,
gilstate = PyGILState_Ensure();
}
- py_func = py_data[BPY_DATA_CB_SLOT_SET];
+ py_func = prop_store->py_data.set_fn;
args = PyTuple_New(2);
self = pyrna_struct_as_instance(ptr);
@@ -961,7 +1032,7 @@ static void bpy_prop_int_array_set_cb(struct PointerRNA *ptr,
static float bpy_prop_float_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop)
{
- PyObject **py_data = RNA_property_py_data_get(prop);
+ struct BPyPropStore *prop_store = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -971,7 +1042,7 @@ static float bpy_prop_float_get_cb(struct PointerRNA *ptr, struct PropertyRNA *p
const bool is_write_ok = pyrna_write_check();
float value;
- BLI_assert(py_data != NULL);
+ BLI_assert(prop_store != NULL);
if (!is_write_ok) {
pyrna_write_set(true);
@@ -983,7 +1054,7 @@ static float bpy_prop_float_get_cb(struct PointerRNA *ptr, struct PropertyRNA *p
gilstate = PyGILState_Ensure();
}
- py_func = py_data[BPY_DATA_CB_SLOT_GET];
+ py_func = prop_store->py_data.get_fn;
args = PyTuple_New(1);
self = pyrna_struct_as_instance(ptr);
@@ -1021,7 +1092,7 @@ static float bpy_prop_float_get_cb(struct PointerRNA *ptr, struct PropertyRNA *p
static void bpy_prop_float_set_cb(struct PointerRNA *ptr, struct PropertyRNA *prop, float value)
{
- PyObject **py_data = RNA_property_py_data_get(prop);
+ struct BPyPropStore *prop_store = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -1030,7 +1101,7 @@ static void bpy_prop_float_set_cb(struct PointerRNA *ptr, struct PropertyRNA *pr
bool use_gil;
const bool is_write_ok = pyrna_write_check();
- BLI_assert(py_data != NULL);
+ BLI_assert(prop_store != NULL);
if (!is_write_ok) {
pyrna_write_set(true);
@@ -1042,7 +1113,7 @@ static void bpy_prop_float_set_cb(struct PointerRNA *ptr, struct PropertyRNA *pr
gilstate = PyGILState_Ensure();
}
- py_func = py_data[BPY_DATA_CB_SLOT_SET];
+ py_func = prop_store->py_data.set_fn;
args = PyTuple_New(2);
self = pyrna_struct_as_instance(ptr);
@@ -1079,7 +1150,7 @@ static void bpy_prop_float_array_get_cb(struct PointerRNA *ptr,
struct PropertyRNA *prop,
float *values)
{
- PyObject **py_data = RNA_property_py_data_get(prop);
+ struct BPyPropStore *prop_store = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -1089,7 +1160,7 @@ static void bpy_prop_float_array_get_cb(struct PointerRNA *ptr,
const bool is_write_ok = pyrna_write_check();
int i, len = RNA_property_array_length(ptr, prop);
- BLI_assert(py_data != NULL);
+ BLI_assert(prop_store != NULL);
if (!is_write_ok) {
pyrna_write_set(true);
@@ -1101,7 +1172,7 @@ static void bpy_prop_float_array_get_cb(struct PointerRNA *ptr,
gilstate = PyGILState_Ensure();
}
- py_func = py_data[BPY_DATA_CB_SLOT_GET];
+ py_func = prop_store->py_data.get_fn;
args = PyTuple_New(1);
self = pyrna_struct_as_instance(ptr);
@@ -1146,7 +1217,7 @@ static void bpy_prop_float_array_set_cb(struct PointerRNA *ptr,
struct PropertyRNA *prop,
const float *values)
{
- PyObject **py_data = RNA_property_py_data_get(prop);
+ struct BPyPropStore *prop_store = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -1157,7 +1228,7 @@ static void bpy_prop_float_array_set_cb(struct PointerRNA *ptr,
const bool is_write_ok = pyrna_write_check();
const int len = RNA_property_array_length(ptr, prop);
- BLI_assert(py_data != NULL);
+ BLI_assert(prop_store != NULL);
if (!is_write_ok) {
pyrna_write_set(true);
@@ -1169,7 +1240,7 @@ static void bpy_prop_float_array_set_cb(struct PointerRNA *ptr,
gilstate = PyGILState_Ensure();
}
- py_func = py_data[BPY_DATA_CB_SLOT_SET];
+ py_func = prop_store->py_data.set_fn;
args = PyTuple_New(2);
self = pyrna_struct_as_instance(ptr);
@@ -1205,7 +1276,7 @@ static void bpy_prop_float_array_set_cb(struct PointerRNA *ptr,
static void bpy_prop_string_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop, char *value)
{
- PyObject **py_data = RNA_property_py_data_get(prop);
+ struct BPyPropStore *prop_store = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -1214,7 +1285,7 @@ static void bpy_prop_string_get_cb(struct PointerRNA *ptr, struct PropertyRNA *p
bool use_gil;
const bool is_write_ok = pyrna_write_check();
- BLI_assert(py_data != NULL);
+ BLI_assert(prop_store != NULL);
if (!is_write_ok) {
pyrna_write_set(true);
@@ -1226,7 +1297,7 @@ static void bpy_prop_string_get_cb(struct PointerRNA *ptr, struct PropertyRNA *p
gilstate = PyGILState_Ensure();
}
- py_func = py_data[BPY_DATA_CB_SLOT_GET];
+ py_func = prop_store->py_data.get_fn;
args = PyTuple_New(1);
self = pyrna_struct_as_instance(ptr);
@@ -1265,7 +1336,7 @@ static void bpy_prop_string_get_cb(struct PointerRNA *ptr, struct PropertyRNA *p
static int bpy_prop_string_length_cb(struct PointerRNA *ptr, struct PropertyRNA *prop)
{
- PyObject **py_data = RNA_property_py_data_get(prop);
+ struct BPyPropStore *prop_store = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -1275,7 +1346,7 @@ static int bpy_prop_string_length_cb(struct PointerRNA *ptr, struct PropertyRNA
const bool is_write_ok = pyrna_write_check();
int length;
- BLI_assert(py_data != NULL);
+ BLI_assert(prop_store != NULL);
if (!is_write_ok) {
pyrna_write_set(true);
@@ -1287,7 +1358,7 @@ static int bpy_prop_string_length_cb(struct PointerRNA *ptr, struct PropertyRNA
gilstate = PyGILState_Ensure();
}
- py_func = py_data[BPY_DATA_CB_SLOT_GET];
+ py_func = prop_store->py_data.get_fn;
args = PyTuple_New(1);
self = pyrna_struct_as_instance(ptr);
@@ -1330,7 +1401,7 @@ static void bpy_prop_string_set_cb(struct PointerRNA *ptr,
struct PropertyRNA *prop,
const char *value)
{
- PyObject **py_data = RNA_property_py_data_get(prop);
+ struct BPyPropStore *prop_store = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -1340,7 +1411,7 @@ static void bpy_prop_string_set_cb(struct PointerRNA *ptr,
const bool is_write_ok = pyrna_write_check();
PyObject *py_value;
- BLI_assert(py_data != NULL);
+ BLI_assert(prop_store != NULL);
if (!is_write_ok) {
pyrna_write_set(true);
@@ -1352,7 +1423,7 @@ static void bpy_prop_string_set_cb(struct PointerRNA *ptr,
gilstate = PyGILState_Ensure();
}
- py_func = py_data[BPY_DATA_CB_SLOT_SET];
+ py_func = prop_store->py_data.set_fn;
args = PyTuple_New(2);
self = pyrna_struct_as_instance(ptr);
@@ -1394,7 +1465,7 @@ static void bpy_prop_string_set_cb(struct PointerRNA *ptr,
static int bpy_prop_enum_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop)
{
- PyObject **py_data = RNA_property_py_data_get(prop);
+ struct BPyPropStore *prop_store = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -1404,7 +1475,7 @@ static int bpy_prop_enum_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop
const bool is_write_ok = pyrna_write_check();
int value;
- BLI_assert(py_data != NULL);
+ BLI_assert(prop_store != NULL);
if (!is_write_ok) {
pyrna_write_set(true);
@@ -1416,7 +1487,7 @@ static int bpy_prop_enum_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop
gilstate = PyGILState_Ensure();
}
- py_func = py_data[BPY_DATA_CB_SLOT_GET];
+ py_func = prop_store->py_data.get_fn;
args = PyTuple_New(1);
self = pyrna_struct_as_instance(ptr);
@@ -1454,7 +1525,7 @@ static int bpy_prop_enum_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop
static void bpy_prop_enum_set_cb(struct PointerRNA *ptr, struct PropertyRNA *prop, int value)
{
- PyObject **py_data = RNA_property_py_data_get(prop);
+ struct BPyPropStore *prop_store = RNA_property_py_data_get(prop);
PyObject *py_func;
PyObject *args;
PyObject *self;
@@ -1463,7 +1534,7 @@ static void bpy_prop_enum_set_cb(struct PointerRNA *ptr, struct PropertyRNA *pro
bool use_gil;
const bool is_write_ok = pyrna_write_check();
- BLI_assert(py_data != NULL);
+ BLI_assert(prop_store != NULL);
if (!is_write_ok) {
pyrna_write_set(true);
@@ -1475,7 +1546,7 @@ static void bpy_prop_enum_set_cb(struct PointerRNA *ptr, struct PropertyRNA *pro
gilstate = PyGILState_Ensure();
}
- py_func = py_data[BPY_DATA_CB_SLOT_SET];
+ py_func = prop_store->py_data.set_fn;
args = PyTuple_New(2);
self = pyrna_struct_as_instance(ptr);
@@ -1732,8 +1803,8 @@ static const EnumPropertyItem *bpy_prop_enum_itemf_cb(struct bContext *C,
bool *r_free)
{
PyGILState_STATE gilstate;
-
- PyObject *py_func = RNA_property_enum_py_data_get(prop);
+ struct BPyPropStore *prop_store = RNA_property_py_data_get(prop);
+ PyObject *py_func = prop_store->py_data.enum_data.itemf_fn;
PyObject *self = NULL;
PyObject *args;
PyObject *items; /* returned from the function call */
@@ -1836,24 +1907,14 @@ static int bpy_prop_callback_check(PyObject *py_func, const char *keyword, int a
return 0;
}
-static PyObject **bpy_prop_py_data_get(struct PropertyRNA *prop)
-{
- PyObject **py_data = RNA_property_py_data_get(prop);
- if (!py_data) {
- py_data = MEM_callocN(sizeof(PyObject *) * BPY_DATA_CB_SLOT_SIZE, __func__);
- RNA_def_py_data(prop, py_data);
- }
- return py_data;
-}
-
static void bpy_prop_callback_assign_update(struct PropertyRNA *prop, PyObject *update_cb)
{
/* assume this is already checked for type and arg length */
if (update_cb && update_cb != Py_None) {
- PyObject **py_data = bpy_prop_py_data_get(prop);
+ struct BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
RNA_def_property_update_runtime(prop, (void *)bpy_prop_update_cb);
- py_data[BPY_DATA_CB_SLOT_UPDATE] = update_cb;
+ ASSIGN_PYOBJECT_INCREF(prop_store->py_data.update_fn, update_cb);
RNA_def_property_flag(prop, PROP_CONTEXT_PROPERTY_UPDATE);
}
@@ -1862,10 +1923,10 @@ static void bpy_prop_callback_assign_update(struct PropertyRNA *prop, PyObject *
static void bpy_prop_callback_assign_pointer(struct PropertyRNA *prop, PyObject *poll_cb)
{
if (poll_cb && poll_cb != Py_None) {
- PyObject **py_data = bpy_prop_py_data_get(prop);
+ struct BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
- RNA_def_property_poll_runtime(prop, (void *)bpy_prop_poll_cb);
- py_data[BPY_DATA_CB_SLOT_POLL] = poll_cb;
+ RNA_def_property_poll_runtime(prop, bpy_prop_poll_cb);
+ ASSIGN_PYOBJECT_INCREF(prop_store->py_data.poll_fn, poll_cb);
}
}
@@ -1877,17 +1938,17 @@ static void bpy_prop_callback_assign_boolean(struct PropertyRNA *prop,
BooleanPropertySetFunc rna_set_cb = NULL;
if (get_cb && get_cb != Py_None) {
- PyObject **py_data = bpy_prop_py_data_get(prop);
+ struct BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
rna_get_cb = bpy_prop_boolean_get_cb;
- py_data[BPY_DATA_CB_SLOT_GET] = get_cb;
+ ASSIGN_PYOBJECT_INCREF(prop_store->py_data.get_fn, get_cb);
}
if (set_cb && set_cb != Py_None) {
- PyObject **py_data = bpy_prop_py_data_get(prop);
+ struct BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
rna_set_cb = bpy_prop_boolean_set_cb;
- py_data[BPY_DATA_CB_SLOT_SET] = set_cb;
+ ASSIGN_PYOBJECT_INCREF(prop_store->py_data.set_fn, set_cb);
}
RNA_def_property_boolean_funcs_runtime(prop, rna_get_cb, rna_set_cb);
@@ -1901,17 +1962,17 @@ static void bpy_prop_callback_assign_boolean_array(struct PropertyRNA *prop,
BooleanArrayPropertySetFunc rna_set_cb = NULL;
if (get_cb && get_cb != Py_None) {
- PyObject **py_data = bpy_prop_py_data_get(prop);
+ struct BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
rna_get_cb = bpy_prop_boolean_array_get_cb;
- py_data[BPY_DATA_CB_SLOT_GET] = get_cb;
+ ASSIGN_PYOBJECT_INCREF(prop_store->py_data.get_fn, get_cb);
}
if (set_cb && set_cb != Py_None) {
- PyObject **py_data = bpy_prop_py_data_get(prop);
+ struct BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
rna_set_cb = bpy_prop_boolean_array_set_cb;
- py_data[BPY_DATA_CB_SLOT_SET] = set_cb;
+ ASSIGN_PYOBJECT_INCREF(prop_store->py_data.set_fn, set_cb);
}
RNA_def_property_boolean_array_funcs_runtime(prop, rna_get_cb, rna_set_cb);
@@ -1925,17 +1986,17 @@ static void bpy_prop_callback_assign_int(struct PropertyRNA *prop,
IntPropertySetFunc rna_set_cb = NULL;
if (get_cb && get_cb != Py_None) {
- PyObject **py_data = bpy_prop_py_data_get(prop);
+ struct BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
rna_get_cb = bpy_prop_int_get_cb;
- py_data[BPY_DATA_CB_SLOT_GET] = get_cb;
+ ASSIGN_PYOBJECT_INCREF(prop_store->py_data.get_fn, get_cb);
}
if (set_cb && set_cb != Py_None) {
- PyObject **py_data = bpy_prop_py_data_get(prop);
+ struct BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
rna_set_cb = bpy_prop_int_set_cb;
- py_data[BPY_DATA_CB_SLOT_SET] = set_cb;
+ ASSIGN_PYOBJECT_INCREF(prop_store->py_data.set_fn, set_cb);
}
RNA_def_property_int_funcs_runtime(prop, rna_get_cb, rna_set_cb, NULL);
@@ -1949,17 +2010,17 @@ static void bpy_prop_callback_assign_int_array(struct PropertyRNA *prop,
IntArrayPropertySetFunc rna_set_cb = NULL;
if (get_cb && get_cb != Py_None) {
- PyObject **py_data = bpy_prop_py_data_get(prop);
+ struct BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
rna_get_cb = bpy_prop_int_array_get_cb;
- py_data[BPY_DATA_CB_SLOT_GET] = get_cb;
+ ASSIGN_PYOBJECT_INCREF(prop_store->py_data.get_fn, get_cb);
}
if (set_cb && set_cb != Py_None) {
- PyObject **py_data = bpy_prop_py_data_get(prop);
+ struct BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
rna_set_cb = bpy_prop_int_array_set_cb;
- py_data[BPY_DATA_CB_SLOT_SET] = set_cb;
+ ASSIGN_PYOBJECT_INCREF(prop_store->py_data.set_fn, set_cb);
}
RNA_def_property_int_array_funcs_runtime(prop, rna_get_cb, rna_set_cb, NULL);
@@ -1973,17 +2034,17 @@ static void bpy_prop_callback_assign_float(struct PropertyRNA *prop,
FloatPropertySetFunc rna_set_cb = NULL;
if (get_cb && get_cb != Py_None) {
- PyObject **py_data = bpy_prop_py_data_get(prop);
+ struct BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
rna_get_cb = bpy_prop_float_get_cb;
- py_data[BPY_DATA_CB_SLOT_GET] = get_cb;
+ ASSIGN_PYOBJECT_INCREF(prop_store->py_data.get_fn, get_cb);
}
if (set_cb && set_cb != Py_None) {
- PyObject **py_data = bpy_prop_py_data_get(prop);
+ struct BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
rna_set_cb = bpy_prop_float_set_cb;
- py_data[BPY_DATA_CB_SLOT_SET] = set_cb;
+ ASSIGN_PYOBJECT_INCREF(prop_store->py_data.set_fn, set_cb);
}
RNA_def_property_float_funcs_runtime(prop, rna_get_cb, rna_set_cb, NULL);
@@ -1997,17 +2058,17 @@ static void bpy_prop_callback_assign_float_array(struct PropertyRNA *prop,
FloatArrayPropertySetFunc rna_set_cb = NULL;
if (get_cb && get_cb != Py_None) {
- PyObject **py_data = bpy_prop_py_data_get(prop);
+ struct BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
rna_get_cb = bpy_prop_float_array_get_cb;
- py_data[BPY_DATA_CB_SLOT_GET] = get_cb;
+ ASSIGN_PYOBJECT_INCREF(prop_store->py_data.get_fn, get_cb);
}
if (set_cb && set_cb != Py_None) {
- PyObject **py_data = bpy_prop_py_data_get(prop);
+ struct BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
rna_set_cb = bpy_prop_float_array_set_cb;
- py_data[BPY_DATA_CB_SLOT_SET] = set_cb;
+ ASSIGN_PYOBJECT_INCREF(prop_store->py_data.set_fn, set_cb);
}
RNA_def_property_float_array_funcs_runtime(prop, rna_get_cb, rna_set_cb, NULL);
@@ -2022,18 +2083,18 @@ static void bpy_prop_callback_assign_string(struct PropertyRNA *prop,
StringPropertySetFunc rna_set_cb = NULL;
if (get_cb && get_cb != Py_None) {
- PyObject **py_data = bpy_prop_py_data_get(prop);
+ struct BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
rna_get_cb = bpy_prop_string_get_cb;
rna_length_cb = bpy_prop_string_length_cb;
- py_data[BPY_DATA_CB_SLOT_GET] = get_cb;
+ ASSIGN_PYOBJECT_INCREF(prop_store->py_data.get_fn, get_cb);
}
if (set_cb && set_cb != Py_None) {
- PyObject **py_data = bpy_prop_py_data_get(prop);
+ struct BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
rna_set_cb = bpy_prop_string_set_cb;
- py_data[BPY_DATA_CB_SLOT_SET] = set_cb;
+ ASSIGN_PYOBJECT_INCREF(prop_store->py_data.set_fn, set_cb);
}
RNA_def_property_string_funcs_runtime(prop, rna_get_cb, rna_length_cb, rna_set_cb);
@@ -2049,26 +2110,23 @@ static void bpy_prop_callback_assign_enum(struct PropertyRNA *prop,
EnumPropertySetFunc rna_set_cb = NULL;
if (get_cb && get_cb != Py_None) {
- PyObject **py_data = bpy_prop_py_data_get(prop);
+ struct BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
rna_get_cb = bpy_prop_enum_get_cb;
- py_data[BPY_DATA_CB_SLOT_GET] = get_cb;
+ ASSIGN_PYOBJECT_INCREF(prop_store->py_data.get_fn, get_cb);
}
if (set_cb && set_cb != Py_None) {
- PyObject **py_data = bpy_prop_py_data_get(prop);
+ struct BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
rna_set_cb = bpy_prop_enum_set_cb;
- py_data[BPY_DATA_CB_SLOT_SET] = set_cb;
+ ASSIGN_PYOBJECT_INCREF(prop_store->py_data.set_fn, set_cb);
}
if (itemf_cb && itemf_cb != Py_None) {
+ struct BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
rna_itemf_cb = bpy_prop_enum_itemf_cb;
- RNA_def_property_enum_py_data(prop, (void *)itemf_cb);
-
- /* watch out!, if a user is tricky they can probably crash blender
- * if they manage to free the callback, take care! */
- /* Py_INCREF(itemf_cb); */
+ ASSIGN_PYOBJECT_INCREF(prop_store->py_data.enum_data.itemf_fn, itemf_cb);
}
RNA_def_property_enum_funcs_runtime(prop, rna_get_cb, rna_set_cb, rna_itemf_cb);
@@ -3723,6 +3781,28 @@ static struct PyMethodDef props_methods[] = {
{NULL, NULL, 0, NULL},
};
+static int props_visit(PyObject *UNUSED(self), visitproc visit, void *arg)
+{
+ LISTBASE_FOREACH (struct BPyPropStore *, prop_store, &g_bpy_prop_store_list) {
+ PyObject **py_data = (PyObject **)&prop_store->py_data;
+ for (int i = 0; i < BPY_PROP_STORE_PY_DATA_SIZE; i++) {
+ Py_VISIT(py_data[i]);
+ }
+ }
+ return 0;
+}
+
+static int props_clear(PyObject *UNUSED(self))
+{
+ LISTBASE_FOREACH (struct BPyPropStore *, prop_store, &g_bpy_prop_store_list) {
+ PyObject **py_data = (PyObject **)&prop_store->py_data;
+ for (int i = 0; i < BPY_PROP_STORE_PY_DATA_SIZE; i++) {
+ Py_CLEAR(py_data[i]);
+ }
+ }
+ return 0;
+}
+
static struct PyModuleDef props_module = {
PyModuleDef_HEAD_INIT,
"bpy.props",
@@ -3735,8 +3815,8 @@ static struct PyModuleDef props_module = {
-1, /* multiple "initialization" just copies the module dict. */
props_methods,
NULL,
- NULL,
- NULL,
+ props_visit,
+ props_clear,
NULL,
};
@@ -3770,5 +3850,24 @@ PyObject *BPY_rna_props(void)
}
PyModule_AddType(submodule, &bpy_prop_deferred_Type);
+ /* Run this when properties are freed. */
+ RNA_def_property_free_pointers_set_py_data_callback(bpy_prop_py_data_remove);
+
return submodule;
}
+
+/**
+ * Run this on exit, clearing all Python callback users and disable the RNA callback,
+ * as it would be called after Python has already finished.
+ */
+void BPY_rna_props_clear_all(void)
+{
+ /* Remove all user counts, so this isn't considered a leak from Python's perspective. */
+ props_clear(NULL);
+
+ /* Running is harmless, but redundant. */
+ RNA_def_property_free_pointers_set_py_data_callback(NULL);
+
+ /* Include as it's correct, in practice this should never be used again. */
+ BLI_listbase_clear(&g_bpy_prop_store_list);
+}
diff --git a/source/blender/python/intern/bpy_props.h b/source/blender/python/intern/bpy_props.h
index 6cebf82d373..d467166f354 100644
--- a/source/blender/python/intern/bpy_props.h
+++ b/source/blender/python/intern/bpy_props.h
@@ -25,6 +25,7 @@ extern "C" {
#endif
PyObject *BPY_rna_props(void);
+void BPY_rna_props_clear_all(void);
PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw);
PyObject *BPy_CollectionProperty(PyObject *self, PyObject *args, PyObject *kw);