Cantera  2.4.0
funcWrapper.h
1 // This file is part of Cantera. See License.txt in the top-level directory or
2 // at http://www.cantera.org/license.txt for license and copyright information.
3 
4 #ifndef CT_CYTHON_FUNC_WRAPPER
5 #define CT_CYTHON_FUNC_WRAPPER
6 
9 #include <stdexcept>
10 
11 #define CANTERA_USE_INTERNAL
12 #include "cantera/clib/clib_defs.h"
13 #include "Python.h"
14 
15 typedef double(*callback_wrapper)(double, void*, void**);
16 
17 // A C++ exception that holds a Python exception so that it can be re-raised
18 // by translate_exception()
19 class CallbackError : public Cantera::CanteraError
20 {
21 public:
22  CallbackError(void* type, void* value) :
23  CanteraError("Python callback function"),
24  m_type((PyObject*) type),
25  m_value((PyObject*) value)
26  {
27  }
28  std::string getMessage() const {
29  std::string msg;
30 
31  PyObject* name = PyObject_GetAttrString(m_type, "__name__");
32  PyObject* value_str = PyObject_Str(m_value);
33 
34  #if PY_MAJOR_VERSION > 2
35  PyObject* name_bytes = PyUnicode_AsASCIIString(name);
36  PyObject* value_bytes = PyUnicode_AsASCIIString(value_str);
37  #else
38  PyObject* name_bytes = PyObject_Bytes(name);
39  PyObject* value_bytes = PyObject_Bytes(value_str);
40  #endif
41 
42  if (name_bytes) {
43  msg += PyBytes_AsString(name_bytes);
44  Py_DECREF(name_bytes);
45  } else {
46  msg += "<error determining exception type>";
47  }
48 
49  msg += ": ";
50 
51  if (value_bytes) {
52  msg += PyBytes_AsString(value_bytes);
53  Py_DECREF(value_bytes);
54  } else {
55  msg += "<error determining exception message>";
56  }
57 
58  Py_XDECREF(name);
59  Py_XDECREF(value_str);
60  return msg;
61  }
62 
63  virtual std::string getClass() const {
64  return "Exception";
65  }
66 
67  PyObject* m_type;
68  PyObject* m_value;
69 };
70 
71 
72 // A function of one variable implemented as a callable Python object
73 class Func1Py : public Cantera::Func1
74 {
75 public:
76  Func1Py(callback_wrapper callback, void* pyobj) :
77  m_callback(callback),
78  m_pyobj(pyobj) {
79  }
80 
81  double eval(double t) const {
82  void* err[2] = {0, 0};
83  double y = m_callback(t, m_pyobj, err);
84  if (err[0]) {
85  throw CallbackError(err[0], err[1]);
86  }
87  return y;
88  }
89 
90 private:
91  callback_wrapper m_callback;
92  void* m_pyobj;
93 };
94 
95 extern "C" {
96  CANTERA_CAPI PyObject* pyCanteraError;
97 }
98 
99 // Translate C++ Exceptions generated by Cantera to appropriate Python
100 // exceptions. Used with Cython function declarations, e.g:
101 // cdef double eval(double) except +translate_exception
102 inline int translate_exception()
103 {
104  try {
105  if (!PyErr_Occurred()) {
106  // Let the latest Python exception pass through and ignore the
107  // current one.
108  throw;
109  }
110  } catch (const CallbackError& exn) {
111  // Re-raise a Python exception generated in a callback
112  PyErr_SetObject(exn.m_type, exn.m_value);
113  } catch (const std::out_of_range& exn) {
114  PyErr_SetString(PyExc_IndexError, exn.what());
115  } catch (const Cantera::CanteraError& exn) {
116  PyErr_SetString(pyCanteraError, exn.what());
117  } catch (const std::exception& exn) {
118  PyErr_SetString(PyExc_RuntimeError, exn.what());
119  } catch (...) {
120  PyErr_SetString(PyExc_Exception, "Unknown exception");
121  }
122  return 0;
123 }
124 
125 #endif
const char * what() const
Get a description of the error.
virtual doublereal eval(doublereal t) const
Evaluate the function.
Definition: Func1.cpp:60
virtual std::string getMessage() const
Method overridden by derived classes to format the error message.
Base class for &#39;functor&#39; classes that evaluate a function of one variable.
Definition: Func1.h:41
Base class for exceptions thrown by Cantera classes.
Definition: ctexceptions.h:65
CanteraError(const std::string &procedure, const std::string &msg, const Args &... args)
Normal Constructor for the CanteraError base class.
Definition: ctexceptions.h:79
virtual std::string getClass() const
Method overridden by derived classes to indicate their type.
Definition: ctexceptions.h:100
Definitions for the classes that are thrown when Cantera experiences an error condition (also contain...