From 35c2267aee84d086c00574496b52e9c0641e320d Mon Sep 17 00:00:00 2001 From: Lukas Toenne Date: Thu, 20 Dec 2012 09:33:12 +0000 Subject: 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. --- source/blender/makesrna/RNA_types.h | 7 +++--- source/blender/makesrna/intern/makesrna.c | 26 ++++++++++++++++++++- source/blender/makesrna/intern/rna_rna.c | 14 +++++++++++- source/blender/python/intern/bpy_rna.c | 38 +++++++++++++++++++------------ 4 files changed, 65 insertions(+), 20 deletions(-) (limited to 'source/blender') diff --git a/source/blender/makesrna/RNA_types.h b/source/blender/makesrna/RNA_types.h index 87504dc6eb7..dacb2fee212 100644 --- a/source/blender/makesrna/RNA_types.h +++ b/source/blender/makesrna/RNA_types.h @@ -309,9 +309,10 @@ typedef struct ParameterDynAlloc { typedef enum FunctionFlag { FUNC_NO_SELF = 1, /* for static functions */ - FUNC_USE_MAIN = 2, - FUNC_USE_CONTEXT = 4, - FUNC_USE_REPORTS = 8, + FUNC_USE_SELF_TYPE = 2, /* for class methods, only used when FUNC_NO_SELF is set */ + FUNC_USE_MAIN = 4, + FUNC_USE_CONTEXT = 8, + FUNC_USE_REPORTS = 16, FUNC_USE_SELF_ID = 2048, FUNC_ALLOW_WRITE = 4096, diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index 9b7872f0b4b..2785a95ddb0 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -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); 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) 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) WRITE_PARAM("_selfid"); - if ((func->flag & FUNC_NO_SELF) == 0) + if ((func->flag & FUNC_NO_SELF) == 0) { WRITE_PARAM("_self"); + } + else if (func->flag & FUNC_USE_SELF_TYPE) { + WRITE_PARAM("_type"); + } if (func->flag & FUNC_USE_MAIN) 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); 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; 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); 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) { 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"); 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 (!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); 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 (!first) fprintf(f, ", "); diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c index 7355e464fc3..3f03445635f 100644 --- a/source/blender/makesrna/intern/rna_rna.c +++ b/source/blender/makesrna/intern/rna_rna.c @@ -939,6 +939,12 @@ static int rna_Function_no_self_get(PointerRNA *ptr) 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 */ 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_boolean_funcs(prop, "rna_Function_no_self_get", NULL); 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) diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index b70e855d332..cca37ee1dc3 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -6035,7 +6035,7 @@ static void pyrna_subtype_set_rna(PyObject *newclass, StructRNA *srna) PyObject_SetAttr(newclass, bpy_intern_str_bl_rna, item); Py_DECREF(item); - /* add classmethods */ + /* add staticmethods and classmethods */ { const PointerRNA func_ptr = {{NULL}, srna, NULL}; 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) { FunctionRNA *func = (FunctionRNA *)link; 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 */ { - /* 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_SetAttrString(newclass, RNA_function_identifier(func), 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); PropertyRNA *parm; 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) { 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 *base_class = RNA_struct_py_type_get(srna); 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__ */ 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) { func = (FunctionRNA *)link; flag = RNA_function_flag(func); + is_staticmethod = (flag & FUNC_NO_SELF) && !(flag & FUNC_USE_SELF_TYPE); if (!(flag & FUNC_REGISTER)) continue; @@ -6853,7 +6856,7 @@ static int bpy_class_validate_recursive(PointerRNA *dummyptr, StructRNA *srna, v } else { 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) { PyErr_Format(PyExc_TypeError, "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; /* 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*/ - if (flag & FUNC_NO_SELF) + if (is_staticmethod) 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; ParameterIterator iter; PointerRNA funcptr; - int err = 0, i, flag, ret_len = 0; - const char is_static = (RNA_function_flag(func) & FUNC_NO_SELF) != 0; + int err = 0, i, ret_len = 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 * 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); - if (!is_static) { + if (!(is_staticmethod || is_classmethod)) { /* some datatypes (operator, render engine) can store PyObjects for re-use */ if (ptr->data) { 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)); -// flag = RNA_function_flag(func); if (item) { RNA_pointer_create(NULL, &RNA_Function, func, &funcptr); args = PyTuple_New(rna_function_arg_count(func)); /* first arg is included in 'item' */ - if (is_static) { + if (is_staticmethod) { i = 0; } + else if (is_classmethod) { + PyTuple_SET_ITEM(args, 0, (PyObject *)py_class); + i = 1; + } else { PyTuple_SET_ITEM(args, 0, py_class_instance); i = 1; @@ -7236,7 +7244,7 @@ static int bpy_class_call(bContext *C, PointerRNA *ptr, FunctionRNA *func, Param if (err != 0) { ReportList *reports; /* alert the user, else they wont know unless they see the console. */ - if ((!is_static) && + if ((!is_staticmethod) && (!is_classmethod) && (ptr->data) && (RNA_struct_is_a(ptr->type, &RNA_Operator)) && (is_valid_wm == (CTX_wm_manager(C) != NULL))) -- cgit v1.2.3