4a17c45ae3884bcf3904862afe5d8c4c8f66949f
[blender.git] / source / blender / python / intern / bpy_operator.c
1
2 /*
3  * $Id$
4  *
5  * ***** BEGIN GPL LICENSE BLOCK *****
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  * Contributor(s): Campbell Barton
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  */
25
26 /** \file blender/python/intern/bpy_operator.c
27  *  \ingroup pythonintern
28  */
29
30
31 /* Note, this module is not to be used directly by the user.
32  * Internally its exposed as '_bpy.ops', which provides functions for 'bpy.ops', a python package.
33  * */
34
35 #include <Python.h>
36
37 #include "RNA_types.h"
38
39 #include "BPY_extern.h"
40 #include "bpy_operator.h"
41 #include "bpy_operator_wrap.h"
42 #include "bpy_rna.h" /* for setting arg props only - pyrna_py_to_prop() */
43 #include "bpy_util.h"
44 #include "../generic/bpy_internal_import.h"
45
46 #include "BLI_utildefines.h"
47
48 #include "RNA_access.h"
49 #include "RNA_enum_types.h"
50
51 #include "WM_api.h"
52 #include "WM_types.h"
53
54 #include "MEM_guardedalloc.h"
55 #include "BKE_report.h"
56 #include "BKE_context.h"
57
58 /* so operators called can spawn threads which aquire the GIL */
59 #define BPY_RELEASE_GIL
60
61
62 static PyObject *pyop_poll(PyObject *UNUSED(self), PyObject *args)
63 {
64         wmOperatorType *ot;
65         char            *opname;
66         PyObject        *context_dict= NULL; /* optional args */
67         PyObject        *context_dict_back;
68         char            *context_str= NULL;
69         PyObject        *ret;
70
71         int context= WM_OP_EXEC_DEFAULT;
72
73         // 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...
74         bContext *C= (bContext *)BPy_GetContext();
75         
76         if(C==NULL) {
77                 PyErr_SetString(PyExc_RuntimeError, "Context is None, cant poll any operators");
78                 return NULL;
79         }
80
81         if (!PyArg_ParseTuple(args, "s|Os:_bpy.ops.poll", &opname, &context_dict, &context_str))
82                 return NULL;
83         
84         ot= WM_operatortype_find(opname, TRUE);
85
86         if (ot == NULL) {
87                 PyErr_Format(PyExc_AttributeError,
88                              "Polling operator \"bpy.ops.%s\" error, "
89                              "could not be found", opname);
90                 return NULL;
91         }
92
93         if(context_str) {
94                 if(RNA_enum_value_from_id(operator_context_items, context_str, &context)==0) {
95                         char *enum_str= BPy_enum_as_string(operator_context_items);
96                         PyErr_Format(PyExc_TypeError,
97                                      "Calling operator \"bpy.ops.%s.poll\" error, "
98                                      "expected a string enum in (%.200s)",
99                                      opname, enum_str);
100                         MEM_freeN(enum_str);
101                         return NULL;
102                 }
103         }
104         
105         if(context_dict==NULL || context_dict==Py_None) {
106                 context_dict= NULL;
107         }
108         else if (!PyDict_Check(context_dict)) {
109                 PyErr_Format(PyExc_TypeError,
110                              "Calling operator \"bpy.ops.%s.poll\" error, "
111                              "custom context expected a dict or None, got a %.200s",
112                              opname, Py_TYPE(context_dict)->tp_name);
113                 return NULL;
114         }
115
116         context_dict_back= CTX_py_dict_get(C);
117
118         CTX_py_dict_set(C, (void *)context_dict);
119         Py_XINCREF(context_dict); /* so we done loose it */
120         
121         /* main purpose of thsi function */
122         ret= WM_operator_poll_context((bContext*)C, ot, context) ? Py_True : Py_False;
123         
124         /* restore with original context dict, probably NULL but need this for nested operator calls */
125         Py_XDECREF(context_dict);
126         CTX_py_dict_set(C, (void *)context_dict_back);
127         
128         Py_INCREF(ret);
129         return ret;
130 }
131
132 static PyObject *pyop_call(PyObject *UNUSED(self), PyObject *args)
133 {
134         wmOperatorType *ot;
135         int error_val= 0;
136         PointerRNA ptr;
137         int operator_ret= OPERATOR_CANCELLED;
138
139         char            *opname;
140         char            *context_str= NULL;
141         PyObject        *kw= NULL; /* optional args */
142         PyObject        *context_dict= NULL; /* optional args */
143         PyObject        *context_dict_back;
144
145         /* note that context is an int, python does the conversion in this case */
146         int context= WM_OP_EXEC_DEFAULT;
147
148         // 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...
149         bContext *C= (bContext *)BPy_GetContext();
150         
151         if(C==NULL) {
152                 PyErr_SetString(PyExc_RuntimeError, "Context is None, cant poll any operators");
153                 return NULL;
154         }
155         
156         if (!PyArg_ParseTuple(args, "sO|O!s:_bpy.ops.call", &opname, &context_dict, &PyDict_Type, &kw, &context_str))
157                 return NULL;
158
159         ot= WM_operatortype_find(opname, TRUE);
160
161         if (ot == NULL) {
162                 PyErr_Format(PyExc_AttributeError,
163                              "Calling operator \"bpy.ops.%s\" error, "
164                              "could not be found", opname);
165                 return NULL;
166         }
167         
168         if(!pyrna_write_check()) {
169                 PyErr_Format(PyExc_RuntimeError,
170                              "Calling operator \"bpy.ops.%s\" error, "
171                              "can't modify blend data in this state (drawing/rendering)",
172                              opname);
173                 return NULL;
174         }
175
176         if(context_str) {
177                 if(RNA_enum_value_from_id(operator_context_items, context_str, &context)==0) {
178                         char *enum_str= BPy_enum_as_string(operator_context_items);
179                         PyErr_Format(PyExc_TypeError,
180                                      "Calling operator \"bpy.ops.%s\" error, "
181                                      "expected a string enum in (%.200s)",
182                                      opname, enum_str);
183                         MEM_freeN(enum_str);
184                         return NULL;
185                 }
186         }
187
188         if(context_dict==NULL || context_dict==Py_None) {
189                 context_dict= NULL;
190         }
191         else if (!PyDict_Check(context_dict)) {
192                 PyErr_Format(PyExc_TypeError,
193                              "Calling operator \"bpy.ops.%s\" error, "
194                              "custom context expected a dict or None, got a %.200s",
195                              opname, Py_TYPE(context_dict)->tp_name);
196                 return NULL;
197         }
198
199         context_dict_back= CTX_py_dict_get(C);
200
201         CTX_py_dict_set(C, (void *)context_dict);
202         Py_XINCREF(context_dict); /* so we done loose it */
203
204         if(WM_operator_poll_context((bContext*)C, ot, context) == FALSE) {
205                 const char *msg= CTX_wm_operator_poll_msg_get(C);
206                 PyErr_Format(PyExc_RuntimeError,
207                              "Operator bpy.ops.%.200s.poll() %.200s",
208                              opname, msg ? msg : "failed, context is incorrect");
209                 CTX_wm_operator_poll_msg_set(C, NULL); /* better set to NULL else it could be used again */
210                 error_val= -1;
211         }
212         else {
213                 WM_operator_properties_create_ptr(&ptr, ot);
214                 WM_operator_properties_sanitize(&ptr, 0);
215
216                 if(kw && PyDict_Size(kw))
217                         error_val= pyrna_pydict_to_props(&ptr, kw, 0, "Converting py args to operator properties: ");
218
219
220                 if (error_val==0) {
221                         ReportList *reports;
222
223                         reports= MEM_mallocN(sizeof(ReportList), "wmOperatorReportList");
224                         BKE_reports_init(reports, RPT_STORE | RPT_OP_HOLD); /* own so these dont move into global reports */
225
226 #ifdef BPY_RELEASE_GIL
227                         /* release GIL, since a thread could be started from an operator
228                          * that updates a driver */
229                         /* note: I havve not seen any examples of code that does this
230                          * so it may not be officially supported but seems to work ok. */
231                         {
232                                 PyThreadState *ts= PyEval_SaveThread();
233 #endif
234
235                                 operator_ret= WM_operator_call_py(C, ot, context, &ptr, reports);
236
237 #ifdef BPY_RELEASE_GIL
238                                 /* regain GIL */
239                                 PyEval_RestoreThread(ts);
240                         }
241 #endif
242
243                         error_val= BPy_reports_to_error(reports, PyExc_RuntimeError, FALSE);
244
245                         /* operator output is nice to have in the terminal/console too */
246                         if(reports->list.first) {
247                                 char *report_str= BKE_reports_string(reports, 0); /* all reports */
248         
249                                 if(report_str) {
250                                         PySys_WriteStdout("%s\n", report_str);
251                                         MEM_freeN(report_str);
252                                 }
253                         }
254         
255                         BKE_reports_clear(reports);
256                         if ((reports->flag & RPT_FREE) == 0)
257                         {
258                                 MEM_freeN(reports);
259                         }
260                 }
261
262                 WM_operator_properties_free(&ptr);
263
264 #if 0
265                 /* if there is some way to know an operator takes args we should use this */
266                 {
267                         /* no props */
268                         if (kw != NULL) {
269                                 PyErr_Format(PyExc_AttributeError,
270                                              "Operator \"%s\" does not take any args",
271                                              opname);
272                                 return NULL;
273                         }
274
275                         WM_operator_name_call(C, opname, WM_OP_EXEC_DEFAULT, NULL);
276                 }
277 #endif
278         }
279
280         /* restore with original context dict, probably NULL but need this for nested operator calls */
281         Py_XDECREF(context_dict);
282         CTX_py_dict_set(C, (void *)context_dict_back);
283
284         if (error_val==-1) {
285                 return NULL;
286         }
287
288         /* when calling  bpy.ops.wm.read_factory_settings() bpy.data's main pointer is freed by clear_globals(),
289          * further access will crash blender. setting context is not needed in this case, only calling because this
290          * function corrects bpy.data (internal Main pointer) */
291         BPY_modules_update(C);
292
293         /* needed for when WM_OT_read_factory_settings us called fro within a script */
294         bpy_import_main_set(CTX_data_main(C));
295
296         /* return operator_ret as a bpy enum */
297         return pyrna_enum_bitfield_to_py(operator_return_items, operator_ret);
298
299 }
300
301 static PyObject *pyop_as_string(PyObject *UNUSED(self), PyObject *args)
302 {
303         wmOperatorType *ot;
304         PointerRNA ptr;
305
306         char            *opname;
307         PyObject        *kw= NULL; /* optional args */
308         int all_args= 1;
309         int error_val= 0;
310
311         char *buf= NULL;
312         PyObject *pybuf;
313
314         bContext *C= (bContext *)BPy_GetContext();
315
316         if(C==NULL) {
317                 PyErr_SetString(PyExc_RuntimeError, "Context is None, cant get the string representation of this object.");
318                 return NULL;
319         }
320         
321         if (!PyArg_ParseTuple(args, "s|O!i:_bpy.ops.as_string", &opname, &PyDict_Type, &kw, &all_args))
322                 return NULL;
323
324         ot= WM_operatortype_find(opname, TRUE);
325
326         if (ot == NULL) {
327                 PyErr_Format(PyExc_AttributeError,
328                              "_bpy.ops.as_string: operator \"%.200s\" "
329                              "could not be found", opname);
330                 return NULL;
331         }
332
333         /* WM_operator_properties_create(&ptr, opname); */
334         /* Save another lookup */
335         RNA_pointer_create(NULL, ot->srna, NULL, &ptr);
336
337         if(kw && PyDict_Size(kw))
338                 error_val= pyrna_pydict_to_props(&ptr, kw, 0, "Converting py args to operator properties: ");
339
340         if (error_val==0)
341                 buf= WM_operator_pystring(C, ot, &ptr, all_args);
342
343         WM_operator_properties_free(&ptr);
344
345         if (error_val==-1) {
346                 return NULL;
347         }
348
349         if(buf) {
350                 pybuf= PyUnicode_FromString(buf);
351                 MEM_freeN(buf);
352         }
353         else {
354                 pybuf= PyUnicode_FromString("");
355         }
356
357         return pybuf;
358 }
359
360 static PyObject *pyop_dir(PyObject *UNUSED(self))
361 {
362         PyObject *list= PyList_New(0), *name;
363         wmOperatorType *ot;
364         
365         for(ot= WM_operatortype_first(); ot; ot= ot->next) {
366                 name= PyUnicode_FromString(ot->idname);
367                 PyList_Append(list, name);
368                 Py_DECREF(name);
369         }
370         
371         return list;
372 }
373
374 static PyObject *pyop_getrna(PyObject *UNUSED(self), PyObject *value)
375 {
376         wmOperatorType *ot;
377         PointerRNA ptr;
378         char *opname= _PyUnicode_AsString(value);
379         BPy_StructRNA *pyrna= NULL;
380         
381         if(opname==NULL) {
382                 PyErr_SetString(PyExc_TypeError, "_bpy.ops.get_rna() expects a string argument");
383                 return NULL;
384         }
385         ot= WM_operatortype_find(opname, TRUE);
386         if(ot==NULL) {
387                 PyErr_Format(PyExc_KeyError, "_bpy.ops.get_rna(\"%s\") not found", opname);
388                 return NULL;
389         }
390         
391         /* type */
392         //RNA_pointer_create(NULL, &RNA_Struct, ot->srna, &ptr);
393
394         /* XXX - should call WM_operator_properties_free */
395         WM_operator_properties_create_ptr(&ptr, ot);
396         WM_operator_properties_sanitize(&ptr, 0);
397
398         
399         pyrna= (BPy_StructRNA *)pyrna_struct_CreatePyObject(&ptr);
400         pyrna->freeptr= TRUE;
401         return (PyObject *)pyrna;
402 }
403
404 static struct PyMethodDef bpy_ops_methods[]= {
405         {"poll", (PyCFunction) pyop_poll, METH_VARARGS, NULL},
406         {"call", (PyCFunction) pyop_call, METH_VARARGS, NULL},
407         {"as_string", (PyCFunction) pyop_as_string, METH_VARARGS, NULL},
408         {"dir", (PyCFunction) pyop_dir, METH_NOARGS, NULL},
409         {"get_rna", (PyCFunction) pyop_getrna, METH_O, NULL},
410         {"macro_define", (PyCFunction) PYOP_wrap_macro_define, METH_VARARGS, NULL},
411         {NULL, NULL, 0, NULL}
412 };
413
414 static struct PyModuleDef bpy_ops_module= {
415         PyModuleDef_HEAD_INIT,
416         "_bpy.ops",
417         NULL,
418         -1,/* multiple "initialization" just copies the module dict. */
419         bpy_ops_methods,
420         NULL, NULL, NULL, NULL
421 };
422
423 PyObject *BPY_operator_module(void)
424 {
425         PyObject *submodule;
426
427         submodule= PyModule_Create(&bpy_ops_module);
428
429         return submodule;
430 }