4#ifndef CT_CYTHON_FUNC_WRAPPER
5#define CT_CYTHON_FUNC_WRAPPER
11#define CANTERA_USE_INTERNAL
15typedef double(*callback_wrapper)(double,
void*,
void**);
23 , m_exception_type(
nullptr)
24 , m_exception_value(
nullptr)
29 : m_func(other.m_func)
30 , m_exception_type(other.m_exception_type)
31 , m_exception_value(other.m_exception_value)
33 Py_XINCREF(m_exception_type);
34 Py_XINCREF(m_exception_value);
38 Py_XDECREF(m_exception_type);
39 Py_XDECREF(m_exception_value);
45 void setFunc(PyObject* f) {
49 PyObject* exceptionType() {
50 return m_exception_type;
52 void setExceptionType(PyObject* obj) {
53 Py_XDECREF(m_exception_type);
55 m_exception_type = obj;
58 PyObject* exceptionValue() {
59 return m_exception_value;
61 void setExceptionValue(PyObject* obj) {
62 Py_XDECREF(m_exception_value);
64 m_exception_value = obj;
69 PyObject* m_exception_type;
70 PyObject* m_exception_value;
80 CallbackError(
void* type,
void* value) :
81 CanteraError(
"Python callback function"),
82 m_type((PyObject*) type),
83 m_value((PyObject*) value)
92 m_type(info.exceptionType()),
93 m_value(info.exceptionValue())
97 info.setExceptionType(0);
98 info.setExceptionValue(0);
109 PyObject* name = PyObject_GetAttrString(m_type,
"__name__");
110 PyObject* value_str = PyObject_Str(m_value);
112 PyObject* name_bytes = PyUnicode_AsASCIIString(name);
113 PyObject* value_bytes = PyUnicode_AsASCIIString(value_str);
116 msg += PyBytes_AsString(name_bytes);
117 Py_DECREF(name_bytes);
119 msg +=
"<error determining exception type>";
125 msg += PyBytes_AsString(value_bytes);
126 Py_DECREF(value_bytes);
128 msg +=
"<error determining exception message>";
132 Py_XDECREF(value_str);
136 virtual std::string
getClass()
const {
149 Func1Py(callback_wrapper callback,
void* pyobj) :
150 m_callback(callback),
154 double eval(
double t)
const {
155 void* err[2] = {0, 0};
156 double y = m_callback(t, m_pyobj, err);
158 throw CallbackError(err[0], err[1]);
164 callback_wrapper m_callback;
169 CANTERA_CAPI PyObject* pyCanteraError;
185template <
class ... Args>
186std::function<void(Args ...)> pyOverride(PyObject* pyFunc,
void func(
PyFuncInfo&, Args ... args)) {
188 func_info.setFunc(pyFunc);
189 return [func_info, func](Args ... args)
mutable {
190 func(func_info, args ...);
191 if (func_info.exceptionType()) {
192 throw CallbackError(func_info);
198template <
class ... Args>
199std::function<int(Args ...)> pyOverride(PyObject* pyFunc,
int func(
PyFuncInfo&, Args ... args)) {
201 func_info.setFunc(pyFunc);
202 return [func_info, func](Args ... args)
mutable {
203 int ret = func(func_info, args ...);
204 if (func_info.exceptionType()) {
205 throw CallbackError(func_info);
214inline int translate_exception()
217 if (!PyErr_Occurred()) {
222 }
catch (
const CallbackError& exn) {
224 PyErr_SetObject(exn.m_type, exn.m_value);
225 }
catch (
const std::out_of_range& exn) {
226 PyErr_SetString(PyExc_IndexError, exn.what());
228 PyErr_SetString(pyCanteraError, exn.
what());
229 }
catch (
const std::exception& exn) {
230 PyErr_SetString(PyExc_RuntimeError, exn.what());
232 PyErr_SetString(PyExc_Exception,
"Unknown exception");
Base class for exceptions thrown by Cantera classes.
virtual std::string getMessage() const
Method overridden by derived classes to format the error message.
virtual std::string getClass() const
Method overridden by derived classes to indicate their type.
const char * what() const
Get a description of the error.
CanteraError(const std::string &procedure, const std::string &msg, const Args &... args)
Normal Constructor for the CanteraError base class.
Base class for 'functor' classes that evaluate a function of one variable.
virtual doublereal eval(doublereal t) const
Evaluate the function.
A class to hold information needed to call Python functions from delgated methods (see class Delegato...
Definitions for the classes that are thrown when Cantera experiences an error condition (also contain...