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:
Lukas Toenne
2012-12-20 09:33:12 +00:00
parent b3dc1d585a
commit 35c2267aee
4 changed files with 65 additions and 20 deletions

View File

@@ -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,

View File

@@ -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, ", ");

View File

@@ -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)

View File

@@ -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)))