diff options
Diffstat (limited to 'source/blender/python/intern/bpy_operator.c')
-rw-r--r-- | source/blender/python/intern/bpy_operator.c | 94 |
1 files changed, 71 insertions, 23 deletions
diff --git a/source/blender/python/intern/bpy_operator.c b/source/blender/python/intern/bpy_operator.c index eeab1fce4b2..70aa46c1302 100644 --- a/source/blender/python/intern/bpy_operator.c +++ b/source/blender/python/intern/bpy_operator.c @@ -32,6 +32,8 @@ #include "bpy_rna.h" /* for setting arg props only - pyrna_py_to_prop() */ #include "bpy_util.h" +#include "BLI_utildefines.h" + #include "RNA_enum_types.h" #include "WM_api.h" @@ -40,18 +42,26 @@ #include "MEM_guardedalloc.h" #include "BKE_report.h" -static PyObject *pyop_poll( PyObject * self, PyObject * args) +static PyObject *pyop_poll(PyObject *UNUSED(self), PyObject *args) { wmOperatorType *ot; char *opname; PyObject *context_dict= NULL; /* optional args */ PyObject *context_dict_back; + char *context_str= NULL; PyObject *ret; + int context= WM_OP_EXEC_DEFAULT; + // XXX Todo, work out a better solution for passing on context, could make a tuple from self and pack the name and Context into it... - bContext *C = BPy_GetContext(); + bContext *C= (bContext *)BPy_GetContext(); - if (!PyArg_ParseTuple(args, "s|O:_bpy.ops.poll", &opname, &context_dict)) + if(C==NULL) { + PyErr_SetString(PyExc_SystemError, "Context is None, cant poll any operators"); + return NULL; + } + + if (!PyArg_ParseTuple(args, "s|Os:_bpy.ops.poll", &opname, &context_dict, &context_str)) return NULL; ot= WM_operatortype_find(opname, TRUE); @@ -61,8 +71,22 @@ static PyObject *pyop_poll( PyObject * self, PyObject * args) return NULL; } - if(!PyDict_Check(context_dict)) + if(context_str) { + if(RNA_enum_value_from_id(operator_context_items, context_str, &context)==0) { + char *enum_str= BPy_enum_as_string(operator_context_items); + PyErr_Format(PyExc_TypeError, "Calling operator \"bpy.ops.%s.poll\" error, expected a string enum in (%.200s)", opname, enum_str); + MEM_freeN(enum_str); + return NULL; + } + } + + if(context_dict==NULL || context_dict==Py_None) { context_dict= NULL; + } + else if (!PyDict_Check(context_dict)) { + PyErr_Format(PyExc_TypeError, "Calling operator \"bpy.ops.%s.poll\" error, custom context expected a dict or None, got a %.200s", opname, Py_TYPE(context_dict)->tp_name); + return NULL; + } context_dict_back= CTX_py_dict_get(C); @@ -70,7 +94,7 @@ static PyObject *pyop_poll( PyObject * self, PyObject * args) Py_XINCREF(context_dict); /* so we done loose it */ /* main purpose of thsi function */ - ret= WM_operator_poll((bContext*)C, ot) ? Py_True : Py_False; + ret= WM_operator_poll_context((bContext*)C, ot, context) ? Py_True : Py_False; /* restore with original context dict, probably NULL but need this for nested operator calls */ Py_XDECREF(context_dict); @@ -80,7 +104,7 @@ static PyObject *pyop_poll( PyObject * self, PyObject * args) return ret; } -static PyObject *pyop_call( PyObject * self, PyObject * args) +static PyObject *pyop_call(PyObject *UNUSED(self), PyObject *args) { wmOperatorType *ot; int error_val = 0; @@ -97,7 +121,12 @@ static PyObject *pyop_call( PyObject * self, PyObject * args) int context= WM_OP_EXEC_DEFAULT; // XXX Todo, work out a better solution for passing on context, could make a tuple from self and pack the name and Context into it... - bContext *C = BPy_GetContext(); + bContext *C = (bContext *)BPy_GetContext(); + + if(C==NULL) { + PyErr_SetString(PyExc_SystemError, "Context is None, cant poll any operators"); + return NULL; + } if (!PyArg_ParseTuple(args, "sO|O!s:_bpy.ops.call", &opname, &context_dict, &PyDict_Type, &kw, &context_str)) return NULL; @@ -109,6 +138,11 @@ static PyObject *pyop_call( PyObject * self, PyObject * args) return NULL; } + if(!pyrna_write_check()) { + PyErr_Format(PyExc_SystemError, "Calling operator \"bpy.ops.%s\" error, can't modify blend data in this state (drawing/rendering)", opname); + return NULL; + } + if(context_str) { if(RNA_enum_value_from_id(operator_context_items, context_str, &context)==0) { char *enum_str= BPy_enum_as_string(operator_context_items); @@ -118,20 +152,28 @@ static PyObject *pyop_call( PyObject * self, PyObject * args) } } - if(!PyDict_Check(context_dict)) + if(context_dict==NULL || context_dict==Py_None) { context_dict= NULL; + } + else if (!PyDict_Check(context_dict)) { + PyErr_Format(PyExc_TypeError, "Calling operator \"bpy.ops.%s\" error, custom context expected a dict or None, got a %.200s", opname, Py_TYPE(context_dict)->tp_name); + return NULL; + } context_dict_back= CTX_py_dict_get(C); CTX_py_dict_set(C, (void *)context_dict); Py_XINCREF(context_dict); /* so we done loose it */ - if(WM_operator_poll((bContext*)C, ot) == FALSE) { - PyErr_Format( PyExc_SystemError, "Operator bpy.ops.%.200s.poll() failed, context is incorrect", opname); + if(WM_operator_poll_context((bContext*)C, ot, context) == FALSE) { + const char *msg= CTX_wm_operator_poll_msg_get(C); + PyErr_Format(PyExc_SystemError, "Operator bpy.ops.%.200s.poll() %.200s", opname, msg ? msg : "failed, context is incorrect"); + CTX_wm_operator_poll_msg_set(C, NULL); /* better set to NULL else it could be used again */ error_val= -1; } else { WM_operator_properties_create_ptr(&ptr, ot); + WM_operator_properties_sanitize(&ptr, 0); if(kw && PyDict_Size(kw)) error_val= pyrna_pydict_to_props(&ptr, kw, 0, "Converting py args to operator properties: "); @@ -145,7 +187,7 @@ static PyObject *pyop_call( PyObject * self, PyObject * args) operator_ret= WM_operator_call_py(C, ot, context, &ptr, reports); - if(BPy_reports_to_error(reports)) + if(BPy_reports_to_error(reports, FALSE)) error_val = -1; /* operator output is nice to have in the terminal/console too */ @@ -189,12 +231,18 @@ static PyObject *pyop_call( PyObject * self, PyObject * args) return NULL; } + /* when calling bpy.ops.wm.read_factory_settings() bpy.data's main pointer is freed by clear_globals(), + * further access will crash blender. setting context is not needed in this case, only calling because this + * function corrects bpy.data (internal Main pointer) */ + BPY_modules_update(C); + + /* return operator_ret as a bpy enum */ return pyrna_enum_bitfield_to_py(operator_return_items, operator_ret); } -static PyObject *pyop_as_string( PyObject * self, PyObject * args) +static PyObject *pyop_as_string(PyObject *UNUSED(self), PyObject *args) { wmOperatorType *ot; PointerRNA ptr; @@ -207,15 +255,20 @@ static PyObject *pyop_as_string( PyObject * self, PyObject * args) char *buf = NULL; PyObject *pybuf; - bContext *C = BPy_GetContext(); + bContext *C = (bContext *)BPy_GetContext(); + if(C==NULL) { + PyErr_SetString(PyExc_SystemError, "Context is None, cant get the string representation of this object."); + return NULL; + } + if (!PyArg_ParseTuple(args, "s|O!i:_bpy.ops.as_string", &opname, &PyDict_Type, &kw, &all_args)) return NULL; ot= WM_operatortype_find(opname, TRUE); if (ot == NULL) { - PyErr_Format( PyExc_SystemError, "_bpy.ops.as_string: operator \"%s\"could not be found", opname); + PyErr_Format(PyExc_SystemError, "_bpy.ops.as_string: operator \"%.200s\"could not be found", opname); return NULL; } @@ -246,7 +299,7 @@ static PyObject *pyop_as_string( PyObject * self, PyObject * args) return pybuf; } -static PyObject *pyop_dir(PyObject *self) +static PyObject *pyop_dir(PyObject *UNUSED(self)) { PyObject *list = PyList_New(0), *name; wmOperatorType *ot; @@ -260,7 +313,7 @@ static PyObject *pyop_dir(PyObject *self) return list; } -static PyObject *pyop_getrna(PyObject *self, PyObject *value) +static PyObject *pyop_getrna(PyObject *UNUSED(self), PyObject *value) { wmOperatorType *ot; PointerRNA ptr; @@ -282,6 +335,7 @@ static PyObject *pyop_getrna(PyObject *self, PyObject *value) /* XXX - should call WM_operator_properties_free */ WM_operator_properties_create_ptr(&ptr, ot); + WM_operator_properties_sanitize(&ptr, 0); pyrna= (BPy_StructRNA *)pyrna_struct_CreatePyObject(&ptr); @@ -311,14 +365,8 @@ static struct PyModuleDef bpy_ops_module = { PyObject *BPY_operator_module(void) { PyObject *submodule; - - submodule= PyModule_Create(&bpy_ops_module); - PyDict_SetItemString(PyImport_GetModuleDict(), bpy_ops_module.m_name, submodule); - /* INCREF since its its assumed that all these functions return the - * module with a new ref like PyDict_New, since they are passed to - * PyModule_AddObject which steals a ref */ - Py_INCREF(submodule); + submodule= PyModule_Create(&bpy_ops_module); return submodule; } |