Fix T97731: Python traceback no longer includes line-numbers

Regression caused by [0] that caused the error message to be
created based on a normalized exception (which hid line numbers).

PyC_ExceptionBuffer{_Simple} & BPy_errors_to_report
no longer clears the exception.

This could have been resolved by changing python_script_error_jump
however that would involve changes to reference counting that are more
risky (noted in code-comment).

[0]: 2d2baeaf04
This commit is contained in:
Campbell Barton 2022-05-03 17:54:37 +10:00
parent a821a2db3d
commit 74dfb7ca23
Notes: blender-bot 2023-04-14 09:18:04 +02:00
Referenced by issue #97731, Regression: Python Traceback no longer includes line-number in Info messages
7 changed files with 26 additions and 16 deletions

View File

@ -90,6 +90,7 @@ class PythonInterpreter : public Interpreter {
if (!BPY_run_string_eval(_context, NULL, str.c_str())) {
BPy_errors_to_report(reports);
PyErr_Clear();
cerr << "\nError executing Python script from PythonInterpreter::interpretString" << endl;
cerr << "Name: " << name << endl;
cerr << "Errors: " << endl;

View File

@ -892,6 +892,10 @@ PyObject *PyC_ExceptionBuffer(void)
PySys_SetObject("stderr", string_io);
PyErr_Restore(error_type, error_value, error_traceback);
/* Printing clears (call #PyErr_Clear as well to ensure it's cleared). */
Py_XINCREF(error_type);
Py_XINCREF(error_value);
Py_XINCREF(error_traceback);
PyErr_Print(); /* print the error */
PyErr_Clear();
@ -907,17 +911,18 @@ PyObject *PyC_ExceptionBuffer(void)
Py_DECREF(string_io_getvalue);
Py_DECREF(string_io); /* free the original reference */
PyErr_Clear();
PyErr_Restore(error_type, error_value, error_traceback);
return string_io_buf;
error_cleanup:
/* could not import the module so print the error and close */
/* Could not import the module so print the error and close. */
Py_XDECREF(string_io_mod);
Py_XDECREF(string_io);
PyErr_Restore(error_type, error_value, error_traceback);
PyErr_Print(); /* print the error */
PyErr_Clear();
PyErr_Restore(error_type, error_value, error_traceback);
return NULL;
}
@ -925,19 +930,15 @@ error_cleanup:
PyObject *PyC_ExceptionBuffer_Simple(void)
{
PyObject *string_io_buf = NULL;
PyObject *error_type, *error_value, *error_traceback;
if (!PyErr_Occurred()) {
return NULL;
}
PyErr_Fetch(&error_type, &error_value, &error_traceback);
PyObject *string_io_buf = NULL;
if (error_value == NULL) {
return NULL;
}
PyObject *error_type, *error_value, *error_traceback;
PyErr_Fetch(&error_type, &error_value, &error_traceback);
if (PyErr_GivenExceptionMatches(error_type, PyExc_SyntaxError)) {
/* Special exception for syntax errors,
@ -959,7 +960,6 @@ PyObject *PyC_ExceptionBuffer_Simple(void)
PyErr_Restore(error_type, error_value, error_traceback);
PyErr_Clear();
return string_io_buf;
}

View File

@ -38,6 +38,8 @@ bool BPy_errors_to_report_ex(struct ReportList *reports,
* BKE_reports_print(reports);
* }
* \endcode
*
* \note The caller is responsible for clearing the error (see #PyErr_Clear).
*/
bool BPy_errors_to_report(struct ReportList *reports);

View File

@ -128,9 +128,6 @@ static bool python_script_exec(bContext *C,
Py_DECREF(filepath_dummy_py);
if (PyErr_Occurred()) {
if (do_jump) {
python_script_error_jump_text(text, filepath_dummy);
}
BPY_text_free_code(text);
}
}
@ -184,6 +181,7 @@ static bool python_script_exec(bContext *C,
}
if (!py_result) {
BPy_errors_to_report(reports);
if (text) {
if (do_jump) {
/* ensure text is valid before use, the script may have freed itself */
@ -193,7 +191,7 @@ static bool python_script_exec(bContext *C,
}
}
}
BPy_errors_to_report(reports);
PyErr_Clear();
}
else {
Py_DECREF(py_result);
@ -275,6 +273,7 @@ static bool bpy_run_string_impl(bContext *C,
ReportList reports;
BKE_reports_init(&reports, RPT_STORE);
BPy_errors_to_report(&reports);
PyErr_Clear();
/* Ensure the reports are printed. */
if (!BKE_reports_print_test(&reports, RPT_ERROR)) {
@ -336,6 +335,7 @@ static void run_string_handle_error(struct BPy_RunErrInfo *err_info)
PyObject *py_err_str = err_info->use_single_line_error ? PyC_ExceptionBuffer_Simple() :
PyC_ExceptionBuffer();
const char *err_str = py_err_str ? PyUnicode_AsUTF8(py_err_str) : "Unable to extract exception";
PyErr_Clear();
if (err_info->reports != NULL) {
if (err_info->report_prefix) {

View File

@ -4111,6 +4111,8 @@ StructRNA *pointer_type_from_py(PyObject *value, const char *error_prefix)
if (PyErr_Occurred()) {
PyObject *msg = PyC_ExceptionBuffer();
const char *msg_char = PyUnicode_AsUTF8(msg);
PyErr_Clear();
PyErr_Format(
PyExc_TypeError, "%.200s expected an RNA type, failed with: %s", error_prefix, msg_char);
Py_DECREF(msg);

View File

@ -2051,6 +2051,7 @@ static int pyrna_py_to_prop(
&itemptr, item, true, "Converting a Python list to an RNA collection") == -1) {
PyObject *msg = PyC_ExceptionBuffer();
const char *msg_char = PyUnicode_AsUTF8(msg);
PyErr_Clear();
PyErr_Format(PyExc_TypeError,
"%.200s %.200s.%.200s error converting a member of a collection "

View File

@ -165,6 +165,10 @@ finally:
bool python_script_error_jump(
const char *filepath, int *r_lineno, int *r_offset, int *r_lineno_end, int *r_offset_end)
{
/* WARNING(@campbellbarton): The normalized exception is restored (loosing line number info).
* Ideally this would leave the exception state as it found it, but that needs to be done
* carefully with regards to reference counting, see: T97731. */
bool success = false;
PyObject *exception, *value;
PyTracebackObject *tb;