Store the context for python in a static variable with assessor functions - BPy_GetCo...
[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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20  *
21  * Contributor(s): Campbell Barton
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  */
25
26 #include "bpy_operator.h"
27 #include "bpy_operator_wrap.h"
28 #include "bpy_rna.h" /* for setting arg props only - pyrna_py_to_prop() */
29 #include "bpy_compat.h"
30 #include "bpy_util.h"
31
32 //#include "blendef.h"
33 #include "BLI_dynstr.h"
34
35 #include "WM_api.h"
36 #include "WM_types.h"
37
38 #include "MEM_guardedalloc.h"
39 //#include "BKE_idprop.h"
40 #include "BKE_report.h"
41
42 extern ListBase global_ops; /* evil, temp use */
43
44
45
46 /* This function is only used by operators right now
47  * Its used for taking keyword args and filling in property values */
48 int PYOP_props_from_dict(PointerRNA *ptr, PyObject *kw)
49 {
50         int error_val = 0;
51         int totkw;
52         const char *arg_name= NULL;
53         PyObject *item;
54
55         PropertyRNA *prop, *iterprop;
56         CollectionPropertyIterator iter;
57
58         iterprop= RNA_struct_iterator_property(ptr->type);
59         RNA_property_collection_begin(ptr, iterprop, &iter);
60
61         totkw = kw ? PyDict_Size(kw):0;
62
63         for(; iter.valid; RNA_property_collection_next(&iter)) {
64                 prop= iter.ptr.data;
65
66                 arg_name= RNA_property_identifier(prop);
67
68                 if (strcmp(arg_name, "rna_type")==0) continue;
69
70                 if (kw==NULL) {
71                         PyErr_Format( PyExc_AttributeError, "no args, expected \"%s\"", arg_name ? arg_name : "<UNKNOWN>");
72                         error_val= -1;
73                         break;
74                 }
75
76                 item= PyDict_GetItemString(kw, arg_name);
77
78                 if (item == NULL) {
79                         PyErr_Format( PyExc_AttributeError, "argument \"%s\" missing", arg_name ? arg_name : "<UNKNOWN>");
80                         error_val = -1; /* pyrna_py_to_prop sets the error */
81                         break;
82                 }
83
84                 if (pyrna_py_to_prop(ptr, prop, NULL, item)) {
85                         error_val= -1;
86                         break;
87                 }
88
89                 totkw--;
90         }
91
92         RNA_property_collection_end(&iter);
93
94         if (error_val==0 && totkw > 0) { /* some keywords were given that were not used :/ */
95                 PyObject *key, *value;
96                 Py_ssize_t pos = 0;
97
98                 while (PyDict_Next(kw, &pos, &key, &value)) {
99                         arg_name= _PyUnicode_AsString(key);
100                         if (RNA_struct_find_property(ptr, arg_name) == NULL) break;
101                         arg_name= NULL;
102                 }
103
104                 PyErr_Format( PyExc_AttributeError, "argument \"%s\" unrecognized", arg_name ? arg_name : "<UNKNOWN>");
105                 error_val = -1;
106         }
107
108         return error_val;
109 }
110
111 static PyObject *pyop_base_dir(PyObject *self);
112 static PyObject *pyop_base_rna(PyObject *self, PyObject *pyname);
113 static struct PyMethodDef pyop_base_methods[] = {
114         {"__dir__", (PyCFunction)pyop_base_dir, METH_NOARGS, ""},
115         {"__rna__", (PyCFunction)pyop_base_rna, METH_O, ""},
116         {"add", (PyCFunction)PYOP_wrap_add, METH_O, ""},
117         {"remove", (PyCFunction)PYOP_wrap_remove, METH_O, ""},
118         {NULL, NULL, 0, NULL}
119 };
120
121 /* 'self' stores the operator string */
122 static PyObject *pyop_base_call( PyObject * self, PyObject * args,  PyObject * kw)
123 {
124         wmOperatorType *ot;
125         int error_val = 0;
126         PointerRNA ptr;
127         
128         // 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...
129         bContext *C = BPy_GetContext();
130         
131         char *opname = _PyUnicode_AsString(self);
132
133         if (PyTuple_Size(args)) {
134                 PyErr_SetString( PyExc_AttributeError, "All operator args must be keywords");
135                 return NULL;
136         }
137
138         ot= WM_operatortype_find(opname);
139         if (ot == NULL) {
140                 PyErr_Format( PyExc_SystemError, "Operator \"%s\"could not be found", opname);
141                 return NULL;
142         }
143         
144         if(ot->poll && (ot->poll(C) == 0)) {
145                 PyErr_SetString( PyExc_SystemError, "Operator poll() function failed, context is incorrect");
146                 return NULL;
147         }
148         
149         WM_operator_properties_create(&ptr, opname);
150         
151         error_val= PYOP_props_from_dict(&ptr, kw);
152         
153         if (error_val==0) {
154                 ReportList reports;
155
156                 BKE_reports_init(&reports, RPT_STORE);
157
158                 WM_operator_call_py(C, ot, &ptr, &reports);
159
160                 if(BPy_reports_to_error(&reports))
161                         error_val = -1;
162
163                 BKE_reports_clear(&reports);
164         }
165
166         WM_operator_properties_free(&ptr);
167
168 #if 0
169         /* if there is some way to know an operator takes args we should use this */
170         {
171                 /* no props */
172                 if (kw != NULL) {
173                         PyErr_Format(PyExc_AttributeError, "Operator \"%s\" does not take any args", opname);
174                         return NULL;
175                 }
176
177                 WM_operator_name_call(C, opname, WM_OP_EXEC_DEFAULT, NULL);
178         }
179 #endif
180
181         if (error_val==-1) {
182                 return NULL;
183         }
184
185         Py_RETURN_NONE;
186 }
187
188 static PyMethodDef pyop_base_call_meth[] = {
189         {"__op_call__", (PyCFunction)pyop_base_call, METH_VARARGS|METH_KEYWORDS, "generic operator calling function"}
190 };
191
192
193 //---------------getattr--------------------------------------------
194 static PyObject *pyop_base_getattro( BPy_OperatorBase * self, PyObject *pyname )
195 {
196         char *name = _PyUnicode_AsString(pyname);
197         PyObject *ret;
198         wmOperatorType *ot;
199         
200         if ((ot= WM_operatortype_find(name))) {
201                 ret = PyCFunction_New( pyop_base_call_meth, pyname); /* set the name string as self, PyCFunction_New incref's self */
202         }
203         else if ((ret = PyObject_GenericGetAttr((PyObject *)self, pyname))) {
204                 /* do nothing, this accounts for methoddef's add and remove */
205         }
206         else {
207                 PyErr_Format( PyExc_AttributeError, "Operator \"%s\" not found", name);
208                 ret= NULL;
209         }
210
211         return ret;
212 }
213
214 static PyObject *pyop_base_dir(PyObject *self)
215 {
216         PyObject *list = PyList_New(0), *name;
217         wmOperatorType *ot;
218         PyMethodDef *meth;
219         
220         for(ot= WM_operatortype_first(); ot; ot= ot->next) {
221                 name = PyUnicode_FromString(ot->idname);
222                 PyList_Append(list, name);
223                 Py_DECREF(name);
224         }
225
226         for(meth=pyop_base_methods; meth->ml_name; meth++) {
227                 name = PyUnicode_FromString(meth->ml_name);
228                 PyList_Append(list, name);
229                 Py_DECREF(name);
230         }
231         
232         return list;
233 }
234
235 static PyObject *pyop_base_rna(PyObject *self, PyObject *pyname)
236 {
237         char *name = _PyUnicode_AsString(pyname);
238         wmOperatorType *ot;
239         
240         if ((ot= WM_operatortype_find(name))) {
241                 BPy_StructRNA *pyrna;
242                 PointerRNA ptr;
243                 
244                 /* XXX POINTER - if this 'ot' is python generated, it could be free'd */
245                 RNA_pointer_create(NULL, ot->srna, NULL, &ptr);
246                 
247                 pyrna= (BPy_StructRNA *)pyrna_struct_CreatePyObject(&ptr); /* were not really using &ptr, overwite next */
248                 //pyrna->freeptr= 1;
249                 return (PyObject *)pyrna;
250         }
251         else {
252                 PyErr_Format(PyExc_AttributeError, "Operator \"%s\" not found", name);
253                 return NULL;
254         }
255 }
256
257 PyTypeObject pyop_base_Type = {NULL};
258
259 PyObject *BPY_operator_module( void )
260 {
261         pyop_base_Type.tp_name = "OperatorBase";
262         pyop_base_Type.tp_basicsize = sizeof( BPy_OperatorBase );
263         pyop_base_Type.tp_getattro = ( getattrofunc )pyop_base_getattro;
264         pyop_base_Type.tp_flags = Py_TPFLAGS_DEFAULT;
265         pyop_base_Type.tp_methods = pyop_base_methods;
266         
267         if( PyType_Ready( &pyop_base_Type ) < 0 )
268                 return NULL;
269
270         //submodule = Py_InitModule3( "operator", M_rna_methods, "rna module" );
271         return (PyObject *)PyObject_NEW( BPy_OperatorBase, &pyop_base_Type );
272 }
273