[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [19314] branches/blender2.5/blender/source /blender: 2.5 PyAPI
Campbell Barton
ideasman42 at gmail.com
Mon Mar 16 16:54:43 CET 2009
Revision: 19314
http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=19314
Author: campbellbarton
Date: 2009-03-16 16:54:43 +0100 (Mon, 16 Mar 2009)
Log Message:
-----------
2.5 PyAPI
Support for subclassing blenders operator, to be registered as a new operator.
Still need to...
* add constants like Operator.FINISHED
* wrap context (with rna?)
* poll() cant work right now because there is no way to access the operatorType that holds the python class.
* ?\239?\187?\191Only float, int and bool properties can be added so far.
working example operator.
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/WinterCamp/TechnicalDesign#Operator_Example_Code
Modified Paths:
--------------
branches/blender2.5/blender/source/blender/python/intern/bpy_interface.c
branches/blender2.5/blender/source/blender/python/intern/bpy_operator.c
branches/blender2.5/blender/source/blender/python/intern/bpy_opwrapper.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/intern/wm_event_system.c
Modified: branches/blender2.5/blender/source/blender/python/intern/bpy_interface.c
===================================================================
--- branches/blender2.5/blender/source/blender/python/intern/bpy_interface.c 2009-03-16 14:52:30 UTC (rev 19313)
+++ branches/blender2.5/blender/source/blender/python/intern/bpy_interface.c 2009-03-16 15:54:43 UTC (rev 19314)
@@ -57,6 +57,22 @@
PyDict_SetItemString( dict, "__bpy_context__", item );
Py_DECREF(item);
+
+ // XXX - put somewhere more logical
+ {
+ PyMethodDef *ml;
+ static PyMethodDef bpy_prop_meths[] = {
+ {"FloatProperty", BPy_FloatProperty, METH_VARARGS|METH_KEYWORDS, ""},
+ {"IntProperty", BPy_IntProperty, METH_VARARGS|METH_KEYWORDS, ""},
+ {"BoolProperty", BPy_BoolProperty, METH_VARARGS|METH_KEYWORDS, ""},
+ {NULL, NULL, 0, NULL}
+ };
+
+ for(ml = &bpy_prop_meths; ml->ml_name; ml++) {
+ PyDict_SetItemString( dict, ml->ml_name, PyCFunction_New(ml, NULL));
+ }
+ }
+
return dict;
}
Modified: branches/blender2.5/blender/source/blender/python/intern/bpy_operator.c
===================================================================
--- branches/blender2.5/blender/source/blender/python/intern/bpy_operator.c 2009-03-16 14:52:30 UTC (rev 19313)
+++ branches/blender2.5/blender/source/blender/python/intern/bpy_operator.c 2009-03-16 15:54:43 UTC (rev 19314)
@@ -111,7 +111,7 @@
static struct PyMethodDef pyop_base_methods[] = {
{"__dir__", (PyCFunction)pyop_base_dir, METH_NOARGS, ""},
{"add", (PyCFunction)PYOP_wrap_add, METH_VARARGS, ""},
- {"remove", (PyCFunction)PYOP_wrap_remove, METH_VARARGS, ""},
+ {"remove", (PyCFunction)PYOP_wrap_remove, METH_O, ""},
{NULL, NULL, 0, NULL}
};
Modified: branches/blender2.5/blender/source/blender/python/intern/bpy_opwrapper.c
===================================================================
--- branches/blender2.5/blender/source/blender/python/intern/bpy_opwrapper.c 2009-03-16 14:52:30 UTC (rev 19313)
+++ branches/blender2.5/blender/source/blender/python/intern/bpy_opwrapper.c 2009-03-16 15:54:43 UTC (rev 19314)
@@ -45,39 +45,9 @@
char idname[OP_MAX_TYPENAME];
char name[OP_MAX_TYPENAME];
char description[OP_MAX_TYPENAME]; // XXX should be longer?
- PyObject *py_invoke;
- PyObject *py_exec;
+ PyObject *py_class;
} PyOperatorType;
-static PyObject *pyop_kwargs_from_operator(wmOperator *op)
-{
- PyObject *dict = PyDict_New();
- 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(op->ptr, prop);
- PyDict_SetItemString(dict, arg_name, item);
- Py_DECREF(item);
- }
-
- RNA_property_collection_end(&iter);
-
- return dict;
-}
-
-
static PyObject *pyop_dict_from_event(wmEvent *event)
{
PyObject *dict= PyDict_New();
@@ -191,33 +161,6 @@
{NULL, 0}
};
-/* exec only - no user input */
-static int PYTHON_OT_exec(bContext *C, wmOperator *op)
-{
- PyOperatorType *pyot = op->type->pyop_data;
- PyObject *args= PyTuple_New(0);
- PyObject *kw= pyop_kwargs_from_operator(op);
- PyObject *ret;
- int ret_flag;
-
- ret = PyObject_Call(pyot->py_exec, args, kw);
-
- if (ret == NULL) {
- pyop_error_report(op->reports);
- }
- else {
- if (BPY_flag_from_seq(pyop_ret_flags, ret, &ret_flag) == -1) {
- /* the returned value could not be converted into a flag */
- pyop_error_report(op->reports);
- }
- }
-
- Py_DECREF(args);
- Py_DECREF(kw);
-
- return ret_flag;
-}
-
/* This invoke function can take events and
*
* It is up to the pyot->py_invoke() python func to run pyot->py_exec()
@@ -233,26 +176,93 @@
* op_exec(**prop_defs)
*
* when there is no invoke function, C calls exec and sets the props.
+ * python class instance is stored in op->customdata so exec() can access
*/
-static int PYTHON_OT_invoke(bContext *C, wmOperator *op, wmEvent *event)
+
+
+#define PYOP_EXEC 1
+#define PYOP_INVOKE 2
+#define PYOP_POLL 3
+
+static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *event)
{
PyOperatorType *pyot = op->type->pyop_data;
- PyObject *args= PyTuple_New(2);
- PyObject *ret;
- int ret_flag;
+ PyObject *args;
+ PyObject *ret= NULL, *py_class_instance, *item;
+ int ret_flag= (mode==PYOP_POLL ? 0:OPERATOR_CANCELLED);
+
+ args = PyTuple_New(1);
+ PyTuple_SET_ITEM(args, 0, PyObject_GetAttrString(pyot->py_class, "__rna__")); // need to use an rna instance as the first arg
+ py_class_instance = PyObject_Call(pyot->py_class, args, NULL);
+ Py_DECREF(args);
+
+ if (py_class_instance) { /* Initializing the class worked, now run its invoke function */
+
+
+ /* Assign instance attributes from operator properties */
+ {
+ PropertyRNA *prop, *iterprop;
+ CollectionPropertyIterator iter;
+ const char *arg_name;
- PyTuple_SET_ITEM(args, 0, pyop_dict_from_event(event));
- PyTuple_SET_ITEM(args, 1, pyop_kwargs_from_operator(op));
+ iterprop= RNA_struct_iterator_property(op->ptr);
+ RNA_property_collection_begin(op->ptr, iterprop, &iter);
- ret = PyObject_Call(pyot->py_invoke, args, NULL);
+ 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(op->ptr, prop);
+ PyObject_SetAttrString(py_class_instance, arg_name, item);
+ Py_DECREF(item);
+ }
+
+ RNA_property_collection_end(&iter);
+ }
+
+
+ if (mode==PYOP_INVOKE) {
+ item= PyObject_GetAttrString(pyot->py_class, "invoke");
+ args = PyTuple_New(2);
+ PyTuple_SET_ITEM(args, 1, pyop_dict_from_event(event));
+ }
+ else if (mode==PYOP_EXEC) {
+ item= PyObject_GetAttrString(pyot->py_class, "exec");
+ args = PyTuple_New(1);
+ }
+ else if (mode==PYOP_POLL) {
+ item= PyObject_GetAttrString(pyot->py_class, "poll");
+ args = PyTuple_New(2);
+ //XXX Todo - wrap context in a useful way, None for now.
+ PyTuple_SET_ITEM(args, 1, Py_None);
+ }
+ PyTuple_SET_ITEM(args, 0, py_class_instance);
+
+ ret = PyObject_Call(item, args, NULL);
+
+ Py_DECREF(args);
+ Py_DECREF(item);
+ }
+
if (ret == NULL) {
pyop_error_report(op->reports);
}
else {
- if (BPY_flag_from_seq(pyop_ret_flags, ret, &ret_flag) == -1) {
+ if (mode==PYOP_POLL) {
+ if (PyBool_Check(ret) == 0) {
+ PyErr_SetString(PyExc_ValueError, "Python poll function return value ");
+ pyop_error_report(op->reports);
+ }
+ else {
+ ret_flag= ret==Py_True ? 1:0;
+ }
+
+ } else if (BPY_flag_from_seq(pyop_ret_flags, ret, &ret_flag) == -1) {
/* the returned value could not be converted into a flag */
pyop_error_report(op->reports);
+
}
/* there is no need to copy the py keyword dict modified by
* pyot->py_invoke(), back to the operator props since they are just
@@ -261,131 +271,234 @@
* If we ever want to do this and use the props again,
* it can be done with - PYOP_props_from_dict(op->ptr, kw)
*/
+
+ Py_DECREF(ret);
}
-
+ return ret_flag;
+}
- Py_DECREF(args); /* also decref's kw */
+static int PYTHON_OT_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+ return PYTHON_OT_generic(PYOP_INVOKE, C, op, event);
+}
- return ret_flag;
+static int PYTHON_OT_exec(bContext *C, wmOperator *op)
+{
+ return PYTHON_OT_generic(PYOP_EXEC, C, op, NULL);
}
+static int PYTHON_OT_poll(bContext *C)
+{
+ // XXX TODO - no way to get the operator type (and therefor class) from the poll function.
+ //return PYTHON_OT_generic(PYOP_POLL, C, NULL, NULL);
+ return 1;
+}
+
void PYTHON_OT_wrapper(wmOperatorType *ot, void *userdata)
{
PyOperatorType *pyot = (PyOperatorType *)userdata;
+ PyObject *py_class = pyot->py_class;
/* identifiers */
ot->name= pyot->name;
ot->idname= pyot->idname;
ot->description= pyot->description;
- /* api callbacks */
- if (pyot->py_invoke != Py_None)
+ /* api callbacks, detailed checks dont on adding */
+ if (PyObject_HasAttrString(py_class, "invoke"))
ot->invoke= PYTHON_OT_invoke;
+ if (PyObject_HasAttrString(py_class, "exec"))
+ ot->exec= PYTHON_OT_exec;
+ if (PyObject_HasAttrString(py_class, "poll"))
+ ot->poll= PYTHON_OT_poll;
- ot->exec= PYTHON_OT_exec;
-
- ot->poll= ED_operator_screenactive; /* how should this work?? */
- /* ot->flag= OPTYPE_REGISTER; */
-
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;
+ // TODO - set properties
+ PyObject *props, *item;
+
+
+ if ((props=PyObject_GetAttrString(py_class, "properties"))) {
+ PyObject *dummy_args = PyTuple_New(0);
+
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));
+
+ for(i=0; i<PyList_Size(props); i++) {
+ item = PyList_GET_ITEM(props, i);
+
+ PyObject *py_func_ptr, *py_kw, *py_srna_cobject, *py_ret;
+
+ if (PyArg_ParseTuple(item, "O!O!", &PyCObject_Type, &py_func_ptr, &PyDict_Type, &py_kw)) {
+
+ PyObject *(*pyfunc)(PyObject *, PyObject *, PyObject *);
+ pyfunc = PyCObject_AsVoidPtr(py_func_ptr);
+ py_srna_cobject = PyCObject_FromVoidPtr(ot->srna, NULL);
+
+ py_ret = pyfunc(py_srna_cobject, dummy_args, py_kw);
+ if (py_ret) {
+ Py_DECREF(py_ret);
+ } else {
+ PyErr_Print();
+ PyErr_Clear();
+ }
+ Py_DECREF(py_srna_cobject);
+
+ } else {
+ /* cant return NULL from here */ // XXX a bit ugly
+ PyErr_Print();
+ PyErr_Clear();
}
- 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)) {
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list