Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCampbell Barton <ideasman42@gmail.com>2009-06-14 16:53:47 +0400
committerCampbell Barton <ideasman42@gmail.com>2009-06-14 16:53:47 +0400
commit8ab7fbe79563895b38bcfc50625e19fa2b38f843 (patch)
treeb161a037474a34fabcbcaa4dc80600bf28bf536d
parentc3c38155ad2aca369fa956b2251ed41c749942cc (diff)
Blender/Python API
Send the full python stack trace to the reporting api, added BPY_exception_buffer which temporarily overrides sys.stdout and sys.stderr to get the output (uses the io module in py3 StringIO in py2 to avoid writing into a real file), pity the Py/C api has no function to do this. fix for crash when showing menu's that have no items.
-rw-r--r--source/blender/editors/interface/interface_regions.c3
-rw-r--r--source/blender/editors/space_script/script_edit.c10
-rw-r--r--source/blender/editors/space_text/text_ops.c2
-rw-r--r--source/blender/python/BPY_extern.h2
-rw-r--r--source/blender/python/intern/bpy_interface.c18
-rw-r--r--source/blender/python/intern/bpy_operator_wrap.c54
-rw-r--r--source/blender/python/intern/bpy_util.c102
-rw-r--r--source/blender/python/intern/bpy_util.h3
-rw-r--r--source/creator/creator.c4
9 files changed, 130 insertions, 68 deletions
diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c
index 7ccb6c5163b..32bcae77e6b 100644
--- a/source/blender/editors/interface/interface_regions.c
+++ b/source/blender/editors/interface/interface_regions.c
@@ -1948,6 +1948,9 @@ uiBlock *ui_block_func_PUPMENU(bContext *C, uiPopupBlockHandle *handle, void *ar
md= decompose_menu_string(info->instr);
rows= md->nitems;
+ if(rows<1)
+ rows= 1;
+
columns= 1;
/* size and location, title slightly bigger for bold */
diff --git a/source/blender/editors/space_script/script_edit.c b/source/blender/editors/space_script/script_edit.c
index 797302a8652..88b8dccc6c9 100644
--- a/source/blender/editors/space_script/script_edit.c
+++ b/source/blender/editors/space_script/script_edit.c
@@ -62,15 +62,17 @@
static int run_pyfile_exec(bContext *C, wmOperator *op)
{
ARegion *ar= CTX_wm_region(C);
+
char filename[512];
RNA_string_get(op->ptr, "filename", filename);
#ifndef DISABLE_PYTHON
- BPY_run_python_script(C, filename, NULL);
+ if(BPY_run_python_script(C, filename, NULL, op->reports)) {
+ ED_region_tag_redraw(ar);
+ return OPERATOR_FINISHED;
+ }
#endif
- ED_region_tag_redraw(ar);
-
- return OPERATOR_FINISHED;
+ return OPERATOR_CANCELLED; /* FAIL */
}
void SCRIPT_OT_python_file_run(wmOperatorType *ot)
diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c
index ebb42aa2098..f43888b08da 100644
--- a/source/blender/editors/space_text/text_ops.c
+++ b/source/blender/editors/space_text/text_ops.c
@@ -521,7 +521,7 @@ static int run_script_exec(bContext *C, wmOperator *op)
#else
Text *text= CTX_data_edit_text(C);
- if (BPY_run_python_script( C, NULL, text ))
+ if (BPY_run_python_script(C, NULL, text, op->reports))
return OPERATOR_FINISHED;
/* Dont report error messages while live editing */
diff --git a/source/blender/python/BPY_extern.h b/source/blender/python/BPY_extern.h
index ff3e89a6e25..855fdde50c5 100644
--- a/source/blender/python/BPY_extern.h
+++ b/source/blender/python/BPY_extern.h
@@ -97,7 +97,7 @@ extern "C" {
int BPY_menu_invoke( struct BPyMenu *pym, short menutype );
/* 2.5 UI Scripts */
- int BPY_run_python_script( struct bContext *C, const char *filename, struct Text *text ); // 2.5 working
+ int BPY_run_python_script( struct bContext *C, const char *filename, struct Text *text, struct ReportList *reports ); // 2.5 working
int BPY_run_script_space_draw(struct bContext *C, struct SpaceScript * sc); // 2.5 working
void BPY_run_ui_scripts(struct bContext *C, int reload);
// int BPY_run_script_space_listener(struct bContext *C, struct SpaceScript * sc, struct ARegion *ar, struct wmNotifier *wmn); // 2.5 working
diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c
index 7b3a67ebff5..22336bd4f71 100644
--- a/source/blender/python/intern/bpy_interface.c
+++ b/source/blender/python/intern/bpy_interface.c
@@ -150,7 +150,7 @@ void BPY_end_python( void )
}
/* Can run a file or text block */
-int BPY_run_python_script( bContext *C, const char *fn, struct Text *text )
+int BPY_run_python_script( bContext *C, const char *fn, struct Text *text, struct ReportList *reports)
{
PyObject *py_dict, *py_result;
PyGILState_STATE gilstate;
@@ -178,7 +178,7 @@ int BPY_run_python_script( bContext *C, const char *fn, struct Text *text )
MEM_freeN( buf );
if( PyErr_Occurred( ) ) {
- PyErr_Print(); PyErr_Clear();
+ BPy_errors_to_report(reports);
BPY_free_compiled_text( text );
PyGILState_Release(gilstate);
return 0;
@@ -194,7 +194,7 @@ int BPY_run_python_script( bContext *C, const char *fn, struct Text *text )
}
if (!py_result) {
- PyErr_Print(); PyErr_Clear();
+ BPy_errors_to_report(reports);
} else {
Py_DECREF( py_result );
}
@@ -221,7 +221,7 @@ static void exit_pydraw( SpaceScript * sc, short err )
script = sc->script;
if( err ) {
- PyErr_Print(); PyErr_Clear();
+ BPy_errors_to_report(NULL); // TODO, reports
script->flags = 0; /* mark script struct for deletion */
SCRIPT_SET_NULL(script);
script->scriptname[0] = '\0';
@@ -250,7 +250,7 @@ static int bpy_run_script_init(bContext *C, SpaceScript * sc)
return 0;
if (sc->script->py_draw==NULL && sc->script->scriptname[0] != '\0')
- BPY_run_python_script(C, sc->script->scriptname, NULL);
+ BPY_run_python_script(C, sc->script->scriptname, NULL, NULL);
if (sc->script->py_draw==NULL)
return 0;
@@ -329,7 +329,7 @@ int BPY_run_python_script_space(const char *modulename, const char *func)
}
if (!py_result) {
- PyErr_Print(); PyErr_Clear();
+ BPy_errors_to_report(NULL); // TODO - reports
} else
Py_DECREF( py_result );
@@ -410,7 +410,7 @@ void BPY_run_ui_scripts(bContext *C, int reload)
if(mod) {
Py_DECREF(mod); /* could be NULL from reloading */
} else {
- PyErr_Print(); PyErr_Clear();
+ BPy_errors_to_report(NULL); // TODO - reports
fprintf(stderr, "unable to import \"%s\" %s/%s\n", path, dirname, de->d_name);
}
}
@@ -530,7 +530,7 @@ static float pydriver_error(ChannelDriver *driver)
driver->flag |= DRIVER_FLAG_INVALID; /* py expression failed */
fprintf(stderr, "\nError in Driver: The following Python expression failed:\n\t'%s'\n\n", driver->expression);
- PyErr_Print(); PyErr_Clear();
+ BPy_errors_to_report(NULL); // TODO - reports
return 0.0f;
}
@@ -589,7 +589,7 @@ float BPY_pydriver_eval (ChannelDriver *driver)
}
fprintf(stderr, "\tBPY_pydriver_eval() - couldn't add variable '%s' to namespace \n", dtar->name);
- PyErr_Print(); PyErr_Clear();
+ BPy_errors_to_report(NULL); // TODO - reports
}
}
diff --git a/source/blender/python/intern/bpy_operator_wrap.c b/source/blender/python/intern/bpy_operator_wrap.c
index 8cd1bc64f11..9b7893a949b 100644
--- a/source/blender/python/intern/bpy_operator_wrap.c
+++ b/source/blender/python/intern/bpy_operator_wrap.c
@@ -137,54 +137,6 @@ static PyObject *pyop_dict_from_event(wmEvent *event)
return dict;
}
-/* TODO - a whole traceback would be ideal */
-static void pyop_error_report(ReportList *reports)
-{
- const char *string;
- PyObject *exception, *v, *tb;
- PyErr_Fetch(&exception, &v, &tb);
- if (exception == NULL)
- return;
-
- /* get the string from the exception */
- if(v==NULL) {
- string= "py exception not set";
- }
- else if(string = _PyUnicode_AsString(v)) {
- /* do nothing */
- }
- else { /* a valid PyObject but not a string, try get its string value */
- PyObject *repr;
-
- Py_INCREF(v); /* incase clearing the error below somehow frees this */
- PyErr_Clear();
-
- repr= PyObject_Repr(v);
-
- if(repr==NULL) {
- PyErr_Clear();
- string= "py exception found but can't be converted";
- }
- else {
- string = _PyUnicode_AsString(repr);
- Py_DECREF(repr);
-
- if(string==NULL) { /* unlikely to happen */
- PyErr_Clear();
- string= "py exception found but can't be converted";
- }
- }
-
- Py_DECREF(v); /* finished dealing with v, PyErr_Clear isnt called anymore so can decref it */
- }
- /* done getting the string */
-
- /* Now we know v != NULL too */
- BKE_report(reports, RPT_ERROR, string);
-
- PyErr_Print();
-}
-
static struct BPY_flag_def pyop_ret_flags[] = {
{"RUNNING_MODAL", OPERATOR_RUNNING_MODAL},
{"CANCELLED", OPERATOR_CANCELLED},
@@ -291,13 +243,13 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve
}
if (ret == NULL) { /* covers py_class_instance failing too */
- pyop_error_report(op->reports);
+ BPy_errors_to_report(op->reports);
}
else {
if (mode==PYOP_POLL) {
if (PyBool_Check(ret) == 0) {
PyErr_SetString(PyExc_ValueError, "Python poll function return value ");
- pyop_error_report(op->reports);
+ BPy_errors_to_report(op->reports);
}
else {
ret_flag= ret==Py_True ? 1:0;
@@ -305,7 +257,7 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve
} else if (BPY_flag_from_seq(pyop_ret_flags, ret, &ret_flag) == -1) {
/* the returned value could not be converted into a flag */
- pyop_error_report(op->reports);
+ BPy_errors_to_report(op->reports);
}
/* there is no need to copy the py keyword dict modified by
diff --git a/source/blender/python/intern/bpy_util.c b/source/blender/python/intern/bpy_util.c
index c447e7de982..d5b131583dc 100644
--- a/source/blender/python/intern/bpy_util.c
+++ b/source/blender/python/intern/bpy_util.c
@@ -168,6 +168,12 @@ void PyObSpit(char *name, PyObject *var) {
PyObject_Print(var, stderr, 0);
fprintf(stderr, " ref:%d ", var->ob_refcnt);
fprintf(stderr, " ptr:%ld", (long)var);
+
+ fprintf(stderr, " type:");
+ if(Py_TYPE(var))
+ fprintf(stderr, "%s", Py_TYPE(var)->tp_name);
+ else
+ fprintf(stderr, "<NIL>");
}
fprintf(stderr, "\n");
}
@@ -329,6 +335,72 @@ int BPY_class_validate(const char *class_type, PyObject *class, PyObject *base_c
return 0;
}
+
+
+/* returns the exception string as a new PyUnicode object, depends on external StringIO module */
+PyObject *BPY_exception_buffer(void)
+{
+ PyObject *stdout_backup = PySys_GetObject("stdout"); /* borrowed */
+ PyObject *stderr_backup = PySys_GetObject("stderr"); /* borrowed */
+ PyObject *string_io = NULL;
+ PyObject *string_io_buf = NULL;
+ PyObject *string_io_mod;
+ PyObject *string_io_getvalue;
+
+ PyObject *error_type, *error_value, *error_traceback;
+
+ if (!PyErr_Occurred())
+ return NULL;
+
+ PyErr_Fetch(&error_type, &error_value, &error_traceback);
+
+ PyErr_Clear();
+
+ /* import StringIO / io
+ * string_io = StringIO.StringIO()
+ */
+
+#if PY_VERSION_HEX < 0x03000000
+ if(! (string_io_mod= PyImport_ImportModule("StringIO")) ) {
+#else
+ if(! (string_io_mod= PyImport_ImportModule("io")) ) {
+#endif
+ return NULL;
+ } else if (! (string_io = PyObject_CallMethod(string_io_mod, "StringIO", NULL))) {
+ Py_DECREF(string_io_mod);
+ return NULL;
+ } else if (! (string_io_getvalue= PyObject_GetAttrString(string_io, "getvalue"))) {
+ Py_DECREF(string_io_mod);
+ Py_DECREF(string_io);
+ return NULL;
+ }
+
+ Py_INCREF(stdout_backup); // since these were borrowed we dont want them freed when replaced.
+ Py_INCREF(stderr_backup);
+
+ PySys_SetObject("stdout", string_io); // both of these are free'd when restoring
+ PySys_SetObject("stderr", string_io);
+
+ PyErr_Restore(error_type, error_value, error_traceback);
+ PyErr_Print(); /* print the error */
+ PyErr_Clear();
+
+ string_io_buf = PyObject_CallObject(string_io_getvalue, NULL);
+
+ PySys_SetObject("stdout", stdout_backup);
+ PySys_SetObject("stderr", stderr_backup);
+
+ Py_DECREF(stdout_backup); /* now sys owns the ref again */
+ Py_DECREF(stderr_backup);
+
+ Py_DECREF(string_io_mod);
+ Py_DECREF(string_io_getvalue);
+ Py_DECREF(string_io); /* free the original reference */
+
+ PyErr_Clear();
+ return string_io_buf;
+}
+
char *BPy_enum_as_string(EnumPropertyItem *item)
{
DynStr *dynstr= BLI_dynstr_new();
@@ -358,3 +430,33 @@ int BPy_reports_to_error(ReportList *reports)
return (report_str != NULL);
}
+
+int BPy_errors_to_report(ReportList *reports)
+{
+ PyObject *pystring;
+ char *cstring;
+
+ if (!PyErr_Occurred())
+ return 1;
+
+ /* less hassle if we allow NULL */
+ if(reports==NULL) {
+ PyErr_Print();
+ PyErr_Clear();
+ return 1;
+ }
+
+ pystring= BPY_exception_buffer();
+
+ if(pystring==NULL) {
+ BKE_report(reports, RPT_ERROR, "unknown py-exception, could not convert");
+ return 0;
+ }
+
+ cstring= _PyUnicode_AsString(pystring);
+
+ BKE_report(reports, RPT_ERROR, cstring);
+ fprintf(stderr, "%s\n", cstring); // not exactly needed. just for testing
+ Py_DECREF(pystring);
+ return 1;
+}
diff --git a/source/blender/python/intern/bpy_util.h b/source/blender/python/intern/bpy_util.h
index 49f48802249..6429af67eb0 100644
--- a/source/blender/python/intern/bpy_util.h
+++ b/source/blender/python/intern/bpy_util.h
@@ -47,6 +47,8 @@ void PyObSpit(char *name, PyObject *var);
void PyLineSpit(void);
void BPY_getFileAndNum(char **filename, int *lineno);
+PyObject *BPY_exception_buffer(void);
+
/* own python like utility function */
PyObject *PyObject_GetAttrStringArgs(PyObject *o, Py_ssize_t n, ...);
@@ -73,6 +75,7 @@ char *BPy_enum_as_string(struct EnumPropertyItem *item);
/* error reporting */
int BPy_reports_to_error(struct ReportList *reports);
+int BPy_errors_to_report(struct ReportList *reports);
/* TODO - find a better solution! */
struct bContext *BPy_GetContext(void);
diff --git a/source/creator/creator.c b/source/creator/creator.c
index 5617435049d..a19e5d0718c 100644
--- a/source/creator/creator.c
+++ b/source/creator/creator.c
@@ -710,7 +710,7 @@ int main(int argc, char **argv)
//XXX
// FOR TESTING ONLY
a++;
- BPY_run_python_script(C, argv[a], NULL);
+ BPY_run_python_script(C, argv[a], NULL, NULL); // use reports?
#if 0
a++;
if (a < argc) {
@@ -719,7 +719,7 @@ int main(int argc, char **argv)
main_init_screen();
scr_init = 1;
}
- BPY_run_python_script(C, argv[a], NULL);
+ BPY_run_python_script(C, argv[a], NULL, NULL); // use reports?
}
else printf("\nError: you must specify a Python script after '-P '.\n");
#endif