Support for actual class methods in the RNA/bpy. Previously all functions with FUNC_NO_SELF were treated as static methods, which is not sufficient for getting actual type information if the function can not be generated in advance in makesrna. Now the FUNC_USE_SELF_TYPE flag can be set in addition to FUNC_NO_SELF (if FUNC_NO_SELF is not set, FUNC_USE_SELF_TYPE has no effect). Such functions will be interpreted as class methods and must take a StructRNA pointer argument. This pointer is the same as the type member in PointerRNA, but can be passed without an actual data/id instance.
This commit is contained in:
@@ -309,9 +309,10 @@ typedef struct ParameterDynAlloc {
|
|||||||
|
|
||||||
typedef enum FunctionFlag {
|
typedef enum FunctionFlag {
|
||||||
FUNC_NO_SELF = 1, /* for static functions */
|
FUNC_NO_SELF = 1, /* for static functions */
|
||||||
FUNC_USE_MAIN = 2,
|
FUNC_USE_SELF_TYPE = 2, /* for class methods, only used when FUNC_NO_SELF is set */
|
||||||
FUNC_USE_CONTEXT = 4,
|
FUNC_USE_MAIN = 4,
|
||||||
FUNC_USE_REPORTS = 8,
|
FUNC_USE_CONTEXT = 8,
|
||||||
|
FUNC_USE_REPORTS = 16,
|
||||||
FUNC_USE_SELF_ID = 2048,
|
FUNC_USE_SELF_ID = 2048,
|
||||||
FUNC_ALLOW_WRITE = 4096,
|
FUNC_ALLOW_WRITE = 4096,
|
||||||
|
|
||||||
|
|||||||
@@ -1989,6 +1989,10 @@ static void rna_def_struct_function_call_impl_cpp(FILE *f, StructRNA *srna, Func
|
|||||||
if (dsrna->dnaname) fprintf(f, "(::%s *) this->ptr.data", dsrna->dnaname);
|
if (dsrna->dnaname) fprintf(f, "(::%s *) this->ptr.data", dsrna->dnaname);
|
||||||
else fprintf(f, "(::%s *) this->ptr.data", srna->identifier);
|
else fprintf(f, "(::%s *) this->ptr.data", srna->identifier);
|
||||||
}
|
}
|
||||||
|
else if (func->flag & FUNC_USE_SELF_TYPE) {
|
||||||
|
WRITE_COMMA;
|
||||||
|
fprintf(f, "this->ptr.type");
|
||||||
|
}
|
||||||
|
|
||||||
if (func->flag & FUNC_USE_MAIN)
|
if (func->flag & FUNC_USE_MAIN)
|
||||||
WRITE_PARAM("(::Main *) main");
|
WRITE_PARAM("(::Main *) main");
|
||||||
@@ -2112,8 +2116,12 @@ static void rna_def_function_wrapper_funcs(FILE *f, StructDefRNA *dsrna, Functio
|
|||||||
if (func->flag & FUNC_USE_SELF_ID)
|
if (func->flag & FUNC_USE_SELF_ID)
|
||||||
WRITE_PARAM("_selfid");
|
WRITE_PARAM("_selfid");
|
||||||
|
|
||||||
if ((func->flag & FUNC_NO_SELF) == 0)
|
if ((func->flag & FUNC_NO_SELF) == 0) {
|
||||||
WRITE_PARAM("_self");
|
WRITE_PARAM("_self");
|
||||||
|
}
|
||||||
|
else if (func->flag & FUNC_USE_SELF_TYPE) {
|
||||||
|
WRITE_PARAM("_type");
|
||||||
|
}
|
||||||
|
|
||||||
if (func->flag & FUNC_USE_MAIN)
|
if (func->flag & FUNC_USE_MAIN)
|
||||||
WRITE_PARAM("bmain");
|
WRITE_PARAM("bmain");
|
||||||
@@ -2174,6 +2182,9 @@ static void rna_def_function_funcs(FILE *f, StructDefRNA *dsrna, FunctionDefRNA
|
|||||||
if (dsrna->dnaname) fprintf(f, "\tstruct %s *_self;\n", dsrna->dnaname);
|
if (dsrna->dnaname) fprintf(f, "\tstruct %s *_self;\n", dsrna->dnaname);
|
||||||
else fprintf(f, "\tstruct %s *_self;\n", srna->identifier);
|
else fprintf(f, "\tstruct %s *_self;\n", srna->identifier);
|
||||||
}
|
}
|
||||||
|
else if (func->flag & FUNC_USE_SELF_TYPE) {
|
||||||
|
fprintf(f, "\tstruct StructRNA *_type;\n");
|
||||||
|
}
|
||||||
|
|
||||||
dparm = dfunc->cont.properties.first;
|
dparm = dfunc->cont.properties.first;
|
||||||
for (; dparm; dparm = dparm->next) {
|
for (; dparm; dparm = dparm->next) {
|
||||||
@@ -2223,6 +2234,9 @@ static void rna_def_function_funcs(FILE *f, StructDefRNA *dsrna, FunctionDefRNA
|
|||||||
if (dsrna->dnaname) fprintf(f, "\t_self= (struct %s *)_ptr->data;\n", dsrna->dnaname);
|
if (dsrna->dnaname) fprintf(f, "\t_self= (struct %s *)_ptr->data;\n", dsrna->dnaname);
|
||||||
else fprintf(f, "\t_self= (struct %s *)_ptr->data;\n", srna->identifier);
|
else fprintf(f, "\t_self= (struct %s *)_ptr->data;\n", srna->identifier);
|
||||||
}
|
}
|
||||||
|
else if (func->flag & FUNC_USE_SELF_TYPE) {
|
||||||
|
fprintf(f, "\t_type= _ptr->type;\n");
|
||||||
|
}
|
||||||
|
|
||||||
if (has_data) {
|
if (has_data) {
|
||||||
fprintf(f, "\t_data= (char *)_parms->data;\n");
|
fprintf(f, "\t_data= (char *)_parms->data;\n");
|
||||||
@@ -2300,6 +2314,11 @@ static void rna_def_function_funcs(FILE *f, StructDefRNA *dsrna, FunctionDefRNA
|
|||||||
fprintf(f, "_self");
|
fprintf(f, "_self");
|
||||||
first = 0;
|
first = 0;
|
||||||
}
|
}
|
||||||
|
else if (func->flag & FUNC_USE_SELF_TYPE) {
|
||||||
|
if (!first) fprintf(f, ", ");
|
||||||
|
fprintf(f, "_type");
|
||||||
|
first = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (func->flag & FUNC_USE_MAIN) {
|
if (func->flag & FUNC_USE_MAIN) {
|
||||||
if (!first) fprintf(f, ", ");
|
if (!first) fprintf(f, ", ");
|
||||||
@@ -2613,6 +2632,11 @@ static void rna_generate_static_parameter_prototypes(FILE *f, StructRNA *srna, F
|
|||||||
else fprintf(f, "struct %s *_self", srna->identifier);
|
else fprintf(f, "struct %s *_self", srna->identifier);
|
||||||
first = 0;
|
first = 0;
|
||||||
}
|
}
|
||||||
|
else if (func->flag & FUNC_USE_SELF_TYPE) {
|
||||||
|
if (!first) fprintf(f, ", ");
|
||||||
|
fprintf(f, "struct StructRNA *_type");
|
||||||
|
first = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (func->flag & FUNC_USE_MAIN) {
|
if (func->flag & FUNC_USE_MAIN) {
|
||||||
if (!first) fprintf(f, ", ");
|
if (!first) fprintf(f, ", ");
|
||||||
|
|||||||
@@ -939,6 +939,12 @@ static int rna_Function_no_self_get(PointerRNA *ptr)
|
|||||||
return !(func->flag & FUNC_NO_SELF);
|
return !(func->flag & FUNC_NO_SELF);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int rna_Function_use_self_type_get(PointerRNA *ptr)
|
||||||
|
{
|
||||||
|
FunctionRNA *func = (FunctionRNA *)ptr->data;
|
||||||
|
return (func->flag & FUNC_USE_SELF_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
/* Blender RNA */
|
/* Blender RNA */
|
||||||
|
|
||||||
static void rna_BlenderRNA_structs_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
|
static void rna_BlenderRNA_structs_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
|
||||||
@@ -1230,7 +1236,13 @@ static void rna_def_function(BlenderRNA *brna)
|
|||||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||||
RNA_def_property_boolean_funcs(prop, "rna_Function_no_self_get", NULL);
|
RNA_def_property_boolean_funcs(prop, "rna_Function_no_self_get", NULL);
|
||||||
RNA_def_property_ui_text(prop, "No Self",
|
RNA_def_property_ui_text(prop, "No Self",
|
||||||
"Function does not pass its self as an argument (becomes a class method in python)");
|
"Function does not pass its self as an argument (becomes a static method in python)");
|
||||||
|
|
||||||
|
prop = RNA_def_property(srna, "use_self_type", PROP_BOOLEAN, PROP_NONE);
|
||||||
|
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||||
|
RNA_def_property_boolean_funcs(prop, "rna_Function_use_self_type_get", NULL);
|
||||||
|
RNA_def_property_ui_text(prop, "Use Self Type",
|
||||||
|
"Function passes its self type as an argument (becomes a class method in python if use_self is false)");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rna_def_number_property(StructRNA *srna, PropertyType type)
|
static void rna_def_number_property(StructRNA *srna, PropertyType type)
|
||||||
|
|||||||
@@ -6035,7 +6035,7 @@ static void pyrna_subtype_set_rna(PyObject *newclass, StructRNA *srna)
|
|||||||
PyObject_SetAttr(newclass, bpy_intern_str_bl_rna, item);
|
PyObject_SetAttr(newclass, bpy_intern_str_bl_rna, item);
|
||||||
Py_DECREF(item);
|
Py_DECREF(item);
|
||||||
|
|
||||||
/* add classmethods */
|
/* add staticmethods and classmethods */
|
||||||
{
|
{
|
||||||
const PointerRNA func_ptr = {{NULL}, srna, NULL};
|
const PointerRNA func_ptr = {{NULL}, srna, NULL};
|
||||||
const ListBase *lb;
|
const ListBase *lb;
|
||||||
@@ -6045,10 +6045,10 @@ static void pyrna_subtype_set_rna(PyObject *newclass, StructRNA *srna)
|
|||||||
for (link = lb->first; link; link = link->next) {
|
for (link = lb->first; link; link = link->next) {
|
||||||
FunctionRNA *func = (FunctionRNA *)link;
|
FunctionRNA *func = (FunctionRNA *)link;
|
||||||
const int flag = RNA_function_flag(func);
|
const int flag = RNA_function_flag(func);
|
||||||
if ((flag & FUNC_NO_SELF) && /* is classmethod */
|
if ((flag & FUNC_NO_SELF) && /* is staticmethod or classmethod */
|
||||||
(flag & FUNC_REGISTER) == FALSE) /* is not for registration */
|
(flag & FUNC_REGISTER) == FALSE) /* is not for registration */
|
||||||
{
|
{
|
||||||
/* we may went to set the type of this later */
|
/* we may want to set the type of this later */
|
||||||
PyObject *func_py = pyrna_func_to_py(&func_ptr, func);
|
PyObject *func_py = pyrna_func_to_py(&func_ptr, func);
|
||||||
PyObject_SetAttrString(newclass, RNA_function_identifier(func), func_py);
|
PyObject_SetAttrString(newclass, RNA_function_identifier(func), func_py);
|
||||||
Py_DECREF(func_py);
|
Py_DECREF(func_py);
|
||||||
@@ -6786,7 +6786,9 @@ static int rna_function_arg_count(FunctionRNA *func)
|
|||||||
const ListBase *lb = RNA_function_defined_parameters(func);
|
const ListBase *lb = RNA_function_defined_parameters(func);
|
||||||
PropertyRNA *parm;
|
PropertyRNA *parm;
|
||||||
Link *link;
|
Link *link;
|
||||||
int count = (RNA_function_flag(func) & FUNC_NO_SELF) ? 0 : 1;
|
int flag = RNA_function_flag(func);
|
||||||
|
int is_staticmethod = (flag & FUNC_NO_SELF) && !(flag & FUNC_USE_SELF_TYPE);
|
||||||
|
int count = is_staticmethod ? 0 : 1;
|
||||||
|
|
||||||
for (link = lb->first; link; link = link->next) {
|
for (link = lb->first; link; link = link->next) {
|
||||||
parm = (PropertyRNA *)link;
|
parm = (PropertyRNA *)link;
|
||||||
@@ -6808,7 +6810,7 @@ static int bpy_class_validate_recursive(PointerRNA *dummyptr, StructRNA *srna, v
|
|||||||
PyObject *py_class = (PyObject *)py_data;
|
PyObject *py_class = (PyObject *)py_data;
|
||||||
PyObject *base_class = RNA_struct_py_type_get(srna);
|
PyObject *base_class = RNA_struct_py_type_get(srna);
|
||||||
PyObject *item;
|
PyObject *item;
|
||||||
int i, flag, arg_count, func_arg_count;
|
int i, flag, is_staticmethod, arg_count, func_arg_count;
|
||||||
const char *py_class_name = ((PyTypeObject *)py_class)->tp_name; /* __name__ */
|
const char *py_class_name = ((PyTypeObject *)py_class)->tp_name; /* __name__ */
|
||||||
|
|
||||||
if (srna_base) {
|
if (srna_base) {
|
||||||
@@ -6831,6 +6833,7 @@ static int bpy_class_validate_recursive(PointerRNA *dummyptr, StructRNA *srna, v
|
|||||||
for (link = lb->first; link; link = link->next) {
|
for (link = lb->first; link; link = link->next) {
|
||||||
func = (FunctionRNA *)link;
|
func = (FunctionRNA *)link;
|
||||||
flag = RNA_function_flag(func);
|
flag = RNA_function_flag(func);
|
||||||
|
is_staticmethod = (flag & FUNC_NO_SELF) && !(flag & FUNC_USE_SELF_TYPE);
|
||||||
|
|
||||||
if (!(flag & FUNC_REGISTER))
|
if (!(flag & FUNC_REGISTER))
|
||||||
continue;
|
continue;
|
||||||
@@ -6853,7 +6856,7 @@ static int bpy_class_validate_recursive(PointerRNA *dummyptr, StructRNA *srna, v
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Py_DECREF(item); /* no need to keep a ref, the class owns it (technically we should keep a ref but...) */
|
Py_DECREF(item); /* no need to keep a ref, the class owns it (technically we should keep a ref but...) */
|
||||||
if (flag & FUNC_NO_SELF) {
|
if (is_staticmethod) {
|
||||||
if (PyMethod_Check(item) == 0) {
|
if (PyMethod_Check(item) == 0) {
|
||||||
PyErr_Format(PyExc_TypeError,
|
PyErr_Format(PyExc_TypeError,
|
||||||
"expected %.200s, %.200s class \"%.200s\" attribute to be a method, not a %.200s",
|
"expected %.200s, %.200s class \"%.200s\" attribute to be a method, not a %.200s",
|
||||||
@@ -6877,9 +6880,9 @@ static int bpy_class_validate_recursive(PointerRNA *dummyptr, StructRNA *srna, v
|
|||||||
arg_count = ((PyCodeObject *)PyFunction_GET_CODE(item))->co_argcount;
|
arg_count = ((PyCodeObject *)PyFunction_GET_CODE(item))->co_argcount;
|
||||||
|
|
||||||
/* note, the number of args we check for and the number of args we give to
|
/* note, the number of args we check for and the number of args we give to
|
||||||
* @classmethods are different (quirk of python),
|
* @staticmethods are different (quirk of python),
|
||||||
* this is why rna_function_arg_count() doesn't return the value -1*/
|
* this is why rna_function_arg_count() doesn't return the value -1*/
|
||||||
if (flag & FUNC_NO_SELF)
|
if (is_staticmethod)
|
||||||
func_arg_count++;
|
func_arg_count++;
|
||||||
|
|
||||||
if (arg_count != func_arg_count) {
|
if (arg_count != func_arg_count) {
|
||||||
@@ -6964,8 +6967,10 @@ static int bpy_class_call(bContext *C, PointerRNA *ptr, FunctionRNA *func, Param
|
|||||||
PropertyRNA *parm;
|
PropertyRNA *parm;
|
||||||
ParameterIterator iter;
|
ParameterIterator iter;
|
||||||
PointerRNA funcptr;
|
PointerRNA funcptr;
|
||||||
int err = 0, i, flag, ret_len = 0;
|
int err = 0, i, ret_len = 0;
|
||||||
const char is_static = (RNA_function_flag(func) & FUNC_NO_SELF) != 0;
|
int flag = RNA_function_flag(func);
|
||||||
|
const char is_staticmethod = (flag & FUNC_NO_SELF) && !(flag & FUNC_USE_SELF_TYPE);
|
||||||
|
const char is_classmethod = (flag & FUNC_NO_SELF) && (flag & FUNC_USE_SELF_TYPE);
|
||||||
|
|
||||||
/* annoying!, need to check if the screen gets set to NULL which is a
|
/* annoying!, need to check if the screen gets set to NULL which is a
|
||||||
* hint that the file was actually re-loaded. */
|
* hint that the file was actually re-loaded. */
|
||||||
@@ -7000,7 +7005,7 @@ static int bpy_class_call(bContext *C, PointerRNA *ptr, FunctionRNA *func, Param
|
|||||||
|
|
||||||
bpy_context_set(C, &gilstate);
|
bpy_context_set(C, &gilstate);
|
||||||
|
|
||||||
if (!is_static) {
|
if (!(is_staticmethod || is_classmethod)) {
|
||||||
/* some datatypes (operator, render engine) can store PyObjects for re-use */
|
/* some datatypes (operator, render engine) can store PyObjects for re-use */
|
||||||
if (ptr->data) {
|
if (ptr->data) {
|
||||||
void **instance = RNA_struct_instance(ptr);
|
void **instance = RNA_struct_instance(ptr);
|
||||||
@@ -7091,18 +7096,21 @@ static int bpy_class_call(bContext *C, PointerRNA *ptr, FunctionRNA *func, Param
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err != -1 && (is_static || py_class_instance)) { /* Initializing the class worked, now run its invoke function */
|
if (err != -1 && (is_staticmethod || is_classmethod || py_class_instance)) { /* Initializing the class worked, now run its invoke function */
|
||||||
PyObject *item = PyObject_GetAttrString((PyObject *)py_class, RNA_function_identifier(func));
|
PyObject *item = PyObject_GetAttrString((PyObject *)py_class, RNA_function_identifier(func));
|
||||||
// flag = RNA_function_flag(func);
|
|
||||||
|
|
||||||
if (item) {
|
if (item) {
|
||||||
RNA_pointer_create(NULL, &RNA_Function, func, &funcptr);
|
RNA_pointer_create(NULL, &RNA_Function, func, &funcptr);
|
||||||
|
|
||||||
args = PyTuple_New(rna_function_arg_count(func)); /* first arg is included in 'item' */
|
args = PyTuple_New(rna_function_arg_count(func)); /* first arg is included in 'item' */
|
||||||
|
|
||||||
if (is_static) {
|
if (is_staticmethod) {
|
||||||
i = 0;
|
i = 0;
|
||||||
}
|
}
|
||||||
|
else if (is_classmethod) {
|
||||||
|
PyTuple_SET_ITEM(args, 0, (PyObject *)py_class);
|
||||||
|
i = 1;
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
PyTuple_SET_ITEM(args, 0, py_class_instance);
|
PyTuple_SET_ITEM(args, 0, py_class_instance);
|
||||||
i = 1;
|
i = 1;
|
||||||
@@ -7236,7 +7244,7 @@ static int bpy_class_call(bContext *C, PointerRNA *ptr, FunctionRNA *func, Param
|
|||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
ReportList *reports;
|
ReportList *reports;
|
||||||
/* alert the user, else they wont know unless they see the console. */
|
/* alert the user, else they wont know unless they see the console. */
|
||||||
if ((!is_static) &&
|
if ((!is_staticmethod) && (!is_classmethod) &&
|
||||||
(ptr->data) &&
|
(ptr->data) &&
|
||||||
(RNA_struct_is_a(ptr->type, &RNA_Operator)) &&
|
(RNA_struct_is_a(ptr->type, &RNA_Operator)) &&
|
||||||
(is_valid_wm == (CTX_wm_manager(C) != NULL)))
|
(is_valid_wm == (CTX_wm_manager(C) != NULL)))
|
||||||
|
|||||||
Reference in New Issue
Block a user