[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [53199] trunk/blender/source/blender: Support for actual class methods in the RNA/bpy.

Lukas Toenne lukas.toenne at googlemail.com
Thu Dec 20 10:33:13 CET 2012


Revision: 53199
          http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-blender&revision=53199
Author:   lukastoenne
Date:     2012-12-20 09:33:12 +0000 (Thu, 20 Dec 2012)
Log Message:
-----------
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.

Modified Paths:
--------------
    trunk/blender/source/blender/makesrna/RNA_types.h
    trunk/blender/source/blender/makesrna/intern/makesrna.c
    trunk/blender/source/blender/makesrna/intern/rna_rna.c
    trunk/blender/source/blender/python/intern/bpy_rna.c

Modified: trunk/blender/source/blender/makesrna/RNA_types.h
===================================================================
--- trunk/blender/source/blender/makesrna/RNA_types.h	2012-12-20 08:54:37 UTC (rev 53198)
+++ trunk/blender/source/blender/makesrna/RNA_types.h	2012-12-20 09:33:12 UTC (rev 53199)
@@ -309,9 +309,10 @@
 
 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,
 

Modified: trunk/blender/source/blender/makesrna/intern/makesrna.c
===================================================================
--- trunk/blender/source/blender/makesrna/intern/makesrna.c	2012-12-20 08:54:37 UTC (rev 53198)
+++ trunk/blender/source/blender/makesrna/intern/makesrna.c	2012-12-20 09:33:12 UTC (rev 53199)
@@ -1989,6 +1989,10 @@
 		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 @@
 	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 @@
 		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 @@
 		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 @@
 			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 @@
 		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, ", ");

Modified: trunk/blender/source/blender/makesrna/intern/rna_rna.c
===================================================================
--- trunk/blender/source/blender/makesrna/intern/rna_rna.c	2012-12-20 08:54:37 UTC (rev 53198)
+++ trunk/blender/source/blender/makesrna/intern/rna_rna.c	2012-12-20 09:33:12 UTC (rev 53199)
@@ -939,6 +939,12 @@
 	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 @@
 	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)

Modified: trunk/blender/source/blender/python/intern/bpy_rna.c
===================================================================
--- trunk/blender/source/blender/python/intern/bpy_rna.c	2012-12-20 08:54:37 UTC (rev 53198)
+++ trunk/blender/source/blender/python/intern/bpy_rna.c	2012-12-20 09:33:12 UTC (rev 53199)
@@ -6035,7 +6035,7 @@
 	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 @@
 		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 @@
 	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 @@
 	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 @@
 	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 @@
 		}
 		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 @@
 				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 @@
 	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 @@
 
 	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 @@
 		}
 	}
 
-	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 @@
 	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)))




More information about the Bf-blender-cvs mailing list