Cantera  2.2.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
funcWrapper.h
1 #ifndef CT_CYTHON_FUNC_WRAPPER
2 #define CT_CYTHON_FUNC_WRAPPER
3 
6 #include <stdexcept>
7 
8 #include "Python.h"
9 
10 typedef double(*callback_wrapper)(double, void*, void**);
11 
12 // A C++ exception that holds a Python exception so that it can be re-raised
13 // by translate_exception()
14 class CallbackError : public Cantera::CanteraError
15 {
16 public:
17  CallbackError(void* type, void* value) :
18  m_type((PyObject*) type),
19  m_value((PyObject*) value)
20  {
21  }
22  const char* what() const throw() {
23  formattedMessage_ = "\n" + std::string(71, '*') + "\n";
24  formattedMessage_ += "Exception raised in Python callback function:\n";
25 
26  PyObject* name = PyObject_GetAttrString(m_type, "__name__");
27  PyObject* value_str = PyObject_Str(m_value);
28 
29  #if PY_MAJOR_VERSION > 2
30  PyObject* name_bytes = PyUnicode_AsASCIIString(name);
31  PyObject* value_bytes = PyUnicode_AsASCIIString(value_str);
32  #else
33  PyObject* name_bytes = PyObject_Bytes(name);
34  PyObject* value_bytes = PyObject_Bytes(value_str);
35  #endif
36 
37  if (name_bytes) {
38  formattedMessage_ += PyBytes_AsString(name_bytes);
39  Py_DECREF(name_bytes);
40  } else {
41  formattedMessage_ += "<error determining exception type>";
42  }
43 
44  formattedMessage_ += ": ";
45 
46  if (value_bytes) {
47  formattedMessage_ += PyBytes_AsString(value_bytes);
48  Py_DECREF(value_bytes);
49  } else {
50  formattedMessage_ += "<error determining exception message>";
51  }
52 
53  Py_XDECREF(name);
54  Py_XDECREF(value_str);
55 
56  formattedMessage_ += "\n" + std::string(71, '*') + "\n";
57  return formattedMessage_.c_str();
58  }
59 
60  PyObject* m_type;
61  PyObject* m_value;
62 };
63 
64 
65 // A function of one variable implemented as a callable Python object
66 class Func1Py : public Cantera::Func1
67 {
68 public:
69  Func1Py(callback_wrapper callback, void* pyobj) :
70  m_callback(callback),
71  m_pyobj(pyobj) {
72  }
73 
74  double eval(double t) const {
75  void* err[2] = {0, 0};
76  double y = m_callback(t, m_pyobj, err);
77  if (err[0]) {
78  throw CallbackError(err[0], err[1]);
79  }
80  return y;
81  }
82 
83 private:
84  callback_wrapper m_callback;
85  void* m_pyobj;
86 };
87 
88 
89 // Translate C++ Exceptions generated by Cantera to appropriate Python
90 // exceptions. Used with Cython function declarations, e.g:
91 // cdef double eval(double) except +translate_exception
92 inline int translate_exception()
93 {
94  try {
95  if (!PyErr_Occurred()) {
96  // Let the latest Python exception pass through and ignore the
97  // current one.
98  throw;
99  }
100  } catch (const CallbackError& exn) {
101  // Re-raise a Python exception generated in a callback
102  PyErr_SetObject(exn.m_type, exn.m_value);
103  } catch (const std::out_of_range& exn) {
104  PyErr_SetString(PyExc_IndexError, exn.what());
105  } catch (const std::exception& exn) {
106  PyErr_SetString(PyExc_Exception, exn.what());
107  } catch (...) {
108  PyErr_SetString(PyExc_Exception, "Unknown exception");
109  }
110  return 0;
111 }
112 
113 #endif
std::string formattedMessage_
Formatted message returned by what()
Definition: ctexceptions.h:139
virtual doublereal eval(doublereal t) const
Evaluate the function.
Definition: Func1.cpp:56
const char * what() const
Get a description of the error.
Base class for 'functor' classes that evaluate a function of one variable.
Definition: Func1.h:41
Base class for exceptions thrown by Cantera classes.
Definition: ctexceptions.h:99
Definitions for the classes that are thrown when Cantera experiences an error condition (also contain...