[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:
Ray Speth 2014-09-23 02:20:41 +00:00
parent eb468b6a48
commit 8e7588671f
2 changed files with 43 additions and 3 deletions

View file

@ -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
};

View file

@ -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) {