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:
		@@ -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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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) {
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
@@ -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 "
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user