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:
parent
cf43c6b0a1
commit
5d23eaa8f4
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user