[Cython/Reactor] Print messages from exceptions raised in Python callbacks
Unlike the normal case for CallbackError, where the error message is visible when it is re-raised in Python, errors occuring during reactor network integration aren't necessarily terminal, so they can't simply be re-raised after returning to Python. But we still want to display the information they contain, so we need to extract that information from the Python exception objects in the what() function that is called by cvodes_rhs.
This commit is contained in:
parent
eb468b6a48
commit
8e7588671f
2 changed files with 43 additions and 3 deletions
|
|
@ -136,10 +136,10 @@ protected:
|
|||
|
||||
//! The name of the procedure where the exception occurred
|
||||
std::string procedure_;
|
||||
mutable std::string formattedMessage_; //!< Formatted message returned by what()
|
||||
|
||||
private:
|
||||
std::string msg_; //!< Message associated with the exception
|
||||
mutable std::string formattedMessage_; //!< Formatted message returned by what()
|
||||
bool saved_; //!< Exception has already been saved to Cantera's error stack
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "cantera/numerics/Func1.h"
|
||||
#include "cantera/base/ctexceptions.h"
|
||||
#include <stdexcept>
|
||||
|
||||
#include "Python.h"
|
||||
|
||||
|
|
@ -16,7 +17,46 @@ public:
|
|||
CallbackError(void* type, void* value) :
|
||||
m_type((PyObject*) type),
|
||||
m_value((PyObject*) value)
|
||||
{}
|
||||
{
|
||||
}
|
||||
const char* what() const throw() {
|
||||
formattedMessage_ = "\n" + std::string(71, '*') + "\n";
|
||||
formattedMessage_ += "Exception raised in Python callback function:\n";
|
||||
|
||||
PyObject* name = PyObject_GetAttrString(m_type, "__name__");
|
||||
PyObject* value_str = PyObject_Str(m_value);
|
||||
|
||||
#if PY_MAJOR_VERSION > 2
|
||||
PyObject* name_bytes = PyUnicode_AsASCIIString(name);
|
||||
PyObject* value_bytes = PyUnicode_AsASCIIString(value_str);
|
||||
#else
|
||||
PyObject* name_bytes = PyObject_Bytes(name);
|
||||
PyObject* value_bytes = PyObject_Bytes(value_str);
|
||||
#endif
|
||||
|
||||
if (name_bytes) {
|
||||
formattedMessage_ += PyBytes_AsString(name_bytes);
|
||||
Py_DECREF(name_bytes);
|
||||
} else {
|
||||
formattedMessage_ += "<error determining exception type>";
|
||||
}
|
||||
|
||||
formattedMessage_ += ": ";
|
||||
|
||||
if (value_bytes) {
|
||||
formattedMessage_ += PyBytes_AsString(value_bytes);
|
||||
Py_DECREF(value_bytes);
|
||||
} else {
|
||||
formattedMessage_ += "<error determining exception message>";
|
||||
}
|
||||
|
||||
Py_XDECREF(name);
|
||||
Py_XDECREF(value_str);
|
||||
|
||||
formattedMessage_ += "\n" + std::string(71, '*') + "\n";
|
||||
return formattedMessage_.c_str();
|
||||
}
|
||||
|
||||
PyObject* m_type;
|
||||
PyObject* m_value;
|
||||
};
|
||||
|
|
@ -57,7 +97,7 @@ inline int translate_exception()
|
|||
// current one.
|
||||
throw;
|
||||
}
|
||||
} catch (CallbackError& exn) {
|
||||
} catch (const CallbackError& exn) {
|
||||
// Re-raise a Python exception generated in a callback
|
||||
PyErr_SetObject(exn.m_type, exn.m_value);
|
||||
} catch (const std::out_of_range& exn) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue