diff options
-rw-r--r-- | source/blender/blenkernel/BKE_report.h | 5 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/report.c | 14 | ||||
-rw-r--r-- | source/blender/editors/space_text/text_ops.c | 4 | ||||
-rw-r--r-- | source/blender/python/intern/bpy_capi_utils.c | 72 | ||||
-rw-r--r-- | source/blender/python/intern/bpy_capi_utils.h | 13 | ||||
-rw-r--r-- | source/blender/python/intern/bpy_interface_run.c | 26 | ||||
-rw-r--r-- | source/blender/python/intern/bpy_traceback.c | 5 |
7 files changed, 86 insertions, 53 deletions
diff --git a/source/blender/blenkernel/BKE_report.h b/source/blender/blenkernel/BKE_report.h index b67c4856e89..38b5c68c8ca 100644 --- a/source/blender/blenkernel/BKE_report.h +++ b/source/blender/blenkernel/BKE_report.h @@ -45,6 +45,11 @@ eReportType BKE_report_store_level(ReportList *reports); void BKE_report_store_level_set(ReportList *reports, eReportType level); char *BKE_reports_string(ReportList *reports, eReportType level); + +/** + * \return true when reports of this type will print to the `stdout`. + */ +bool BKE_reports_print_test(const ReportList *reports, eReportType type); void BKE_reports_print(ReportList *reports, eReportType level); Report *BKE_reports_last_displayable(ReportList *reports); diff --git a/source/blender/blenkernel/intern/report.c b/source/blender/blenkernel/intern/report.c index 98b680c8054..6d654730bca 100644 --- a/source/blender/blenkernel/intern/report.c +++ b/source/blender/blenkernel/intern/report.c @@ -86,9 +86,7 @@ void BKE_report(ReportList *reports, eReportType type, const char *_message) int len; const char *message = TIP_(_message); - /* in background mode always print otherwise there are cases the errors won't be displayed, - * but still add to the report list since this is used for python exception handling */ - if (G.background || !reports || ((reports->flag & RPT_PRINT) && (type >= reports->printlevel))) { + if (BKE_reports_print_test(reports, type)) { printf("%s: %s\n", BKE_report_type_str(type), message); fflush(stdout); /* this ensures the message is printed before a crash */ } @@ -115,7 +113,7 @@ void BKE_reportf(ReportList *reports, eReportType type, const char *_format, ... va_list args; const char *format = TIP_(_format); - if (G.background || !reports || ((reports->flag & RPT_PRINT) && (type >= reports->printlevel))) { + if (BKE_reports_print_test(reports, type)) { printf("%s: ", BKE_report_type_str(type)); va_start(args, _format); vprintf(format, args); @@ -258,6 +256,14 @@ char *BKE_reports_string(ReportList *reports, eReportType level) return cstring; } +bool BKE_reports_print_test(const ReportList *reports, eReportType type) +{ + /* In background mode always print otherwise there are cases the errors won't be displayed, + * but still add to the report list since this is used for python exception handling. */ + return (G.background || (reports == NULL) || + ((reports->flag & RPT_PRINT) && (type >= reports->printlevel))); +} + void BKE_reports_print(ReportList *reports, eReportType level) { char *cstring = BKE_reports_string(reports, level); diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c index 49c0236866d..d4aac8dd57f 100644 --- a/source/blender/editors/space_text/text_ops.c +++ b/source/blender/editors/space_text/text_ops.c @@ -788,9 +788,7 @@ static int text_run_script(bContext *C, ReportList *reports) } } - BKE_report( - reports, RPT_ERROR, "Python script failed, check the message in the system console"); - + /* No need to report the error, this has already been handled by #BPY_run_text. */ return OPERATOR_FINISHED; } #else diff --git a/source/blender/python/intern/bpy_capi_utils.c b/source/blender/python/intern/bpy_capi_utils.c index 742c04de3d7..f7f8253edac 100644 --- a/source/blender/python/intern/bpy_capi_utils.c +++ b/source/blender/python/intern/bpy_capi_utils.c @@ -54,70 +54,60 @@ void BPy_reports_write_stdout(const ReportList *reports, const char *header) } bool BPy_errors_to_report_ex(ReportList *reports, - const char *error_prefix, + const char *err_prefix, const bool use_full, const bool use_location) { - PyObject *pystring; if (!PyErr_Occurred()) { return 1; } - /* less hassle if we allow NULL */ - if (reports == NULL) { - PyErr_Print(); - PyErr_Clear(); - return 1; - } - - if (use_full) { - pystring = PyC_ExceptionBuffer(); - } - else { - pystring = PyC_ExceptionBuffer_Simple(); - } - - if (pystring == NULL) { + PyObject *err_str_py = use_full ? PyC_ExceptionBuffer() : PyC_ExceptionBuffer_Simple(); + if (err_str_py == NULL) { BKE_report(reports, RPT_ERROR, "Unknown py-exception, could not convert"); return 0; } - if (error_prefix == NULL) { + /* Trim trailing newlines so the report doesn't contain a trailing new-line. + * This would add a blank-line in the info space. */ + Py_ssize_t err_str_len; + const char *err_str = PyUnicode_AsUTF8AndSize(err_str_py, &err_str_len); + while (err_str_len > 0 && err_str[err_str_len - 1] == '\n') { + err_str_len -= 1; + } + + if (err_prefix == NULL) { /* Not very helpful, better than nothing. */ - error_prefix = "Python"; + err_prefix = "Python"; } - if (use_location) { - const char *filename; - int lineno; + const char *location_filepath = NULL; + int location_line_number = -1; - PyC_FileAndNum(&filename, &lineno); - if (filename == NULL) { - filename = "<unknown location>"; - } + /* Give some additional context. */ + if (use_location) { + PyC_FileAndNum(&location_filepath, &location_line_number); + } + if (location_filepath) { BKE_reportf(reports, RPT_ERROR, - TIP_("%s: %s\nlocation: %s:%d\n"), - error_prefix, - PyUnicode_AsUTF8(pystring), - filename, - lineno); - - /* Not exactly needed. Useful for developers tracking down issues. */ - fprintf(stderr, - TIP_("%s: %s\nlocation: %s:%d\n"), - error_prefix, - PyUnicode_AsUTF8(pystring), - filename, - lineno); + "%s: %.*s\n" + /* Location (when available). */ + "Location: %s:%d", + err_prefix, + (int)err_str_len, + err_str, + location_filepath, + location_line_number); } else { - BKE_reportf(reports, RPT_ERROR, "%s: %s", error_prefix, PyUnicode_AsUTF8(pystring)); + BKE_reportf(reports, RPT_ERROR, "%s: %.*s", err_prefix, (int)err_str_len, err_str); } - Py_DECREF(pystring); + /* Ensure this is _always_ printed to the output so developers don't miss exceptions. */ + Py_DECREF(err_str_py); return 1; } diff --git a/source/blender/python/intern/bpy_capi_utils.h b/source/blender/python/intern/bpy_capi_utils.h index 223c6ad5f7e..ab5ce7818f3 100644 --- a/source/blender/python/intern/bpy_capi_utils.h +++ b/source/blender/python/intern/bpy_capi_utils.h @@ -27,7 +27,18 @@ bool BPy_errors_to_report_ex(struct ReportList *reports, const char *error_prefix, bool use_full, bool use_location); -bool BPy_errors_to_report_brief_with_prefix(struct ReportList *reports, const char *error_prefix); +/** + * \param reports: When set, an error will be added to this report, when NULL, print the error. + * + * \note Unless the caller handles printing the reports (or reports is NULL) it's best to ensure + * the output is printed to the `stdout/stderr`: + * \code{.cc} + * BPy_errors_to_report(reports); + * if (!BKE_reports_print_test(reports)) { + * BKE_reports_print(reports); + * } + * \endcode + */ bool BPy_errors_to_report(struct ReportList *reports); struct bContext *BPY_context_get(void); diff --git a/source/blender/python/intern/bpy_interface_run.c b/source/blender/python/intern/bpy_interface_run.c index 147c6cf8187..50a2722c276 100644 --- a/source/blender/python/intern/bpy_interface_run.c +++ b/source/blender/python/intern/bpy_interface_run.c @@ -271,7 +271,23 @@ static bool bpy_run_string_impl(bContext *C, if (retval == NULL) { ok = false; - BPy_errors_to_report(CTX_wm_reports(C)); + + ReportList reports; + BKE_reports_init(&reports, RPT_STORE); + BPy_errors_to_report(&reports); + + /* Ensure the reports are printed. */ + if (!BKE_reports_print_test(&reports, RPT_ERROR)) { + BKE_reports_print(&reports, RPT_ERROR); + } + + ReportList *wm_reports = CTX_wm_reports(C); + if (wm_reports) { + BLI_movelisttolist(&wm_reports->list, &reports.list); + } + else { + BKE_reports_clear(&reports); + } } else { Py_DECREF(retval); @@ -330,6 +346,14 @@ static void run_string_handle_error(struct BPy_RunErrInfo *err_info) } } + /* Print the reports if they were not printed already. */ + if ((err_info->reports == NULL) || !BKE_reports_print_test(err_info->reports, RPT_ERROR)) { + if (err_info->report_prefix) { + fprintf(stderr, "%s: ", err_info->report_prefix); + } + fprintf(stderr, "%s\n", err_str); + } + if (err_info->r_string != NULL) { *err_info->r_string = BLI_strdup(err_str); } diff --git a/source/blender/python/intern/bpy_traceback.c b/source/blender/python/intern/bpy_traceback.c index 40478f3613c..1c545774203 100644 --- a/source/blender/python/intern/bpy_traceback.c +++ b/source/blender/python/intern/bpy_traceback.c @@ -205,12 +205,9 @@ bool python_script_error_jump( } } } - PyErr_Restore(exception, value, (PyObject *)tb); /* takes away reference! */ } else { PyErr_NormalizeException(&exception, &value, (PyObject **)&tb); - PyErr_Restore(exception, value, (PyObject *)tb); /* takes away reference! */ - PyErr_Print(); for (tb = (PyTracebackObject *)PySys_GetObject("last_traceback"); tb && (PyObject *)tb != Py_None; @@ -230,5 +227,7 @@ bool python_script_error_jump( } } + PyErr_Restore(exception, value, (PyObject *)tb); /* takes away reference! */ + return success; } |