Support for the C Macro system in Python.
[blender.git] / source / blender / python / intern / bpy_operator_wrap.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
27 #include "bpy_operator_wrap.h"
28 #include "BLI_listbase.h"
29 #include "BKE_context.h"
30 #include "BKE_report.h"
31 #include "DNA_windowmanager_types.h"
32 #include "MEM_guardedalloc.h"
33 #include "WM_api.h"
34 #include "WM_types.h"
35 #include "UI_interface.h"
36 #include "ED_screen.h"
37
38 #include "RNA_define.h"
39
40 #include "bpy_rna.h"
41 #include "bpy_util.h"
42
43 #include "../generic/bpy_internal_import.h" // our own imports
44
45 #define PYOP_ATTR_UINAME                "bl_label"
46 #define PYOP_ATTR_IDNAME                "bl_idname"             /* the name given by python */
47 #define PYOP_ATTR_IDNAME_BL     "_bl_idname"    /* our own name converted into blender syntax, users wont see this */
48 #define PYOP_ATTR_DESCRIPTION   "__doc__"               /* use pythons docstring */
49 #define PYOP_ATTR_REGISTER              "bl_register"   /* True/False. if this python operator should be registered */
50 #define PYOP_ATTR_UNDO                  "bl_undo"               /* True/False. if this python operator should be undone */
51
52 static struct BPY_flag_def pyop_ret_flags[] = {
53         {"RUNNING_MODAL", OPERATOR_RUNNING_MODAL},
54         {"CANCELLED", OPERATOR_CANCELLED},
55         {"FINISHED", OPERATOR_FINISHED},
56         {"PASS_THROUGH", OPERATOR_PASS_THROUGH},
57         {NULL, 0}
58 };
59
60 /* This invoke function can take events and
61  *
62  * It is up to the pyot->py_invoke() python func to run pyot->py_exec()
63  * the invoke function gets the keyword props as a dict, but can parse them
64  * to py_exec like this...
65  *
66  * def op_exec(x=-1, y=-1, text=""):
67  *     ...
68  *
69  * def op_invoke(event, prop_defs):
70  *     prop_defs['x'] = event['x']
71  *     ...
72  *     op_exec(**prop_defs)
73  *
74  * when there is no invoke function, C calls exec and sets the props.
75  * python class instance is stored in op->customdata so exec() can access
76  */
77
78
79 #define PYOP_EXEC 1
80 #define PYOP_INVOKE 2
81 #define PYOP_POLL 3
82 #define PYOP_DRAW 4
83         
84 extern void BPY_update_modules( void ); //XXX temp solution
85
86 static int PYTHON_OT_generic(int mode, bContext *C, wmOperatorType *ot, wmOperator *op, wmEvent *event, uiLayout *layout)
87 {
88         PyObject *py_class = ot->pyop_data;
89         PyObject *args;
90         PyObject *ret= NULL, *py_class_instance, *item= NULL;
91         int ret_flag= (mode==PYOP_POLL ? 0:OPERATOR_CANCELLED);
92         PointerRNA ptr_context;
93         PointerRNA ptr_operator;
94
95         PyGILState_STATE gilstate;
96
97         bpy_context_set(C, &gilstate);
98
99         args = PyTuple_New(1);
100
101         /* poll has no 'op', should be ok still */
102         /* use an rna instance as the first arg */
103         RNA_pointer_create(NULL, &RNA_Operator, op, &ptr_operator);
104         PyTuple_SET_ITEM(args, 0, pyrna_struct_CreatePyObject(&ptr_operator));
105
106         py_class_instance = PyObject_Call(py_class, args, NULL);
107         Py_DECREF(args);
108         
109         if (py_class_instance==NULL) { /* Initializing the class worked, now run its invoke function */
110                 PyErr_Print();
111                 PyErr_Clear();
112         }
113         else {
114                 RNA_pointer_create(NULL, &RNA_Context, C, &ptr_context);
115
116                 if (mode==PYOP_INVOKE) {
117                         PointerRNA ptr_event;
118                         item= PyObject_GetAttrString(py_class, "invoke");
119                         args = PyTuple_New(3);
120
121                         RNA_pointer_create(NULL, &RNA_Event, event, &ptr_event);
122
123                         // PyTuple_SET_ITEM "steals" object reference, it is
124                         // an object passed shouldn't be DECREF'ed
125                         PyTuple_SET_ITEM(args, 1, pyrna_struct_CreatePyObject(&ptr_context));
126                         PyTuple_SET_ITEM(args, 2, pyrna_struct_CreatePyObject(&ptr_event));
127                 }
128                 else if (mode==PYOP_EXEC) {
129                         item= PyObject_GetAttrString(py_class, "execute");
130                         args = PyTuple_New(2);
131                         
132                         PyTuple_SET_ITEM(args, 1, pyrna_struct_CreatePyObject(&ptr_context));
133                 }
134                 else if (mode==PYOP_POLL) {
135                         item= PyObject_GetAttrString(py_class, "poll");
136                         args = PyTuple_New(2);
137                         PyTuple_SET_ITEM(args, 1, pyrna_struct_CreatePyObject(&ptr_context));
138                 }
139                 else if (mode==PYOP_DRAW) {
140                         PointerRNA ptr_layout;
141                         item= PyObject_GetAttrString(py_class, "draw");
142                         args = PyTuple_New(2);
143
144                         RNA_pointer_create(NULL, &RNA_UILayout, layout, &ptr_layout);
145
146                         // PyTuple_SET_ITEM "steals" object reference, it is
147                         // an object passed shouldn't be DECREF'ed
148                         PyTuple_SET_ITEM(args, 1, pyrna_struct_CreatePyObject(&ptr_context));
149 #if 0
150                         PyTuple_SET_ITEM(args, 2, pyrna_struct_CreatePyObject(&ptr_layout));
151 #else
152                         {
153                                 /* mimic panels */
154                                 PyObject *py_layout= pyrna_struct_CreatePyObject(&ptr_layout);
155                                 PyObject *pyname= PyUnicode_FromString("layout");
156
157                                 if(PyObject_GenericSetAttr(py_class_instance, pyname, py_layout)) {
158                                         PyErr_Print();
159                                         PyErr_Clear();
160                                 }
161                                 else {
162                                         Py_DECREF(py_layout);
163                                 }
164
165                                 Py_DECREF(pyname);
166                         }
167 #endif
168                 }
169                 PyTuple_SET_ITEM(args, 0, py_class_instance);
170
171                 ret = PyObject_Call(item, args, NULL);
172
173                 Py_DECREF(args);
174                 Py_DECREF(item);
175         }
176         
177         if (ret == NULL) { /* covers py_class_instance failing too */
178                 if(op)
179                         BPy_errors_to_report(op->reports);
180         }
181         else {
182                 if (mode==PYOP_POLL) {
183                         if (PyBool_Check(ret) == 0) {
184                                 PyErr_Format(PyExc_ValueError, "Python operator '%s.poll', did not return a bool value", ot->idname);
185                                 BPy_errors_to_report(op ? op->reports:NULL); /* prints and clears if NULL given */
186                         }
187                         else {
188                                 ret_flag= ret==Py_True ? 1:0;
189                         }
190                 } else if(mode==PYOP_DRAW) {
191                         /* pass */
192                 } else if (BPY_flag_from_seq(pyop_ret_flags, ret, &ret_flag) == -1) {
193                         /* the returned value could not be converted into a flag */
194                         PyErr_Format(PyExc_ValueError, "Python operator, error using return value from \"%s\"\n", ot->idname);
195                         BPy_errors_to_report(op ? op->reports:NULL);
196                         ret_flag = OPERATOR_CANCELLED;
197                 }
198                 /* there is no need to copy the py keyword dict modified by
199                  * pyot->py_invoke(), back to the operator props since they are just
200                  * thrown away anyway
201                  *
202                  * If we ever want to do this and use the props again,
203                  * it can be done with - pyrna_pydict_to_props(op->ptr, kw, "")
204                  */
205                 
206                 Py_DECREF(ret);
207         }
208
209 #if 0 /* only for testing */
210
211         /* print operator return value */
212         if (mode != PYOP_POLL) {
213                 char flag_str[100];
214                 char class_name[100];
215                 BPY_flag_def *flag_def = pyop_ret_flags;
216
217                 strcpy(flag_str, "");
218                 
219                 while(flag_def->name) {
220                         if (ret_flag & flag_def->flag) {
221                                 if(flag_str[1])
222                                         sprintf(flag_str, "%s | %s", flag_str, flag_def->name);
223                                 else
224                                         strcpy(flag_str, flag_def->name);
225                         }
226                         flag_def++;
227                 }
228
229                 /* get class name */
230                 item= PyObject_GetAttrString(py_class, PYOP_ATTR_IDNAME);
231                 strcpy(class_name, _PyUnicode_AsString(item));
232                 Py_DECREF(item);
233
234                 fprintf(stderr, "%s's %s returned %s\n", class_name, mode == PYOP_EXEC ? "execute" : "invoke", flag_str);
235         }
236 #endif
237
238         bpy_context_clear(C, &gilstate);
239
240         return ret_flag;
241 }
242
243 static int PYTHON_OT_invoke(bContext *C, wmOperator *op, wmEvent *event)
244 {
245         return PYTHON_OT_generic(PYOP_INVOKE, C, op->type, op, event, NULL);
246 }
247
248 static int PYTHON_OT_execute(bContext *C, wmOperator *op)
249 {
250         return PYTHON_OT_generic(PYOP_EXEC, C, op->type, op, NULL, NULL);
251 }
252
253 static int PYTHON_OT_poll(bContext *C, wmOperatorType *ot)
254 {
255         return PYTHON_OT_generic(PYOP_POLL, C, ot, NULL, NULL, NULL);
256 }
257
258 static void PYTHON_OT_draw(bContext *C, wmOperator *op, uiLayout *layout)
259 {
260         PYTHON_OT_generic(PYOP_DRAW, C, op->type, op, NULL, layout);
261 }
262
263 void PYTHON_OT_wrapper(wmOperatorType *ot, void *userdata)
264 {
265         PyObject *py_class = (PyObject *)userdata;
266         PyObject *item;
267
268         /* identifiers */
269         item= PyObject_GetAttrString(py_class, PYOP_ATTR_IDNAME_BL);
270         ot->idname= _PyUnicode_AsString(item);
271         Py_DECREF(item);
272
273         item= PyObject_GetAttrString(py_class, PYOP_ATTR_UINAME);
274         if (item) {
275                 ot->name= _PyUnicode_AsString(item);
276                 Py_DECREF(item);
277         }
278         else {
279                 ot->name= ot->idname;
280                 PyErr_Clear();
281         }
282
283         item= PyObject_GetAttrString(py_class, PYOP_ATTR_DESCRIPTION);
284         ot->description= (item && PyUnicode_Check(item)) ? _PyUnicode_AsString(item):"undocumented python operator";
285         Py_XDECREF(item);
286         
287         /* api callbacks, detailed checks dont on adding */ 
288         if (PyObject_HasAttrString(py_class, "invoke"))
289                 ot->invoke= PYTHON_OT_invoke;
290         //else
291         //      ot->invoke= WM_operator_props_popup; /* could have an option for standard invokes */
292
293         if (PyObject_HasAttrString(py_class, "execute"))
294                 ot->exec= PYTHON_OT_execute;
295         if (PyObject_HasAttrString(py_class, "poll"))
296                 ot->pyop_poll= PYTHON_OT_poll;
297         if (PyObject_HasAttrString(py_class, "draw"))
298                 ot->ui= PYTHON_OT_draw;
299         
300         ot->pyop_data= userdata;
301         
302         /* flags */
303         ot->flag= 0;
304
305         item= PyObject_GetAttrString(py_class, PYOP_ATTR_REGISTER);
306         if (item) {
307                 ot->flag |= PyObject_IsTrue(item)!=0 ? OPTYPE_REGISTER:0;
308                 Py_DECREF(item);
309         }
310         else {
311                 PyErr_Clear();
312         }
313         item= PyObject_GetAttrString(py_class, PYOP_ATTR_UNDO);
314         if (item) {
315                 ot->flag |= PyObject_IsTrue(item)!=0 ? OPTYPE_UNDO:0;
316                 Py_DECREF(item);
317         }
318         else {
319                 PyErr_Clear();
320         }
321
322         /* Can't use this because it returns a dict proxy
323          *
324          * item= PyObject_GetAttrString(py_class, "__dict__");
325          */
326         item= ((PyTypeObject*)py_class)->tp_dict;
327         if(item) {
328                 /* only call this so pyrna_deferred_register_props gives a useful error
329                  * WM_operatortype_append_ptr will call RNA_def_struct_identifier
330                  * later */
331                 RNA_def_struct_identifier(ot->srna, ot->idname);
332
333                 if(pyrna_deferred_register_props(ot->srna, item)!=0) {
334                         /* failed to register operator props */
335                         PyErr_Print();
336                         PyErr_Clear();
337
338                 }
339         }
340         else {
341                 PyErr_Clear();
342         }
343 }
344
345 void PYTHON_OT_MACRO_wrapper(wmOperatorType *ot, void *userdata)
346 {
347         PyObject *py_class = (PyObject *)userdata;
348         PyObject *item;
349
350         /* identifiers */
351         item= PyObject_GetAttrString(py_class, PYOP_ATTR_IDNAME_BL);
352         ot->idname= _PyUnicode_AsString(item);
353         Py_DECREF(item);
354
355         item= PyObject_GetAttrString(py_class, PYOP_ATTR_UINAME);
356         if (item) {
357                 ot->name= _PyUnicode_AsString(item);
358                 Py_DECREF(item);
359         }
360         else {
361                 ot->name= ot->idname;
362                 PyErr_Clear();
363         }
364
365         item= PyObject_GetAttrString(py_class, PYOP_ATTR_DESCRIPTION);
366         ot->description= (item && PyUnicode_Check(item)) ? _PyUnicode_AsString(item):"undocumented python operator";
367         Py_XDECREF(item);
368
369         if (PyObject_HasAttrString(py_class, "poll"))
370                 ot->pyop_poll= PYTHON_OT_poll;
371         if (PyObject_HasAttrString(py_class, "draw"))
372                 ot->ui= PYTHON_OT_draw;
373
374         ot->pyop_data= userdata;
375
376         /* flags */
377         ot->flag= OPTYPE_MACRO; /* macro at least */
378
379         item= PyObject_GetAttrString(py_class, PYOP_ATTR_REGISTER);
380         if (item) {
381                 ot->flag |= PyObject_IsTrue(item)!=0 ? OPTYPE_REGISTER:0;
382                 Py_DECREF(item);
383         }
384         else {
385                 PyErr_Clear();
386         }
387         item= PyObject_GetAttrString(py_class, PYOP_ATTR_UNDO);
388         if (item) {
389                 ot->flag |= PyObject_IsTrue(item)!=0 ? OPTYPE_UNDO:0;
390                 Py_DECREF(item);
391         }
392         else {
393                 PyErr_Clear();
394         }
395
396         /* Can't use this because it returns a dict proxy
397          *
398          * item= PyObject_GetAttrString(py_class, "__dict__");
399          */
400         item= ((PyTypeObject*)py_class)->tp_dict;
401         if(item) {
402                 /* only call this so pyrna_deferred_register_props gives a useful error
403                  * WM_operatortype_append_macro_ptr will call RNA_def_struct_identifier
404                  * later */
405                 RNA_def_struct_identifier(ot->srna, ot->idname);
406
407                 if(pyrna_deferred_register_props(ot->srna, item)!=0) {
408                         /* failed to register operator props */
409                         PyErr_Print();
410                         PyErr_Clear();
411
412                 }
413         }
414         else {
415                 PyErr_Clear();
416         }
417 }
418
419
420 /* pyOperators - Operators defined IN Python */
421 PyObject *PYOP_wrap_add(PyObject *self, PyObject *py_class)
422 {       
423         PyObject *base_class, *item;
424         wmOperatorType *ot;
425         
426         
427         char *idname= NULL;
428         char idname_bl[OP_MAX_TYPENAME]; /* converted to blender syntax */
429
430         static struct BPY_class_attr_check pyop_class_attr_values[]= {
431                 {PYOP_ATTR_IDNAME,              's', -1, OP_MAX_TYPENAME-3,     0}, /* -3 because a.b -> A_OT_b */
432                 {PYOP_ATTR_UINAME,              's', -1,-1,     BPY_CLASS_ATTR_OPTIONAL},
433                 {PYOP_ATTR_DESCRIPTION, 's', -1,-1,     BPY_CLASS_ATTR_NONE_OK},
434                 {"execute",                             'f', 2, -1, BPY_CLASS_ATTR_OPTIONAL},
435                 {"invoke",                              'f', 3, -1, BPY_CLASS_ATTR_OPTIONAL},
436                 {"poll",                                'f', 2, -1, BPY_CLASS_ATTR_OPTIONAL},
437                 {"draw",                                'f', 2, -1, BPY_CLASS_ATTR_OPTIONAL},
438                 {NULL, 0, 0, 0}
439         };
440
441         // in python would be...
442         //PyObject *optype = PyObject_GetAttrString(PyObject_GetAttrString(PyDict_GetItemString(PyEval_GetGlobals(), "bpy"), "types"), "Operator");
443
444         //PyObject bpy_mod= PyDict_GetItemString(PyEval_GetGlobals(), "bpy");
445         PyObject *bpy_mod= PyImport_ImportModuleLevel("bpy", NULL, NULL, NULL, 0);
446         base_class = PyObject_GetAttrStringArgs(bpy_mod, 2, "types", "Operator");
447         Py_DECREF(bpy_mod);
448
449         if(BPY_class_validate("Operator", py_class, base_class, pyop_class_attr_values, NULL) < 0) {
450                 return NULL; /* BPY_class_validate sets the error */
451         }
452         Py_DECREF(base_class);
453
454         /* class name is used for operator ID - this can be changed later if we want */
455         item= PyObject_GetAttrString(py_class, PYOP_ATTR_IDNAME);
456         idname =  _PyUnicode_AsString(item);
457
458
459         /* annoying conversion! */
460         WM_operator_bl_idname(idname_bl, idname);
461         Py_DECREF(item);
462
463         item= PyUnicode_FromString(idname_bl);
464         PyObject_SetAttrString(py_class, PYOP_ATTR_IDNAME_BL, item);
465         idname =  _PyUnicode_AsString(item);
466         Py_DECREF(item);
467         /* end annoying conversion! */
468
469         
470         /* remove if it already exists */
471         if ((ot=WM_operatortype_exists(idname))) {
472                 if(ot->pyop_data) {
473                         Py_XDECREF((PyObject*)ot->pyop_data);
474                 }
475                 WM_operatortype_remove(idname);
476         }
477         
478         Py_INCREF(py_class);
479         WM_operatortype_append_ptr(PYTHON_OT_wrapper, py_class);
480
481         Py_RETURN_NONE;
482 }
483
484 /* pyOperators - Macro Operators defined IN Python */
485 PyObject *PYOP_wrap_add_macro(PyObject *self, PyObject *py_class)
486 {
487         PyObject *base_class, *item;
488         wmOperatorType *ot;
489
490
491         char *idname= NULL;
492         char idname_bl[OP_MAX_TYPENAME]; /* converted to blender syntax */
493
494         static struct BPY_class_attr_check pyop_class_attr_values[]= {
495                 {PYOP_ATTR_IDNAME,              's', -1, OP_MAX_TYPENAME-3,     0}, /* -3 because a.b -> A_OT_b */
496                 {PYOP_ATTR_UINAME,              's', -1,-1,     BPY_CLASS_ATTR_OPTIONAL},
497                 {PYOP_ATTR_DESCRIPTION, 's', -1,-1,     BPY_CLASS_ATTR_NONE_OK},
498                 {"poll",                                'f', 2, -1, BPY_CLASS_ATTR_OPTIONAL},
499                 {"draw",                                'f', 2, -1, BPY_CLASS_ATTR_OPTIONAL},
500                 {NULL, 0, 0, 0}
501         };
502
503         //PyObject bpy_mod= PyDict_GetItemString(PyEval_GetGlobals(), "bpy");
504         PyObject *bpy_mod= PyImport_ImportModuleLevel("bpy", NULL, NULL, NULL, 0);
505         base_class = PyObject_GetAttrStringArgs(bpy_mod, 2, "types", "Macro");
506         Py_DECREF(bpy_mod);
507
508         if(BPY_class_validate("Macro", py_class, base_class, pyop_class_attr_values, NULL) < 0) {
509                 return NULL; /* BPY_class_validate sets the error */
510         }
511         Py_DECREF(base_class);
512
513         /* class name is used for operator ID - this can be changed later if we want */
514         item= PyObject_GetAttrString(py_class, PYOP_ATTR_IDNAME);
515         idname =  _PyUnicode_AsString(item);
516
517
518         /* annoying conversion! */
519         WM_operator_bl_idname(idname_bl, idname);
520         Py_DECREF(item);
521
522         item= PyUnicode_FromString(idname_bl);
523         PyObject_SetAttrString(py_class, PYOP_ATTR_IDNAME_BL, item);
524         idname =  _PyUnicode_AsString(item);
525         Py_DECREF(item);
526         /* end annoying conversion! */
527
528
529         /* remove if it already exists */
530         if ((ot=WM_operatortype_exists(idname))) {
531                 if(ot->pyop_data) {
532                         Py_XDECREF((PyObject*)ot->pyop_data);
533                 }
534                 WM_operatortype_remove(idname);
535         }
536
537         Py_INCREF(py_class);
538         WM_operatortype_append_macro_ptr(PYTHON_OT_MACRO_wrapper, py_class);
539
540         Py_RETURN_NONE;
541 }
542
543 PyObject *PYOP_wrap_macro_define(PyObject *self, PyObject *args)
544 {
545         wmOperatorType *ot;
546         wmOperatorTypeMacro *otmacro;
547         PyObject *macro;
548         PyObject *item;
549         PointerRNA ptr_otmacro;
550
551         char *opname;
552         char *macroname;
553
554         if (!PyArg_ParseTuple(args, "Os:_bpy.ops.macro_define", &macro, &opname))
555                 return NULL;
556
557         if (WM_operatortype_exists(opname) == NULL) {
558                 PyErr_Format(PyExc_ValueError, "Macro Define: '%s' is not a valid operator id", opname);
559                 return NULL;
560         }
561
562         /* identifiers */
563         item= PyObject_GetAttrString(macro, PYOP_ATTR_IDNAME_BL);
564
565         if (!item) {
566                 item= PyObject_GetAttrString(macro, PYOP_ATTR_IDNAME);
567
568                 if (!item) {
569                         PyErr_Format(PyExc_ValueError, "Macro Define: not a valid Macro class");
570                 } else {
571                         macroname= _PyUnicode_AsString(item);
572                         PyErr_Format(PyExc_ValueError, "Macro Define: '%s' hasn't been registered yet", macroname);
573                 }
574                 return NULL;
575         }
576
577         macroname= _PyUnicode_AsString(item);
578
579         ot = WM_operatortype_exists(macroname);
580
581         if (!ot) {
582                 PyErr_Format(PyExc_ValueError, "Macro Define: '%s' is not a valid macro or hasn't been registered yet", macroname);
583                 return NULL;
584         }
585
586         otmacro = WM_operatortype_macro_define(ot, opname);
587
588         RNA_pointer_create(NULL, &RNA_OperatorTypeMacro, otmacro, &ptr_otmacro);
589
590         return pyrna_struct_CreatePyObject(&ptr_otmacro);
591 }
592
593
594 PyObject *PYOP_wrap_remove(PyObject *self, PyObject *value)
595 {
596         PyObject *py_class;
597         char *idname= NULL;
598         wmOperatorType *ot;
599         
600
601         if (PyUnicode_Check(value))
602                 idname = _PyUnicode_AsString(value);
603         else if (PyCFunction_Check(value)) {
604                 PyObject *cfunc_self = PyCFunction_GetSelf(value);
605                 if (cfunc_self)
606                         idname = _PyUnicode_AsString(cfunc_self);
607         }
608         
609         if (idname==NULL) {
610                 PyErr_SetString( PyExc_ValueError, "Expected the operator name as a string or the operator function");
611                 return NULL;
612         }
613
614         if (!(ot= WM_operatortype_exists(idname))) {
615                 PyErr_Format( PyExc_AttributeError, "Operator \"%s\" does not exists, cant remove", idname);
616                 return NULL;
617         }
618         
619         if (!(py_class= (PyObject *)ot->pyop_data)) {
620                 PyErr_Format( PyExc_AttributeError, "Operator \"%s\" was not created by python", idname);
621                 return NULL;
622         }
623         
624         Py_XDECREF(py_class);
625
626         WM_operatortype_remove(idname);
627
628         Py_RETURN_NONE;
629 }