python support for reporting with operators.

* 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
This commit is contained in:
Campbell Barton 2009-01-02 07:54:38 +00:00
parent cf43c6b0a1
commit 5d23eaa8f4
12 changed files with 96 additions and 37 deletions

@ -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

@ -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);
}

@ -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);

@ -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)

@ -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;
}
}

@ -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);

@ -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) {

@ -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))

@ -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);

@ -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

@ -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);

@ -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)