python support for reporting with operators.
authorCampbell Barton <ideasman42@gmail.com>
Fri, 2 Jan 2009 07:54:38 +0000 (07:54 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Fri, 2 Jan 2009 07:54:38 +0000 (07:54 +0000)
* errors in python called operators are raised as errors
* Python defined operators errors are reported as errors (not full traceback yet)
* added BKE_reports_string, same as BKE_reports_print but it returns a string rather then printing it.
* WM_operator_name_call optionally takes an initialized report struct

12 files changed:
source/blender/blenkernel/BKE_report.h
source/blender/blenkernel/intern/report.c
source/blender/editors/interface/interface_handlers.c
source/blender/editors/interface/interface_regions.c
source/blender/editors/space_action/action_header.c
source/blender/editors/space_node/node_header.c
source/blender/editors/space_view3d/view3d_header.c
source/blender/python/epy_doc_gen.py
source/blender/python/intern/bpy_operator.c
source/blender/python/intern/bpy_opwrapper.c
source/blender/windowmanager/WM_api.h
source/blender/windowmanager/intern/wm_event_system.c

index 8a5c623a225e8c8388d3c2c4adc6bd717461fc94..21221026b8b3bcfccf4997139d61bc0f0cc59d8b 100644 (file)
@@ -80,6 +80,7 @@ void BKE_report_print_level_set(ReportList *reports, ReportType level);
 ReportType BKE_report_store_level(ReportList *reports);
 void BKE_report_store_level_set(ReportList *reports, ReportType level);
 
+char *BKE_reports_string(ReportList *reports, ReportType level);
 void BKE_reports_print(ReportList *reports, ReportType level);
 
 #ifdef __cplusplus
index 97bbaf66b3ab4ff21eeb1a294c400ccb1fc65157..5ba21529c5c399215578c69f3e179e74ec55cccc 100644 (file)
@@ -215,17 +215,37 @@ void BKE_report_store_level_set(ReportList *reports, ReportType level)
        reports->storelevel= level;
 }
 
-void BKE_reports_print(ReportList *reports, ReportType level)
+char *BKE_reports_string(ReportList *reports, ReportType level)
 {
        Report *report;
+       DynStr *ds;
+       char *cstring;
 
        if(!reports)
-               return;
-       
+               return NULL;
+
+       ds= BLI_dynstr_new();
        for(report=reports->list.first; report; report=report->next)
                if(report->type >= level)
-                       printf("%s: %s\n", report->typestr, report->message);
+                       BLI_dynstr_appendf(ds, "%s: %s\n", report->typestr, report->message);
+
+       if (BLI_dynstr_get_len(ds))
+               cstring= BLI_dynstr_get_cstring(ds);
+       else
+               cstring= NULL;
 
+       BLI_dynstr_free(ds);
+       return cstring;
+}
+
+void BKE_reports_print(ReportList *reports, ReportType level)
+{
+       char *cstring = BKE_reports_string(reports, level);
+       
+       if (cstring == NULL)
+               return;
+       
+       printf(cstring);
        fflush(stdout);
 }
 
index 55e7e297b3f945b22cd74cb32afdb856a7ff2cbe..432d722dd6296b28003f6697dbdd38de5722af2a 100644 (file)
@@ -222,7 +222,7 @@ static void ui_apply_but_funcs_after(bContext *C)
                        after->butm_func(C, after->butm_func_arg, after->a2);
 
                if(after->opname)
-                       WM_operator_name_call(C, after->opname, after->opcontext, after->opptr);
+                       WM_operator_name_call(C, after->opname, after->opcontext, after->opptr, NULL);
                if(after->opptr) {
                        WM_operator_properties_free(after->opptr);
                        MEM_freeN(after->opptr);
index 72a0fd811d04aab7f512a9e17c46e5813ef7016b..d32cad9256903df787f265fc60aaad87f9d6031d 100644 (file)
@@ -1690,7 +1690,7 @@ static void operator_cb(bContext *C, void *arg, int retval)
        const char *opname= arg;
 
        if(opname && retval > 0)
-               WM_operator_name_call(C, opname, WM_OP_EXEC_DEFAULT, NULL);
+               WM_operator_name_call(C, opname, WM_OP_EXEC_DEFAULT, NULL, NULL);
 }
 
 static void vconfirm(bContext *C, char *opname, char *title, char *itemfmt, va_list ap)
index 406c9bf2147f83440add7acac12b2748b581620c..e0e9a4d7a181247ad0a6ce7203406a162c945ea7 100644 (file)
@@ -463,10 +463,10 @@ static void do_action_buttons(bContext *C, void *arg, int event)
                        break;
                        
                case B_ACTCOPYKEYS:
-                       WM_operator_name_call(C, "ACT_OT_keyframes_copy", WM_OP_EXEC_REGION_WIN, NULL);
+                       WM_operator_name_call(C, "ACT_OT_keyframes_copy", WM_OP_EXEC_REGION_WIN, NULL, NULL);
                        break;
                case B_ACTPASTEKEYS:
-                       WM_operator_name_call(C, "ACT_OT_keyframes_paste", WM_OP_EXEC_REGION_WIN, NULL);
+                       WM_operator_name_call(C, "ACT_OT_keyframes_paste", WM_OP_EXEC_REGION_WIN, NULL, NULL);
                        break;
        }
 }
index 7f818532301a95e2333dec16cfd8b1fd4f94077a..7191bb2214c7db82eda5c15879a5cbe48c8e5728 100644 (file)
@@ -592,13 +592,13 @@ static void do_node_viewmenu(bContext *C, void *arg, int event)
        
        switch(event) {
                case 1: /* Zoom in */
-                       WM_operator_name_call(C, "View2D_OT_view_zoomin", WM_OP_EXEC_REGION_WIN, NULL);
+                       WM_operator_name_call(C, "View2D_OT_view_zoomin", WM_OP_EXEC_REGION_WIN, NULL, NULL);
                        break;
                case 2: /* View all */
-                       WM_operator_name_call(C, "View2D_OT_view_zoomout", WM_OP_EXEC_REGION_WIN, NULL);
+                       WM_operator_name_call(C, "View2D_OT_view_zoomout", WM_OP_EXEC_REGION_WIN, NULL, NULL);
                        break;
                case 3: /* View all */
-                       WM_operator_name_call(C, "NODE_OT_fit_all", WM_OP_EXEC_REGION_WIN, NULL);
+                       WM_operator_name_call(C, "NODE_OT_fit_all", WM_OP_EXEC_REGION_WIN, NULL, NULL);
                        break;
                case 4: /* Grease Pencil */
                        // XXX add_blockhandler(sa, NODES_HANDLER_GREASEPENCIL, UI_PNL_UNSTOW);
index 1bb452cffb664446677d5e87351e99bb273466cc..06eb00d75c8db8bd53da8501b349ef0d48360af2 100644 (file)
@@ -443,7 +443,7 @@ static void do_view3d_view_alignviewmenu(bContext *C, void *arg, int event)
 // XXX         mainqenter(PADASTERKEY, 1);
                break;
        case 6: /* Center View and Cursor to Origin */
-               WM_operator_name_call(C, "VIEW3D_OT_viewcenter", WM_OP_EXEC_REGION_WIN, NULL);
+               WM_operator_name_call(C, "VIEW3D_OT_viewcenter", WM_OP_EXEC_REGION_WIN, NULL, NULL);
                curs= give_cursor(scene, v3d);
                curs[0]=curs[1]=curs[2]= 0.0;
                break;
@@ -528,10 +528,10 @@ static void do_view3d_viewmenu(bContext *C, void *arg, int event)
                endlocalview(scene, sa);
                break;
        case 9: /* View All (Home) */
-               WM_operator_name_call(C, "VIEW3D_OT_viewhome", WM_OP_EXEC_REGION_WIN, NULL);
+               WM_operator_name_call(C, "VIEW3D_OT_viewhome", WM_OP_EXEC_REGION_WIN, NULL, NULL);
                break;
        case 11: /* View Selected */
-               WM_operator_name_call(C, "VIEW3D_OT_viewcenter", WM_OP_EXEC_REGION_WIN, NULL);
+               WM_operator_name_call(C, "VIEW3D_OT_viewcenter", WM_OP_EXEC_REGION_WIN, NULL, NULL);
                break;
        case 13: /* Play Back Animation */
                play_anim(0);
@@ -543,7 +543,7 @@ static void do_view3d_viewmenu(bContext *C, void *arg, int event)
                add_blockhandler(sa, VIEW3D_HANDLER_PROPERTIES, UI_PNL_UNSTOW);
                break;
        case 17: /* Set Clipping Border */
-               WM_operator_name_call(C, "VIEW3D_OT_clipping", WM_OP_INVOKE_REGION_WIN, NULL);
+               WM_operator_name_call(C, "VIEW3D_OT_clipping", WM_OP_INVOKE_REGION_WIN, NULL, NULL);
                break;
        case 18: /* render preview */
                toggle_blockhandler(sa, VIEW3D_HANDLER_PREVIEW, 0);
@@ -5317,7 +5317,7 @@ static void do_view3d_buttons(bContext *C, void *arg, int event)
 
        switch(event) {
        case B_HOME:
-               WM_operator_name_call(C, "VIEW3D_OT_viewhome", WM_OP_EXEC_REGION_WIN, NULL);
+               WM_operator_name_call(C, "VIEW3D_OT_viewhome", WM_OP_EXEC_REGION_WIN, NULL, NULL);
                break;
        case B_SCENELOCK:
                if(v3d->scenelock) {
index 77b0c245dbd80aa5b3678e6c6117b38837ff5a1d..9e0c6127a4c60b71495c1d47ce7dc3cb55b00fce 100644 (file)
@@ -86,8 +86,8 @@ def rna2epy(target_path):
                        
                        array_str = get_array_str(length)
                        
-                       if rna_prop.readonly:   readonly_str = ' (readonly)'
-                       else:                           readonly_str = ''
+                       if rna_prop.editable:   readonly_str = ''
+                       else:                           readonly_str = ' (readonly)'
                        
                        if rna_prop_ptr: # Use the pointer type
                                out.write('\t@ivar %s: %s\n' %  (rna_prop_identifier, rna_desc))
index cc87fd0704eb404ab44ec981d3eb7f3c04bbf615..061c43c4773f37055c74708f99bca4c813f97468 100644 (file)
@@ -35,7 +35,8 @@
 #include "WM_types.h"
 
 #include "MEM_guardedalloc.h"
-#include "BKE_idprop.h"
+//#include "BKE_idprop.h"
+#include "BKE_report.h"
 
 extern ListBase global_ops; /* evil, temp use */
 
@@ -168,7 +169,7 @@ PyObject *pyop_func_get_rna(BPy_OperatorFunc *self)
 }
 
 static PyGetSetDef pyop_func_getseters[] = {
-       {"rna", (getter)pyop_func_get_rna, (setter)NULL, "vertex's coordinate", NULL},
+       {"rna", (getter)pyop_func_get_rna, (setter)NULL, "Operator RNA properties", NULL},
        {NULL,NULL,NULL,NULL,NULL}  /* Sentinel */
 };
 
@@ -178,7 +179,8 @@ static PyObject * pyop_func_call(BPy_OperatorFunc * self, PyObject *args, PyObje
 
        int error_val = 0;
        PointerRNA ptr;
-       
+       char *report_str= NULL;
+
        if (PyTuple_Size(args)) {
                PyErr_SetString( PyExc_AttributeError, "All operator args must be keywords");
                return NULL;
@@ -195,7 +197,22 @@ static PyObject * pyop_func_call(BPy_OperatorFunc * self, PyObject *args, PyObje
        error_val= PYOP_props_from_dict(&ptr, kw);
        
        if (error_val==0) {
-               WM_operator_name_call(self->C, self->name, WM_OP_EXEC_DEFAULT, &ptr);
+               ReportList reports;
+
+               BKE_reports_init(&reports, RPT_STORE);
+
+               WM_operator_name_call(self->C, self->name, WM_OP_EXEC_DEFAULT, &ptr, &reports);
+
+               report_str= BKE_reports_string(&reports, RPT_ERROR);
+
+               if (report_str) {
+                       PyErr_SetString(PyExc_SystemError, report_str);
+                       MEM_freeN(report_str);
+                       error_val = -1;
+               }
+
+               if (reports.list.first)
+                       BKE_reports_clear(&reports);
        }
 
        WM_operator_properties_free(&ptr);
index 000bec3b675b061667252764d722473d56c3d12d..8a644f51b2469b9ab97912082d03397432bb96cc 100644 (file)
@@ -27,6 +27,7 @@
 #include "bpy_opwrapper.h"
 #include "BLI_listbase.h"
 #include "BKE_context.h"
+#include "BKE_report.h"
 #include "DNA_windowmanager_types.h"
 #include "MEM_guardedalloc.h"
 #include "WM_api.h"
@@ -168,6 +169,19 @@ static PyObject *pyop_dict_from_event(wmEvent *event)
        return dict;
 }
 
+/* TODO - a whole traceback would be ideal */
+static void pyop_error_report(ReportList *reports)
+{
+       PyObject *exception, *v, *tb;
+       PyErr_Fetch(&exception, &v, &tb);
+       if (exception == NULL)
+               return;
+       /* Now we know v != NULL too */
+       BKE_report(reports, RPT_ERROR, _PyUnicode_AsString(v));
+       
+       PyErr_Print();
+}
+
 static struct BPY_flag_def pyop_ret_flags[] = {
        {"RUNNING_MODAL", OPERATOR_RUNNING_MODAL},
        {"CANCELLED", OPERATOR_CANCELLED},
@@ -188,12 +202,12 @@ static int PYTHON_OT_exec(bContext *C, wmOperator *op)
        ret = PyObject_Call(pyot->py_exec, args, kw);
 
        if (ret == NULL) {
-               PyErr_Print();
+               pyop_error_report(op->reports);
        }
        else {
                if (BPY_flag_from_seq(pyop_ret_flags, ret, &ret_flag) == -1) {
                         /* the returned value could not be converted into a flag */
-                       PyErr_Print();
+                       pyop_error_report(op->reports);
                }
        }
 
@@ -232,12 +246,12 @@ static int PYTHON_OT_invoke(bContext *C, wmOperator *op, wmEvent *event)
        ret = PyObject_Call(pyot->py_invoke, args, NULL);
 
        if (ret == NULL) {
-               PyErr_Print();
+               pyop_error_report(op->reports);
        }
        else {
                if (BPY_flag_from_seq(pyop_ret_flags, ret, &ret_flag) == -1) {
                         /* the returned value could not be converted into a flag */
-                       PyErr_Print();
+                       pyop_error_report(op->reports);
                }
                /* there is no need to copy the py keyword dict modified by
                 * pyot->py_invoke(), back to the operator props since they are just
index 8ec6078e1d90b59ffd4de2d151710c129c61f678..f5cf17d6857808d7e4bf5b1d1e8c82131cbc056d 100644 (file)
@@ -123,7 +123,7 @@ void                WM_operatortype_append_ptr      (void (*opfunc)(wmOperatorType*, void *), void
 int                    WM_operatortype_remove(const char *idname);
 
 int                    WM_operator_call                (struct bContext *C, struct wmOperator *op);
-int         WM_operator_name_call      (struct bContext *C, const char *opstring, int context, struct PointerRNA *properties);
+int         WM_operator_name_call      (struct bContext *C, const char *opstring, int context, struct PointerRNA *properties, struct ReportList *reports);
 
 void           WM_operator_properties_create(struct PointerRNA *ptr, const char *opstring);
 void           WM_operator_properties_free(struct PointerRNA *ptr);
index 6dffc0ff29e2016c41d137fc3b08a8882e0ef9a9..f7bb9877124a2ebfe0b5a80db3bd3109d4b1aaa9 100644 (file)
@@ -355,7 +355,7 @@ int WM_operator_call(bContext *C, wmOperator *op)
        return retval;
 }
 
-static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, PointerRNA *properties)
+static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, PointerRNA *properties, ReportList *reports)
 {
        wmWindowManager *wm= CTX_wm_manager(C);
        int retval= OPERATOR_PASS_THROUGH;
@@ -372,8 +372,13 @@ static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, P
                        op->ptr->data= IDP_CopyProperty(properties->data);
                RNA_pointer_create(&RNA_WindowManager, &wm->id, ot->srna, op->ptr->data, op->ptr);
 
-               op->reports= MEM_callocN(sizeof(ReportList), "wmOperatorReportList");
-               BKE_reports_init(op->reports, RPT_STORE);
+               if (reports) {
+                       op->reports= reports; /* must be initialized alredy */
+               }
+               else {
+                       op->reports= MEM_mallocN(sizeof(ReportList), "wmOperatorReportList");
+                       BKE_reports_init(op->reports, RPT_STORE);
+               }
 
                if(op->type->invoke && event)
                        retval= (*op->type->invoke)(C, op, event);
@@ -386,13 +391,15 @@ static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, P
                        WM_operator_print(op);
 
                if(!(retval & OPERATOR_RUNNING_MODAL))
-                       if(op->reports->list.first)
+                       if(reports==NULL && op->reports->list.first) /* only show the report if the report list was not given in the function */
                                uiPupmenuReports(C, op->reports);
 
                if((retval & OPERATOR_FINISHED) && (ot->flag & OPTYPE_REGISTER)) {
                        wm_operator_register(wm, op);
                }
                else if(!(retval & OPERATOR_RUNNING_MODAL)) {
+                       if (reports)
+                               op->reports= NULL; /* dont let the operator free reports given by the user */
                        WM_operator_free(op);
                }
        }
@@ -401,7 +408,7 @@ static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, P
 }
 
 /* invokes operator in context */
-int WM_operator_name_call(bContext *C, const char *opstring, int context, PointerRNA *properties)
+int WM_operator_name_call(bContext *C, const char *opstring, int context, PointerRNA *properties, ReportList *reports)
 {
        wmOperatorType *ot= WM_operatortype_find(opstring);
        wmWindow *window= CTX_wm_window(C);
@@ -431,7 +438,7 @@ int WM_operator_name_call(bContext *C, const char *opstring, int context, Pointe
                                                CTX_wm_region_set(C, ar1);
                                }
                                
-                               retval= wm_operator_invoke(C, ot, event, properties);
+                               retval= wm_operator_invoke(C, ot, event, properties, reports);
                                
                                /* set region back */
                                CTX_wm_region_set(C, ar);
@@ -446,7 +453,7 @@ int WM_operator_name_call(bContext *C, const char *opstring, int context, Pointe
                                ARegion *ar= CTX_wm_region(C);
 
                                CTX_wm_region_set(C, NULL);
-                               retval= wm_operator_invoke(C, ot, event, properties);
+                               retval= wm_operator_invoke(C, ot, event, properties, reports);
                                CTX_wm_region_set(C, ar);
 
                                return retval;
@@ -461,7 +468,7 @@ int WM_operator_name_call(bContext *C, const char *opstring, int context, Pointe
 
                                CTX_wm_region_set(C, NULL);
                                CTX_wm_area_set(C, NULL);
-                               retval= wm_operator_invoke(C, ot, window->eventstate, properties);
+                               retval= wm_operator_invoke(C, ot, window->eventstate, properties, reports);
                                CTX_wm_region_set(C, ar);
                                CTX_wm_area_set(C, area);
 
@@ -470,7 +477,7 @@ int WM_operator_name_call(bContext *C, const char *opstring, int context, Pointe
                        case WM_OP_EXEC_DEFAULT:
                                event= NULL;    /* pass on without break */
                        case WM_OP_INVOKE_DEFAULT:
-                               return wm_operator_invoke(C, ot, event, properties);
+                               return wm_operator_invoke(C, ot, event, properties, reports);
                }
        }
        
@@ -665,7 +672,7 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand
                wmOperatorType *ot= WM_operatortype_find(event->keymap_idname);
 
                if(ot)
-                       retval= wm_operator_invoke(C, ot, event, properties);
+                       retval= wm_operator_invoke(C, ot, event, properties, NULL);
        }
 
        if(retval & OPERATOR_PASS_THROUGH)