[Bf-committers] [Bf-blender-cvs] SVN commit: /data/svn/bf-blender [18097] branches/blender2.5/blender/source /blender: python operators (in bpy_opwrapper.*)

joe joeedh at gmail.com
Sun Dec 28 00:15:33 CET 2008


awesome!

On Sat, Dec 27, 2008 at 7:52 AM, Campbell Barton <ideasman42 at gmail.com>wrote:

> Revision: 18097
>
> http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=18097
> Author:   campbellbarton
> Date:     2008-12-27 15:52:49 +0100 (Sat, 27 Dec 2008)
>
> Log Message:
> -----------
> python operators (in bpy_opwrapper.*)
> This means you can define an operator in python that is called from C or
> Python - like any other operator.
>
> Python functions for invoke and exec can be registered with an operator
> name.
>
> keywords are read from the python exec() function, then used to create
> operator properties. The default python values are used to set the property
> type and defaults.
>
> def exec(size=2.0, text="blah"): ...
>
> is equivalent to...
> prop = RNA_def_property(ot->srna, "size", PROP_FLOAT, PROP_NONE);
> RNA_def_property_float_default(prop, 2.0f);
>
> prop = RNA_def_property(ot->srna, "size", PROP_STRING, PROP_NONE);
> RNA_def_property_string_default(prop, "blah");
>
>
> TODO -
> * make use of events
> * return OPERATOR_CANCELLED/OPERATOR_FINISHED.. etc
> * add support for array args
> * more testing
>
> Modified Paths:
> --------------
>
>  branches/blender2.5/blender/source/blender/makesdna/DNA_windowmanager_types.h
>    branches/blender2.5/blender/source/blender/makesrna/RNA_define.h
>    branches/blender2.5/blender/source/blender/makesrna/intern/rna_define.c
>    branches/blender2.5/blender/source/blender/python/intern/bpy_operator.c
>    branches/blender2.5/blender/source/blender/python/intern/bpy_rna.c
>    branches/blender2.5/blender/source/blender/python/intern/bpy_rna.h
>    branches/blender2.5/blender/source/blender/windowmanager/WM_api.h
>
>  branches/blender2.5/blender/source/blender/windowmanager/intern/wm_operators.c
>
> Added Paths:
> -----------
>    branches/blender2.5/blender/source/blender/python/intern/bpy_opwrapper.c
>    branches/blender2.5/blender/source/blender/python/intern/bpy_opwrapper.h
>
> Modified:
> branches/blender2.5/blender/source/blender/makesdna/DNA_windowmanager_types.h
> ===================================================================
> ---
> branches/blender2.5/blender/source/blender/makesdna/DNA_windowmanager_types.h
>       2008-12-27 11:44:00 UTC (rev 18096)
> +++
> branches/blender2.5/blender/source/blender/makesdna/DNA_windowmanager_types.h
>       2008-12-27 14:52:49 UTC (rev 18097)
> @@ -137,6 +137,10 @@
>
>        short flag;
>
> +       /* only used for operators defined with python
> +        * use to store pointers to python functions */
> +       void *pyop_data;
> +
>  } wmOperatorType;
>
>  #define OP_MAX_TYPENAME        64
>
> Modified: branches/blender2.5/blender/source/blender/makesrna/RNA_define.h
> ===================================================================
> --- branches/blender2.5/blender/source/blender/makesrna/RNA_define.h
>  2008-12-27 11:44:00 UTC (rev 18096)
> +++ branches/blender2.5/blender/source/blender/makesrna/RNA_define.h
>  2008-12-27 14:52:49 UTC (rev 18097)
> @@ -47,7 +47,7 @@
>  void RNA_def_struct_funcs(StructRNA *srna, const char *notify, const char
> *refine);
>  void RNA_def_struct_identifier(StructRNA *srna, const char *identifier);
>  void RNA_def_struct_ui_text(StructRNA *srna, const char *name, const char
> *description);
> -
> +void RNA_struct_free(BlenderRNA *brna, StructRNA *srna);
>  /* Property */
>
>  PropertyRNA *RNA_def_property(StructRNA *srna, const char *identifier, int
> type, int subtype);
>
> Modified:
> branches/blender2.5/blender/source/blender/makesrna/intern/rna_define.c
> ===================================================================
> --- branches/blender2.5/blender/source/blender/makesrna/intern/rna_define.c
>     2008-12-27 11:44:00 UTC (rev 18096)
> +++ branches/blender2.5/blender/source/blender/makesrna/intern/rna_define.c
>     2008-12-27 14:52:49 UTC (rev 18097)
> @@ -549,6 +549,12 @@
>        srna->description= description;
>  }
>
> +void RNA_struct_free(BlenderRNA *brna, StructRNA *srna)
> +{
> +       rna_freelistN(&srna->properties);
> +       rna_freelinkN(&brna->structs, srna);
> +}
> +
>  /* Property Definition */
>
>  PropertyRNA *RNA_def_property(StructRNA *srna, const char *identifier, int
> type, int subtype)
>
> Modified:
> branches/blender2.5/blender/source/blender/python/intern/bpy_operator.c
> ===================================================================
> --- branches/blender2.5/blender/source/blender/python/intern/bpy_operator.c
>     2008-12-27 11:44:00 UTC (rev 18096)
> +++ branches/blender2.5/blender/source/blender/python/intern/bpy_operator.c
>     2008-12-27 14:52:49 UTC (rev 18097)
> @@ -24,11 +24,13 @@
>  */
>
>  #include "bpy_operator.h"
> +#include "bpy_opwrapper.h"
>  #include "bpy_rna.h" /* for setting arg props only - pyrna_py_to_prop() */
>  #include "bpy_compat.h"
>
>  //#include "blendef.h"
>  #include "BLI_dynstr.h"
> +
>  #include "WM_api.h"
>  #include "WM_types.h"
>
> @@ -40,6 +42,20 @@
>  /* floats bigger then this are displayed as inf in the docstrings */
>  #define MAXFLOAT_DOC 10000000
>
> +#if 0
> +void PyObSpit(char *name, PyObject *var) {
> +       fprintf(stderr, "<%s> : ", name);
> +       if (var==NULL) {
> +               fprintf(stderr, "<NIL>");
> +       }
> +       else {
> +               PyObject_Print(var, stderr, 0);
> +       }
> +       fprintf(stderr, "\n");
> +}
> +#endif
> +
> +
>  static int pyop_func_compare( BPy_OperatorFunc * a, BPy_OperatorFunc * b )
>  {
>        return (strcmp(a->name, b->name)==0) ? 0 : -1;
> @@ -56,6 +72,7 @@
>        return PyUnicode_FromFormat( "[BPy_OperatorFunc \"%s\"]",
> self->name);
>  }
>
> +
>  //---------------getattr--------------------------------------------
>  static PyObject *pyop_base_getattro( BPy_OperatorBase * self, PyObject
> *pyname )
>  {
> @@ -73,7 +90,17 @@
>                        PyList_Append(ret, item);
>                        Py_DECREF(item);
>                }
> -       } else {
> +
> +               item = PyUnicode_FromString("add");
> PyList_Append(ret, item); Py_DECREF(item);
> +               item = PyUnicode_FromString("remove");  PyList_Append(ret,
> item); Py_DECREF(item);
> +       }
> +       else if ( strcmp( name, "add" ) == 0 ) {
> +               ret= PYOP_wrap_add_func();
> +       }
> +       else if ( strcmp( name, "remove" ) == 0 ) {
> +               ret= PYOP_wrap_remove_func();
> +       }
> +       else {
>                ot = WM_operatortype_find(name);
>
>                if (ot) {
>
> Added:
> branches/blender2.5/blender/source/blender/python/intern/bpy_opwrapper.c
> ===================================================================
> ---
> branches/blender2.5/blender/source/blender/python/intern/bpy_opwrapper.c
>                        (rev 0)
> +++
> branches/blender2.5/blender/source/blender/python/intern/bpy_opwrapper.c
>  2008-12-27 14:52:49 UTC (rev 18097)
> @@ -0,0 +1,252 @@
> +
> +/**
> + * $Id$
> + *
> + * ***** BEGIN GPL LICENSE BLOCK *****
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; either version 2
> + * of the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software Foundation,
> + * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
> + *
> + * Contributor(s): Campbell Barton
> + *
> + * ***** END GPL LICENSE BLOCK *****
> + */
> +
> +
> +#include "bpy_opwrapper.h"
> +#include "BLI_listbase.h"
> +#include "BKE_context.h"
> +#include "DNA_windowmanager_types.h"
> +#include "MEM_guardedalloc.h"
> +#include "WM_api.h"
> +#include "WM_types.h"
> +#include "ED_screen.h"
> +
> +#include "RNA_define.h"
> +
> +#include "bpy_rna.h"
> +#include "bpy_compat.h"
> +
> +typedef struct PyOperatorType {
> +       void *next, *prev;
> +       char idname[OP_MAX_TYPENAME];
> +       char name[OP_MAX_TYPENAME];
> +       PyObject *py_invoke;
> +       PyObject *py_exec;
> +} PyOperatorType;
> +
> +static void pyop_kwargs_from_operator(PyObject *dict, wmOperator *op)
> +{
> +       PyObject *item;
> +       PropertyRNA *prop, *iterprop;
> +       CollectionPropertyIterator iter;
> +       const char *arg_name;
> +
> +       iterprop= RNA_struct_iterator_property(op->ptr);
> +       RNA_property_collection_begin(op->ptr, iterprop, &iter);
> +
> +       for(; iter.valid; RNA_property_collection_next(&iter)) {
> +               prop= iter.ptr.data;
> +
> +               arg_name= RNA_property_identifier(&iter.ptr, prop);
> +
> +               if (strcmp(arg_name, "rna_type")==0) continue;
> +
> +               item = pyrna_prop_to_py(&iter.ptr, prop);
> +               PyDict_SetItemString(dict, arg_name, item);
> +               Py_DECREF(item);
> +       }
> +
> +       RNA_property_collection_end(&iter);
> +
> +}
> +
> +static int PYTHON_OT_exec(bContext *C, wmOperator *op)
> +{
> +       PyOperatorType *pyot = op->type->pyop_data;
> +       PyObject *ret, *args= PyTuple_New(0), *kw= PyDict_New();
> +
> +       pyop_kwargs_from_operator(kw, op);
> +
> +       ret = PyObject_Call(pyot->py_exec, args, kw);
> +
> +       Py_DECREF(args);
> +       Py_DECREF(kw);
> +
> +       return OPERATOR_FINISHED;
> +}
> +
> +static int PYTHON_OT_invoke(bContext *C, wmOperator *op, wmEvent *event)
> +{
> +       PyOperatorType *pyot = op->type->pyop_data;
> +       PyObject *ret, *args= PyTuple_New(0), *kw= PyDict_New();
> +
> +       pyop_kwargs_from_operator(kw, op);
> +
> +       ret = PyObject_Call(pyot->py_invoke, args, kw);
> +
> +       Py_DECREF(args);
> +       Py_DECREF(kw);
> +
> +       return OPERATOR_FINISHED;
> +}
> +
> +void PYTHON_OT_wrapper(wmOperatorType *ot, void *userdata)
> +{
> +       PyOperatorType *pyot = (PyOperatorType *)userdata;
> +
> +       /* identifiers */
> +       ot->name= pyot->name;
> +       ot->idname= pyot->idname;
> +
> +       /* api callbacks */
> +       if (pyot->py_invoke != Py_None)
> +               ot->invoke= PYTHON_OT_invoke;
> +
> +       ot->exec= PYTHON_OT_exec;
> +
> +       ot->poll= ED_operator_screenactive; /* how should this work?? */
> +
> +       ot->pyop_data= userdata;
> +
> +       /* inspect function keyword args to get properties */
> +       {
> +               PropertyRNA *prop;
> +
> +               PyObject *var_names=
> PyObject_GetAttrString(PyFunction_GET_CODE(pyot->py_exec), "co_varnames");
> +               PyObject *var_vals =
> PyFunction_GET_DEFAULTS(pyot->py_exec);
> +               PyObject *py_val, *py_name;
> +               int i;
> +               char *name;
> +
> +               if (PyTuple_Size(var_names) != PyTuple_Size(var_vals)) {
> +                       printf("All args must be keywords");
> +               }
> +
> +               for(i=0; i<PyTuple_Size(var_names); i++) {
> +                       py_name = PyTuple_GetItem(var_names, i);
> +                       name = _PyUnicode_AsString(py_name);
> +                       py_val = PyTuple_GetItem(var_vals, i);
> +
> +                       if (PyBool_Check(py_val)) {
> +                               prop = RNA_def_property(ot->srna, name,
> PROP_BOOLEAN, PROP_NONE);
> +                               RNA_def_property_boolean_default(prop,
> PyObject_IsTrue(py_val));
> +                       }
> +                       else if (PyLong_Check(py_val)) {
> +                               prop = RNA_def_property(ot->srna, name,
> PROP_INT, PROP_NONE);
> +                               RNA_def_property_int_default(prop,
> (int)PyLong_AsSsize_t(py_val));
> +                       }
> +                       else if (PyFloat_Check(py_val)) {
> +                               prop = RNA_def_property(ot->srna, name,
> PROP_FLOAT, PROP_NONE);
> +                               RNA_def_property_float_default(prop,
> (float)PyFloat_AsDouble(py_val));
> +                       }
> +                       else if (PyUnicode_Check(py_val)) {
> +                               /* WARNING - holding a reference to the
> string from py_val is
> +                                * not ideal since we rely on python
> keeping it,
> +                                * however we're also keeping a reference
> to this function
> +                                * so it should be OK!. just be careful
> with changes */
> +                               prop = RNA_def_property(ot->srna, name,
> PROP_STRING, PROP_NONE);
> +                               RNA_def_property_string_default(prop,
> _PyUnicode_AsString(py_val));
> +                       }
> +                       else {
> +                               printf("error, python function arg \"%s\"
> was not a bool, int, float or string type\n", name);
> +                       }
> +               }
> +       }
> +
> +}
> +
> +/* pyOperators - Operators defined IN Python */
> +static PyObject *pyop_add(PyObject *self, PyObject *args)
> +{
> +       PyOperatorType *pyot;
> +
> +       char *idname= NULL;
> +       char *name= NULL;
> +       PyObject *invoke= NULL;
> +       PyObject *exec= NULL;
> +
> +       if (!PyArg_ParseTuple(args, "ssOO", &idname, &name, &invoke,
> &exec))
> +               PyErr_SetString( PyExc_AttributeError, "expected 2 strings
> and 2 function objects");
> +               return NULL;
> +
> +       if (WM_operatortype_find(idname)) {
> +               PyErr_Format( PyExc_AttributeError, "First argument \"%s\"
> operator alredy exists with this name", idname);
> +               return NULL;
> +       }
> +
> +       if (((PyFunction_Check(invoke) || invoke==Py_None) &&
> PyFunction_Check(exec)) == 0) {
> +               PyErr_SetString( PyExc_AttributeError, "the 2nd arg must be
> a function or None, the secons must be a function");
> +               return NULL;
> +       }
> +
> +       pyot= MEM_callocN(sizeof(PyOperatorType), "PyOperatorType");
> +
> +       strcpy(pyot->idname, idname);
> +       strcpy(pyot->name, name);
> +       pyot->py_invoke= invoke;
> +       pyot->py_exec= exec;
> +       Py_INCREF(invoke);
> +       Py_INCREF(exec);
> +
> +       WM_operatortype_append_ptr(PYTHON_OT_wrapper, pyot);
> +
> +       Py_RETURN_NONE;
> +}
> +
> +static PyObject *pyop_remove(PyObject *self, PyObject *args)
> +{
> +       char *idname= NULL;
> +       wmOperatorType *ot;
> +       PyOperatorType *pyot;
> +
> +       if (!PyArg_ParseTuple(args, "s", &idname))
> +               return NULL;
> +
> +       if (!(ot= WM_operatortype_find(idname))) {
>
> @@ Diff output truncated at 10240 characters. @@
>
> _______________________________________________
> Bf-blender-cvs mailing list
> Bf-blender-cvs at blender.org
> http://lists.blender.org/mailman/listinfo/bf-blender-cvs
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.blender.org/pipermail/bf-committers/attachments/20081227/251f0695/attachment-0001.htm 


More information about the Bf-committers mailing list