4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * * Neither the name of Red Hat nor the names of its contributors may be
16 * used to endorse or promote products derived from this software without
17 * specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
22 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
26 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
29 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42 /* This is the fallback in case we cannot get the full traceback. */
44 print_python_error (const char *callback
, PyObject
*error
)
47 CLEANUP_FREE
char *error_cstr
= NULL
;
49 error_str
= PyObject_Str (error
);
50 error_cstr
= python_to_string (error_str
);
51 nbdkit_error ("%s: %s: error: %s",
53 error_cstr
? error_cstr
: "<unknown>");
54 Py_DECREF (error_str
);
57 /* Convert the Python traceback to a string and call nbdkit_error.
58 * https://stackoverflow.com/a/15907460/7126113
61 print_python_traceback (const char *callback
,
62 PyObject
*type
, PyObject
*error
, PyObject
*traceback
)
64 PyObject
*module_name
, *traceback_module
, *format_exception_fn
, *rv
,
66 CLEANUP_FREE
char *traceback_cstr
= NULL
;
68 module_name
= PyUnicode_FromString ("traceback");
69 traceback_module
= PyImport_Import (module_name
);
70 Py_DECREF (module_name
);
72 /* couldn't 'import traceback' */
73 if (traceback_module
== NULL
)
76 format_exception_fn
= PyObject_GetAttrString (traceback_module
,
78 if (format_exception_fn
== NULL
)
80 if (!PyCallable_Check (format_exception_fn
))
83 rv
= PyObject_CallFunctionObjArgs (format_exception_fn
,
84 type
, error
, traceback
, NULL
);
87 traceback_str
= PyUnicode_Join (NULL
, rv
);
89 traceback_cstr
= python_to_string (traceback_str
);
90 if (traceback_cstr
== NULL
) {
91 Py_DECREF (traceback_str
);
95 nbdkit_error ("%s: %s: error: %s",
98 Py_DECREF (traceback_str
);
100 /* This means we succeeded in calling nbdkit_error. */
105 check_python_failure (const char *callback
)
107 if (PyErr_Occurred ()) {
108 PyObject
*type
, *error
, *traceback
;
110 PyErr_Fetch (&type
, &error
, &traceback
);
111 PyErr_NormalizeException (&type
, &error
, &traceback
);
113 /* Try to print the full traceback. */
114 if (print_python_traceback (callback
, type
, error
, traceback
) == -1) {
115 /* Couldn't do that, so fall back to converting the Python error
118 print_python_error (callback
, error
);
121 /* In all cases this returns -1 to indicate that a Python error