[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [59536] trunk/blender/source/blender: This commit adds optional parameters for pyfunc implementations of RNA API (i.e.

Bastien Montagne montagne29 at wanadoo.fr
Mon Aug 26 23:11:52 CEST 2013


Revision: 59536
          http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-blender&revision=59536
Author:   mont29
Date:     2013-08-26 21:11:52 +0000 (Mon, 26 Aug 2013)
Log Message:
-----------
This commit adds optional parameters for pyfunc implementations of RNA API (i.e. callbacks, e.g. draw functions of panels, uiLists, or exec/poll/etc. of operators). Thanks to Brecht for he review!

Any parameter after the first flagged with PROP_PYFUNC_OPTIONAL will be considered as optional, hence the python code does not have to define/use it. This will ease API evolutions by avoiding to break existing code when adding non-essential new parameters.

Note: this will need some update to API doc generation, patch is ready, will have it reviewed by Campbell asap.

Modified Paths:
--------------
    trunk/blender/source/blender/makesrna/RNA_types.h
    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	2013-08-26 20:29:36 UTC (rev 59535)
+++ trunk/blender/source/blender/makesrna/RNA_types.h	2013-08-26 21:11:52 UTC (rev 59536)
@@ -146,7 +146,7 @@
 } PropertySubType;
 
 /* Make sure enums are updated with thses */
-/* HIGHEST FLAG IN USE: 1 << 29 */
+/* HIGHEST FLAG IN USE: 1 << 30 */
 typedef enum PropertyFlag {
 	/* editable means the property is editable in the user
 	 * interface, properties are editable by default except
@@ -172,10 +172,16 @@
 	/* do not write in presets */
 	PROP_SKIP_SAVE = (1 << 28),
 
-	/* function paramater flags */
+	/* function parameter flags */
 	PROP_REQUIRED = (1 << 2),
 	PROP_OUTPUT = (1 << 3),
 	PROP_RNAPTR = (1 << 11),
+	/* This allows for non-breaking API updates, when adding non-critical new parameter to a callback function.
+	 * This way, old py code defining funcs without that parameter would still work.
+	 * WARNING: any parameter after the first PYFUNC_OPTIONAL one will be considered as optional!
+	 * NOTE: only for input parameters!
+	 */
+	PROP_PYFUNC_OPTIONAL = (1 << 30),
 	/* registering */
 	PROP_REGISTER = (1 << 4),
 	PROP_REGISTER_OPTIONAL = (1 << 4) | (1 << 5),

Modified: trunk/blender/source/blender/python/intern/bpy_rna.c
===================================================================
--- trunk/blender/source/blender/python/intern/bpy_rna.c	2013-08-26 20:29:36 UTC (rev 59535)
+++ trunk/blender/source/blender/python/intern/bpy_rna.c	2013-08-26 21:11:52 UTC (rev 59536)
@@ -6875,7 +6875,7 @@
 
 /*-------------------- Type Registration ------------------------*/
 
-static int rna_function_arg_count(FunctionRNA *func)
+static int rna_function_arg_count(FunctionRNA *func, int *min_count)
 {
 	const ListBase *lb = RNA_function_defined_parameters(func);
 	PropertyRNA *parm;
@@ -6883,13 +6883,23 @@
 	int flag = RNA_function_flag(func);
 	int is_staticmethod = (flag & FUNC_NO_SELF) && !(flag & FUNC_USE_SELF_TYPE);
 	int count = is_staticmethod ? 0 : 1;
+	bool done_min_count = false;
 
 	for (link = lb->first; link; link = link->next) {
 		parm = (PropertyRNA *)link;
-		if (!(RNA_property_flag(parm) & PROP_OUTPUT))
+		if (!(RNA_property_flag(parm) & PROP_OUTPUT)) {
+			if (!done_min_count && (RNA_property_flag(parm) & PROP_PYFUNC_OPTIONAL)) {
+				/* From now on, following parameters are optional in py func */
+				if (min_count)
+					*min_count = count;
+				done_min_count = true;
+			}
 			count++;
+		}
 	}
 
+	if (!done_min_count && min_count)
+		*min_count = count;
 	return count;
 }
 
@@ -6904,7 +6914,7 @@
 	PyObject *py_class = (PyObject *)py_data;
 	PyObject *base_class = RNA_struct_py_type_get(srna);
 	PyObject *item;
-	int i, flag, is_staticmethod, arg_count, func_arg_count;
+	int i, flag, is_staticmethod, arg_count, func_arg_count, func_arg_min_count = 0;
 	const char *py_class_name = ((PyTypeObject *)py_class)->tp_name;  /* __name__ */
 
 	if (srna_base) {
@@ -6968,7 +6978,7 @@
 				}
 			}
 
-			func_arg_count = rna_function_arg_count(func);
+			func_arg_count = rna_function_arg_count(func, &func_arg_min_count);
 
 			if (func_arg_count >= 0) { /* -1 if we don't care*/
 				arg_count = ((PyCodeObject *)PyFunction_GET_CODE(item))->co_argcount;
@@ -6976,14 +6986,25 @@
 				/* note, the number of args we check for and the number of args we give to
 				 * @staticmethods are different (quirk of python),
 				 * this is why rna_function_arg_count() doesn't return the value -1*/
-				if (is_staticmethod)
+				if (is_staticmethod) {
 					func_arg_count++;
+					func_arg_min_count++;
+				}
 
-				if (arg_count != func_arg_count) {
-					PyErr_Format(PyExc_ValueError,
-					             "expected %.200s, %.200s class \"%.200s\" function to have %d args, found %d",
-					             class_type, py_class_name, RNA_function_identifier(func),
-					             func_arg_count, arg_count);
+				if (arg_count < func_arg_min_count || arg_count > func_arg_count) {
+					if (func_arg_min_count != func_arg_count) {
+						PyErr_Format(PyExc_ValueError,
+						             "expected %.200s, %.200s class \"%.200s\" function to have between %d and %d "
+						             "args, found %d",
+						             class_type, py_class_name, RNA_function_identifier(func),
+						             func_arg_count, func_arg_min_count, arg_count);
+					}
+					else {
+						PyErr_Format(PyExc_ValueError,
+						             "expected %.200s, %.200s class \"%.200s\" function to have %d args, found %d",
+						             class_type, py_class_name, RNA_function_identifier(func),
+						             func_arg_count, arg_count);
+					}
 					return -1;
 				}
 			}
@@ -7063,7 +7084,7 @@
 	PropertyRNA *parm;
 	ParameterIterator iter;
 	PointerRNA funcptr;
-	int err = 0, i, ret_len = 0;
+	int err = 0, i, ret_len = 0, arg_count;
 	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);
@@ -7198,8 +7219,16 @@
 		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_staticmethod) {
+				arg_count = ((PyCodeObject *)PyFunction_GET_CODE(((PyMethodObject *)item)->im_func))->co_argcount - 1;
+			}
+			else {
+				arg_count = ((PyCodeObject *)PyFunction_GET_CODE(item))->co_argcount;
+			}
+//			args = PyTuple_New(rna_function_arg_count(func)); /* first arg is included in 'item' */
+			args = PyTuple_New(arg_count); /* first arg is included in 'item' */
 
+
 			if (is_staticmethod) {
 				i = 0;
 			}
@@ -7230,9 +7259,11 @@
 					continue;
 				}
 
-				parmitem = pyrna_param_to_py(&funcptr, parm, iter.data);
-				PyTuple_SET_ITEM(args, i, parmitem);
-				i++;
+				if (i < arg_count) {
+					parmitem = pyrna_param_to_py(&funcptr, parm, iter.data);
+					PyTuple_SET_ITEM(args, i, parmitem);
+					i++;
+				}
 			}
 
 #ifdef USE_PEDANTIC_WRITE




More information about the Bf-blender-cvs mailing list