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 <campbell@blender.org>2022-07-26 05:23:41 +0300
committerThomas Dinges <blender@dingto.org>2022-07-26 17:48:49 +0300
commit5f7c677ac968233fe277ea9b6ab7891f820f3677 (patch)
tree532f1f57472e1f894ba0b92ff8d27255e4be4a03
parent83d412a504bf5e1399f61b34154ef8927049ac65 (diff)
Fix Python SystemExit exceptions silently exiting
Any script that raised a SystemExit called by --python, --python-expr command line args or by executing the text block would exit without printing a message. This caused the error from T99966 to be hidden. Add explicit handling for SystemExit to ensure the message is always shown before exiting. More details noted in code-comments.
-rw-r--r--source/blender/python/generic/py_capi_utils.c37
1 files changed, 37 insertions, 0 deletions
diff --git a/source/blender/python/generic/py_capi_utils.c b/source/blender/python/generic/py_capi_utils.c
index d2e3c44c1b6..8e92d7205b3 100644
--- a/source/blender/python/generic/py_capi_utils.c
+++ b/source/blender/python/generic/py_capi_utils.c
@@ -819,6 +819,36 @@ void PyC_Err_PrintWithFunc(PyObject *py_func)
/** \name Exception Buffer Access
* \{ */
+static void pyc_exception_buffer_handle_system_exit(PyObject *error_type,
+ PyObject *error_value,
+ PyObject *error_traceback)
+{
+ if (!PyErr_GivenExceptionMatches(error_type, PyExc_SystemExit)) {
+ return;
+ }
+ /* Inspecting, follow Python's logic in #_Py_HandleSystemExit & treat as a regular exception. */
+ if (_Py_GetConfig()->inspect) {
+ return;
+ }
+
+ /* NOTE(@campbellbarton): A `SystemExit` exception will exit immediately (unless inspecting).
+ * So print the error and exit now. This is necessary as the call to #PyErr_Print exits,
+ * the temporary `sys.stderr` assignment causes the output to be suppressed, failing silently.
+ * Instead, restore the error and print it. If Python changes it's behavior and doesn't exit in
+ * the future - continue to create the exception buffer, see: T99966.
+ *
+ * Arguably accessing a `SystemExit` exception as a buffer should be supported without exiting.
+ * (by temporarily enabling inspection for example) however - it's not obvious exactly when this
+ * should be enabled and complicates the Python API by introducing different kinds of execution.
+ * Since the rule of thumb is for Blender's embedded Python to match stand-alone Python,
+ * favor exiting when a `SystemExit` is raised.
+ * Especially since this exception more likely to be used for background/batch-processing
+ * utilities where exiting immediately makes sense, the possibility of this being called
+ * indirectly from python-drivers or modal-operators is less of a concern. */
+ PyErr_Restore(error_type, error_value, error_traceback);
+ PyErr_Print();
+}
+
/* returns the exception string as a new PyUnicode object, depends on external traceback module */
# if 0
@@ -869,6 +899,8 @@ PyObject *PyC_ExceptionBuffer(void)
PyErr_Fetch(&error_type, &error_value, &error_traceback);
+ pyc_exception_buffer_handle_system_exit(error_type, error_value, error_traceback);
+
/* import io
* string_io = io.StringIO()
*/
@@ -940,6 +972,11 @@ PyObject *PyC_ExceptionBuffer_Simple(void)
PyErr_Fetch(&error_type, &error_value, &error_traceback);
+ /* Since #PyErr_Print is not called it's not essential that `SystemExit` exceptions are handled.
+ * Do this to match the behavior of #PyC_ExceptionBuffer since requesting a brief exception
+ * shouldn't result in completely different behavior. */
+ pyc_exception_buffer_handle_system_exit(error_type, error_value, error_traceback);
+
if (PyErr_GivenExceptionMatches(error_type, PyExc_SyntaxError)) {
/* Special exception for syntax errors,
* in these cases the full error is verbose and not very useful,