diff options
author | Campbell Barton <campbell@blender.org> | 2022-08-02 11:16:44 +0300 |
---|---|---|
committer | Thomas Dinges <blender@dingto.org> | 2022-08-02 11:16:44 +0300 |
commit | bc9d461ab0e178c45f681ee4154b97e94fa45156 (patch) | |
tree | 5c6862be58b4edf1b95e183d0f365f255d720f08 | |
parent | 41689bb310469d85d9eae59ca578f4a15dc0e80b (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.c | 37 |
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 9824d5f17c4..44293759672 100644 --- a/source/blender/python/generic/py_capi_utils.c +++ b/source/blender/python/generic/py_capi_utils.c @@ -591,6 +591,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 @@ -641,6 +671,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); + PyErr_Clear(); /* import io @@ -713,6 +745,11 @@ PyObject *PyC_ExceptionBuffer_Simple(void) return NULL; } + /* 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, |