Blender  V2.59
bpy_operator.c
Go to the documentation of this file.
00001 
00002 /*
00003  * $Id: bpy_operator.c 39293 2011-08-11 06:06:17Z campbellbarton $
00004  *
00005  * ***** BEGIN GPL LICENSE BLOCK *****
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software Foundation,
00019  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  * Contributor(s): Campbell Barton
00022  *
00023  * ***** END GPL LICENSE BLOCK *****
00024  */
00025 
00031 /* Note, this module is not to be used directly by the user.
00032  * Internally its exposed as '_bpy.ops', which provides functions for 'bpy.ops', a python package.
00033  * */
00034 
00035 #include <Python.h>
00036 
00037 #include "RNA_types.h"
00038 
00039 #include "BPY_extern.h"
00040 #include "bpy_operator.h"
00041 #include "bpy_operator_wrap.h"
00042 #include "bpy_rna.h" /* for setting arg props only - pyrna_py_to_prop() */
00043 #include "bpy_util.h"
00044 #include "../generic/bpy_internal_import.h"
00045 
00046 #include "BLI_utildefines.h"
00047 
00048 #include "RNA_access.h"
00049 #include "RNA_enum_types.h"
00050 
00051 #include "WM_api.h"
00052 #include "WM_types.h"
00053 
00054 #include "MEM_guardedalloc.h"
00055 
00056 #include "BLI_ghash.h"
00057 
00058 #include "BKE_report.h"
00059 #include "BKE_context.h"
00060 
00061 /* so operators called can spawn threads which aquire the GIL */
00062 #define BPY_RELEASE_GIL
00063 
00064 
00065 static PyObject *pyop_poll(PyObject *UNUSED(self), PyObject *args)
00066 {
00067         wmOperatorType *ot;
00068         char            *opname;
00069         PyObject        *context_dict= NULL; /* optional args */
00070         PyObject        *context_dict_back;
00071         char            *context_str= NULL;
00072         PyObject        *ret;
00073 
00074         int context= WM_OP_EXEC_DEFAULT;
00075 
00076         // 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...
00077         bContext *C= (bContext *)BPy_GetContext();
00078         
00079         if(C==NULL) {
00080                 PyErr_SetString(PyExc_RuntimeError, "Context is None, cant poll any operators");
00081                 return NULL;
00082         }
00083 
00084         if (!PyArg_ParseTuple(args, "s|Os:_bpy.ops.poll", &opname, &context_dict, &context_str))
00085                 return NULL;
00086         
00087         ot= WM_operatortype_find(opname, TRUE);
00088 
00089         if (ot == NULL) {
00090                 PyErr_Format(PyExc_AttributeError,
00091                              "Polling operator \"bpy.ops.%s\" error, "
00092                              "could not be found", opname);
00093                 return NULL;
00094         }
00095 
00096         if(context_str) {
00097                 if(RNA_enum_value_from_id(operator_context_items, context_str, &context)==0) {
00098                         char *enum_str= BPy_enum_as_string(operator_context_items);
00099                         PyErr_Format(PyExc_TypeError,
00100                                      "Calling operator \"bpy.ops.%s.poll\" error, "
00101                                      "expected a string enum in (%.200s)",
00102                                      opname, enum_str);
00103                         MEM_freeN(enum_str);
00104                         return NULL;
00105                 }
00106         }
00107         
00108         if(context_dict==NULL || context_dict==Py_None) {
00109                 context_dict= NULL;
00110         }
00111         else if (!PyDict_Check(context_dict)) {
00112                 PyErr_Format(PyExc_TypeError,
00113                              "Calling operator \"bpy.ops.%s.poll\" error, "
00114                              "custom context expected a dict or None, got a %.200s",
00115                              opname, Py_TYPE(context_dict)->tp_name);
00116                 return NULL;
00117         }
00118 
00119         context_dict_back= CTX_py_dict_get(C);
00120 
00121         CTX_py_dict_set(C, (void *)context_dict);
00122         Py_XINCREF(context_dict); /* so we done loose it */
00123         
00124         /* main purpose of thsi function */
00125         ret= WM_operator_poll_context((bContext*)C, ot, context) ? Py_True : Py_False;
00126         
00127         /* restore with original context dict, probably NULL but need this for nested operator calls */
00128         Py_XDECREF(context_dict);
00129         CTX_py_dict_set(C, (void *)context_dict_back);
00130         
00131         Py_INCREF(ret);
00132         return ret;
00133 }
00134 
00135 static PyObject *pyop_call(PyObject *UNUSED(self), PyObject *args)
00136 {
00137         wmOperatorType *ot;
00138         int error_val= 0;
00139         PointerRNA ptr;
00140         int operator_ret= OPERATOR_CANCELLED;
00141 
00142         char            *opname;
00143         char            *context_str= NULL;
00144         PyObject        *kw= NULL; /* optional args */
00145         PyObject        *context_dict= NULL; /* optional args */
00146         PyObject        *context_dict_back;
00147 
00148         /* note that context is an int, python does the conversion in this case */
00149         int context= WM_OP_EXEC_DEFAULT;
00150 
00151         // 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...
00152         bContext *C= (bContext *)BPy_GetContext();
00153         
00154         if(C==NULL) {
00155                 PyErr_SetString(PyExc_RuntimeError, "Context is None, cant poll any operators");
00156                 return NULL;
00157         }
00158         
00159         if (!PyArg_ParseTuple(args, "sO|O!s:_bpy.ops.call", &opname, &context_dict, &PyDict_Type, &kw, &context_str))
00160                 return NULL;
00161 
00162         ot= WM_operatortype_find(opname, TRUE);
00163 
00164         if (ot == NULL) {
00165                 PyErr_Format(PyExc_AttributeError,
00166                              "Calling operator \"bpy.ops.%s\" error, "
00167                              "could not be found", opname);
00168                 return NULL;
00169         }
00170         
00171         if(!pyrna_write_check()) {
00172                 PyErr_Format(PyExc_RuntimeError,
00173                              "Calling operator \"bpy.ops.%s\" error, "
00174                              "can't modify blend data in this state (drawing/rendering)",
00175                              opname);
00176                 return NULL;
00177         }
00178 
00179         if(context_str) {
00180                 if(RNA_enum_value_from_id(operator_context_items, context_str, &context)==0) {
00181                         char *enum_str= BPy_enum_as_string(operator_context_items);
00182                         PyErr_Format(PyExc_TypeError,
00183                                      "Calling operator \"bpy.ops.%s\" error, "
00184                                      "expected a string enum in (%.200s)",
00185                                      opname, enum_str);
00186                         MEM_freeN(enum_str);
00187                         return NULL;
00188                 }
00189         }
00190 
00191         if(context_dict==NULL || context_dict==Py_None) {
00192                 context_dict= NULL;
00193         }
00194         else if (!PyDict_Check(context_dict)) {
00195                 PyErr_Format(PyExc_TypeError,
00196                              "Calling operator \"bpy.ops.%s\" error, "
00197                              "custom context expected a dict or None, got a %.200s",
00198                              opname, Py_TYPE(context_dict)->tp_name);
00199                 return NULL;
00200         }
00201 
00202         context_dict_back= CTX_py_dict_get(C);
00203 
00204         CTX_py_dict_set(C, (void *)context_dict);
00205         Py_XINCREF(context_dict); /* so we done loose it */
00206 
00207         if(WM_operator_poll_context((bContext*)C, ot, context) == FALSE) {
00208                 const char *msg= CTX_wm_operator_poll_msg_get(C);
00209                 PyErr_Format(PyExc_RuntimeError,
00210                              "Operator bpy.ops.%.200s.poll() %.200s",
00211                              opname, msg ? msg : "failed, context is incorrect");
00212                 CTX_wm_operator_poll_msg_set(C, NULL); /* better set to NULL else it could be used again */
00213                 error_val= -1;
00214         }
00215         else {
00216                 WM_operator_properties_create_ptr(&ptr, ot);
00217                 WM_operator_properties_sanitize(&ptr, 0);
00218 
00219                 if(kw && PyDict_Size(kw))
00220                         error_val= pyrna_pydict_to_props(&ptr, kw, 0, "Converting py args to operator properties: ");
00221 
00222 
00223                 if (error_val==0) {
00224                         ReportList *reports;
00225 
00226                         reports= MEM_mallocN(sizeof(ReportList), "wmOperatorReportList");
00227                         BKE_reports_init(reports, RPT_STORE | RPT_OP_HOLD); /* own so these dont move into global reports */
00228 
00229 #ifdef BPY_RELEASE_GIL
00230                         /* release GIL, since a thread could be started from an operator
00231                          * that updates a driver */
00232                         /* note: I havve not seen any examples of code that does this
00233                          * so it may not be officially supported but seems to work ok. */
00234                         {
00235                                 PyThreadState *ts= PyEval_SaveThread();
00236 #endif
00237 
00238                                 operator_ret= WM_operator_call_py(C, ot, context, &ptr, reports);
00239 
00240 #ifdef BPY_RELEASE_GIL
00241                                 /* regain GIL */
00242                                 PyEval_RestoreThread(ts);
00243                         }
00244 #endif
00245 
00246                         error_val= BPy_reports_to_error(reports, PyExc_RuntimeError, FALSE);
00247 
00248                         /* operator output is nice to have in the terminal/console too */
00249                         if(reports->list.first) {
00250                                 char *report_str= BKE_reports_string(reports, 0); /* all reports */
00251         
00252                                 if(report_str) {
00253                                         PySys_WriteStdout("%s\n", report_str);
00254                                         MEM_freeN(report_str);
00255                                 }
00256                         }
00257         
00258                         BKE_reports_clear(reports);
00259                         if ((reports->flag & RPT_FREE) == 0)
00260                         {
00261                                 MEM_freeN(reports);
00262                         }
00263                 }
00264 
00265                 WM_operator_properties_free(&ptr);
00266 
00267 #if 0
00268                 /* if there is some way to know an operator takes args we should use this */
00269                 {
00270                         /* no props */
00271                         if (kw != NULL) {
00272                                 PyErr_Format(PyExc_AttributeError,
00273                                              "Operator \"%s\" does not take any args",
00274                                              opname);
00275                                 return NULL;
00276                         }
00277 
00278                         WM_operator_name_call(C, opname, WM_OP_EXEC_DEFAULT, NULL);
00279                 }
00280 #endif
00281         }
00282 
00283         /* restore with original context dict, probably NULL but need this for nested operator calls */
00284         Py_XDECREF(context_dict);
00285         CTX_py_dict_set(C, (void *)context_dict_back);
00286 
00287         if (error_val==-1) {
00288                 return NULL;
00289         }
00290 
00291         /* when calling  bpy.ops.wm.read_factory_settings() bpy.data's main pointer is freed by clear_globals(),
00292          * further access will crash blender. setting context is not needed in this case, only calling because this
00293          * function corrects bpy.data (internal Main pointer) */
00294         BPY_modules_update(C);
00295 
00296         /* needed for when WM_OT_read_factory_settings us called fro within a script */
00297         bpy_import_main_set(CTX_data_main(C));
00298 
00299         /* return operator_ret as a bpy enum */
00300         return pyrna_enum_bitfield_to_py(operator_return_items, operator_ret);
00301 
00302 }
00303 
00304 static PyObject *pyop_as_string(PyObject *UNUSED(self), PyObject *args)
00305 {
00306         wmOperatorType *ot;
00307         PointerRNA ptr;
00308 
00309         char            *opname;
00310         PyObject        *kw= NULL; /* optional args */
00311         int all_args= 1;
00312         int error_val= 0;
00313 
00314         char *buf= NULL;
00315         PyObject *pybuf;
00316 
00317         bContext *C= (bContext *)BPy_GetContext();
00318 
00319         if(C==NULL) {
00320                 PyErr_SetString(PyExc_RuntimeError, "Context is None, cant get the string representation of this object.");
00321                 return NULL;
00322         }
00323         
00324         if (!PyArg_ParseTuple(args, "s|O!i:_bpy.ops.as_string", &opname, &PyDict_Type, &kw, &all_args))
00325                 return NULL;
00326 
00327         ot= WM_operatortype_find(opname, TRUE);
00328 
00329         if (ot == NULL) {
00330                 PyErr_Format(PyExc_AttributeError,
00331                              "_bpy.ops.as_string: operator \"%.200s\" "
00332                              "could not be found", opname);
00333                 return NULL;
00334         }
00335 
00336         /* WM_operator_properties_create(&ptr, opname); */
00337         /* Save another lookup */
00338         RNA_pointer_create(NULL, ot->srna, NULL, &ptr);
00339 
00340         if(kw && PyDict_Size(kw))
00341                 error_val= pyrna_pydict_to_props(&ptr, kw, 0, "Converting py args to operator properties: ");
00342 
00343         if (error_val==0)
00344                 buf= WM_operator_pystring(C, ot, &ptr, all_args);
00345 
00346         WM_operator_properties_free(&ptr);
00347 
00348         if (error_val==-1) {
00349                 return NULL;
00350         }
00351 
00352         if(buf) {
00353                 pybuf= PyUnicode_FromString(buf);
00354                 MEM_freeN(buf);
00355         }
00356         else {
00357                 pybuf= PyUnicode_FromString("");
00358         }
00359 
00360         return pybuf;
00361 }
00362 
00363 static PyObject *pyop_dir(PyObject *UNUSED(self))
00364 {
00365         GHashIterator *iter= WM_operatortype_iter();
00366         PyObject *list= PyList_New(0), *name;
00367 
00368         for( ; !BLI_ghashIterator_isDone(iter); BLI_ghashIterator_step(iter)) {
00369                 wmOperatorType *ot= BLI_ghashIterator_getValue(iter);
00370 
00371                 name= PyUnicode_FromString(ot->idname);
00372                 PyList_Append(list, name);
00373                 Py_DECREF(name);
00374         }
00375         BLI_ghashIterator_free(iter);
00376 
00377         return list;
00378 }
00379 
00380 static PyObject *pyop_getrna(PyObject *UNUSED(self), PyObject *value)
00381 {
00382         wmOperatorType *ot;
00383         PointerRNA ptr;
00384         char *opname= _PyUnicode_AsString(value);
00385         BPy_StructRNA *pyrna= NULL;
00386         
00387         if(opname==NULL) {
00388                 PyErr_SetString(PyExc_TypeError, "_bpy.ops.get_rna() expects a string argument");
00389                 return NULL;
00390         }
00391         ot= WM_operatortype_find(opname, TRUE);
00392         if(ot==NULL) {
00393                 PyErr_Format(PyExc_KeyError, "_bpy.ops.get_rna(\"%s\") not found", opname);
00394                 return NULL;
00395         }
00396         
00397         /* type */
00398         //RNA_pointer_create(NULL, &RNA_Struct, ot->srna, &ptr);
00399 
00400         /* XXX - should call WM_operator_properties_free */
00401         WM_operator_properties_create_ptr(&ptr, ot);
00402         WM_operator_properties_sanitize(&ptr, 0);
00403 
00404         
00405         pyrna= (BPy_StructRNA *)pyrna_struct_CreatePyObject(&ptr);
00406 #ifdef PYRNA_FREE_SUPPORT
00407         pyrna->freeptr= TRUE;
00408 #endif
00409         return (PyObject *)pyrna;
00410 }
00411 
00412 static struct PyMethodDef bpy_ops_methods[]= {
00413         {"poll", (PyCFunction) pyop_poll, METH_VARARGS, NULL},
00414         {"call", (PyCFunction) pyop_call, METH_VARARGS, NULL},
00415         {"as_string", (PyCFunction) pyop_as_string, METH_VARARGS, NULL},
00416         {"dir", (PyCFunction) pyop_dir, METH_NOARGS, NULL},
00417         {"get_rna", (PyCFunction) pyop_getrna, METH_O, NULL},
00418         {"macro_define", (PyCFunction) PYOP_wrap_macro_define, METH_VARARGS, NULL},
00419         {NULL, NULL, 0, NULL}
00420 };
00421 
00422 static struct PyModuleDef bpy_ops_module= {
00423         PyModuleDef_HEAD_INIT,
00424         "_bpy.ops",
00425         NULL,
00426         -1,/* multiple "initialization" just copies the module dict. */
00427         bpy_ops_methods,
00428         NULL, NULL, NULL, NULL
00429 };
00430 
00431 PyObject *BPY_operator_module(void)
00432 {
00433         PyObject *submodule;
00434 
00435         submodule= PyModule_Create(&bpy_ops_module);
00436 
00437         return submodule;
00438 }