All Classes Namespaces Functions Typedefs Enumerations
py2py3cppwrapper.h
1 /*
2  * Author: Markus Friedrich
3  *
4  * This file is free and unencumbered software released into the public domain.
5  *
6  * Anyone is free to copy, modify, publish, use, compile, sell, or
7  * distribute this software, either in source code form or as a compiled
8  * binary, for any purpose, commercial or non-commercial, and by any
9  * means.
10  *
11  * In jurisdictions that recognize copyright laws, the author or authors
12  * of this software dedicate any and all copyright interest in the
13  * software to the public domain. We make this dedication for the benefit
14  * of the public at large and to the detriment of our heirs and
15  * successors. We intend this dedication to be an overt act of
16  * relinquishment in perpetuity of all present and future rights to this
17  * software under copyright law.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
23  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25  * OTHER DEALINGS IN THE SOFTWARE.
26  *
27  * For more information, please refer to <http://unlicense.org/>
28  */
29 
30 #ifndef _PY2PY3CPPWRAPPER_H_
31 #define _PY2PY3CPPWRAPPER_H_
32 
33 #include <Python.h>
34 #include <string>
35 #include <stdexcept>
36 #include <memory>
37 #include <sstream>
38 #include <boost/shared_ptr.hpp>
39 #include <boost/locale/encoding_utf.hpp>
40 
41 namespace PythonCpp {
42 
43 // initialize python giving main as program name to python
44 void initializePython(const std::string &main, const std::vector<std::string> &args=std::vector<std::string>()) {
45 #if PY_MAJOR_VERSION < 3
46  Py_SetProgramName(const_cast<char*>(main.c_str()));
47  Py_InitializeEx(0);
48  std::vector<char*> argv(args.size());
49  for(size_t i=0; i<args.size(); ++i)
50  argv[i]=const_cast<char*>(args[i].c_str());
51  PySys_SetArgvEx(args.size(), &argv[0], 0);
52 #else
53  Py_SetProgramName(const_cast<wchar_t*>(boost::locale::conv::utf_to_utf<wchar_t>(main).c_str()));
54  Py_InitializeEx(0);
55  std::vector<wchar_t*> argv(args.size());
56  std::vector<std::wstring> argsw;
57  argsw.reserve(args.size());
58  for(size_t i=0; i<args.size(); ++i) {
59  argsw.push_back(boost::locale::conv::utf_to_utf<wchar_t>(args[i]));
60  argv[i]=const_cast<wchar_t*>(argsw[i].c_str());
61  }
62  PySys_SetArgvEx(args.size(), &argv[0], 0);
63 #endif
64 }
65 
66 // wrap some python 3 function to also work in python 2 (the wrappers have suffix _Py2Py2
67 // and are later defined without the suffix as a macro)
68 
69 inline bool PyLong_Check_Py2Py3(PyObject *o) {
70 #if PY_MAJOR_VERSION < 3
71  return PyLong_Check(o) || PyInt_Check(o);
72 #else
73  return PyLong_Check(o);
74 #endif
75 }
76 
77 inline long PyLong_AsLong_Py2Py3(PyObject *o) {
78 #if PY_MAJOR_VERSION < 3
79  if(PyInt_Check(o))
80  return PyInt_AsLong(o);
81  return PyLong_AsLong(o);
82 #else
83  return PyLong_AsLong(o);
84 #endif
85 }
86 
87 inline bool PyUnicode_Check_Py2Py3(PyObject *o) {
88 #if PY_MAJOR_VERSION < 3
89  return PyUnicode_Check(o) || PyString_Check(o);
90 #else
91  return PyUnicode_Check(o);
92 #endif
93 }
94 
95 // we cannot return char* here since for python 3 this would lead to a reference to a temporary
96 inline std::string PyUnicode_AsUTF8_Py2Py3(PyObject *o) {
97 #if PY_MAJOR_VERSION < 3
98  if(PyString_Check(o)) {
99  char *retc=PyString_AsString(o);
100  if(!retc) return "";
101  return retc;
102  }
103  PyObject *str=PyUnicode_AsUTF8String(o);
104  if(!str) return "";
105  char *retc=PyString_AsString(str);
106  if(!retc) {
107  Py_DECREF(str);
108  return "";
109  }
110  std::string ret=retc;
111  Py_DECREF(str);
112  return ret;
113 #else
114  char *retc=PyUnicode_AsUTF8(o);
115  if(!retc) return "";
116  return retc;
117 #endif
118 }
119 
120 // now define the wrappers without the suffix: now the wrappers are active!!!!!
121 
122 #undef PyLong_Check
123 #undef PyUnicode_Check
124 #define PyLong_Check PythonCpp::PyLong_Check_Py2Py3
125 #define PyLong_AsLong PythonCpp::PyLong_AsLong_Py2Py3
126 #define PyUnicode_Check PythonCpp::PyUnicode_Check_Py2Py3
127 #define PyUnicode_AsUTF8 PythonCpp::PyUnicode_AsUTF8_Py2Py3
128 
129 // make PyRun_String a function
130 inline PyObject* PyRun_String_func(const char *str, int start, PyObject *globals, PyObject *locals) { return PyRun_String(str, start, globals, locals); }
131 #undef PyRun_String
132 #define PyRun_String PythonCpp::PyRun_String_func
133 
134 // make PyFloat_Check a function
135 inline int PyFloat_Check_func(PyObject *p) { return PyFloat_Check(p); }
136 #undef PyFloat_Check
137 #define PyFloat_Check PythonCpp::PyFloat_Check_func
138 
139 // make PyFloat_AS_DOUBLE a function
140 inline int PyFloat_AS_DOUBLE_func(PyObject *p) { return PyFloat_AS_DOUBLE(p); }
141 #undef PyFloat_AS_DOUBLE
142 #define PyFloat_AS_DOUBLE PythonCpp::PyFloat_AS_DOUBLE_func
143 
144 // make PyBool_Check a function
145 inline int PyBool_Check_func(PyObject *p) { return PyBool_Check(p); }
146 #undef PyBool_Check
147 #define PyBool_Check PythonCpp::PyBool_Check_func
148 
149 // make PyList_Check a function
150 inline int PyList_Check_func(PyObject *p) { return PyList_Check(p); }
151 #undef PyList_Check
152 #define PyList_Check PythonCpp::PyList_Check_func
153 
154 // make PyObject_TypeCheck a function
155 inline int PyObject_TypeCheck_func(PyObject *p, PyTypeObject *type) { return PyObject_TypeCheck(p, type); }
156 #undef PyObject_TypeCheck
157 #define PyObject_TypeCheck PythonCpp::PyObject_TypeCheck_func
158 
159 // we use this for python object for c++ reference counting
160 typedef boost::shared_ptr<PyObject> PyO;
161 
162 // A Python error exception object.
163 // Stores the file and line number of the C++ file where the error occured.
164 // Stores also the Python error objects type, value and traceback.
165 class PythonException : public std::exception {
166  public:
167  PythonException(const char *file_, int line_);
168  ~PythonException() throw() {}
169  std::string getFile() { return file; }
170  int getLine() { return line; }
171  PyO getType() { return type; }
172  PyO getValue() { return value; }
173  PyO getTraceback() { return traceback; }
174  const char* what() const throw();
175  private:
176  std::string file;
177  int line;
178  PyO type, value, traceback;
179  mutable std::string msg;
180 };
181 
182 // check for a python exception and throw a PythonException if one exists
183 void checkPythonError() {
184  if(PyErr_Occurred())
185  throw PythonException("", 0);
186 }
187 
188 // helper struct to map the return type of the callPy function
189 // default: map to the same type
190 template<typename T>
191 struct MapRetType {
192  typedef T type;
193  inline static type convert(const T &r) {
194  return r;
195  }
196 };
197 // specialization: map PyObject* to PyO
198 template<> struct MapRetType<PyObject*> {
199  typedef PyO type;
200  inline static PyO convert(PyObject *r) {
201  if(!r)
202  throw std::runtime_error("Internal error: Expected python object but got NULL pointer and not python exception is set.");
203  return PyO(r, &Py_DecRef);
204  }
205 };
206 
207 // helper function to map the argument types of the callPy function
208 // default: map to the same type
209 template<typename Arg>
210 inline Arg convertArg(const Arg &arg) {
211  return arg;
212 }
213 // specialization:: map PyO to PyObject*
214 inline PyObject* convertArg(const PyO &o) {
215  if(o && Py_REFCNT(o.get())<=0)
216  throw std::runtime_error("Internal error: access object with reference count <= 0. Check the source code.");
217  return o.get();
218 }
219 // specialization:: map std::string to const char*
220 inline const char* convertArg(const std::string &o) {
221  return o.c_str();
222 }
223 
224 // Call Python function func with arguments args.
225 // Use the macro CALLPY or CALLPYB, see below.
226 /* when we used c++11 replace all the following code with this c++11 code:
227 template<typename PyRet, typename... PyArgs, typename... CallArgs>
228 inline typename MapRetType<PyRet>::type callPy(const char *file, int line, PyRet (*func)(PyArgs...), CallArgs... args) {
229  PyRet ret=func(convertArg(args1)...);
230  if(PyErr_Occurred())
231  throw PythonException(file, line);
232  return MapRetType<PyRet>::convert(ret);
233 }
234 */
235 // 0 arg
236 template<typename PyRet>
237 inline typename MapRetType<PyRet>::type callPy(const char *file, int line, PyRet (*func)()) {
238  PyRet ret=func();
239  if(PyErr_Occurred())
240  throw PythonException(file, line);
241  return MapRetType<PyRet>::convert(ret);
242 }
243 // 1 arg
244 template<typename PyRet, typename PyArgs1, typename CallArgs1>
245 inline typename MapRetType<PyRet>::type callPy(const char *file, int line, PyRet (*func)(PyArgs1), CallArgs1 args1) {
246  PyRet ret=func(convertArg(args1));
247  if(PyErr_Occurred())
248  throw PythonException(file, line);
249  return MapRetType<PyRet>::convert(ret);
250 }
251 // 2 arg
252 template<typename PyRet, typename PyArgs1, typename PyArgs2, typename CallArgs1, typename CallArgs2>
253 inline typename MapRetType<PyRet>::type callPy(const char *file, int line, PyRet (*func)(PyArgs1, PyArgs2), CallArgs1 args1, CallArgs2 args2) {
254  PyRet ret=func(convertArg(args1), convertArg(args2));
255  if(PyErr_Occurred())
256  throw PythonException(file, line);
257  return MapRetType<PyRet>::convert(ret);
258 }
259 // 3 arg
260 template<typename PyRet, typename PyArgs1, typename PyArgs2, typename PyArgs3, typename CallArgs1, typename CallArgs2, typename CallArgs3>
261 inline typename MapRetType<PyRet>::type callPy(const char *file, int line, PyRet (*func)(PyArgs1, PyArgs2, PyArgs3), CallArgs1 args1, CallArgs2 args2, CallArgs3 args3) {
262  PyRet ret=func(convertArg(args1), convertArg(args2), convertArg(args3));
263  if(PyErr_Occurred())
264  throw PythonException(file, line);
265  return MapRetType<PyRet>::convert(ret);
266 }
267 // 4 arg
268 template<typename PyRet, typename PyArgs1, typename PyArgs2, typename PyArgs3, typename PyArgs4, typename CallArgs1, typename CallArgs2, typename CallArgs3, typename CallArgs4>
269 inline typename MapRetType<PyRet>::type callPy(const char *file, int line, PyRet (*func)(PyArgs1, PyArgs2, PyArgs3, PyArgs4), CallArgs1 args1, CallArgs2 args2, CallArgs3 args3, CallArgs4 args4) {
270  PyRet ret=func(convertArg(args1), convertArg(args2), convertArg(args3), convertArg(args4));
271  if(PyErr_Occurred())
272  throw PythonException(file, line);
273  return MapRetType<PyRet>::convert(ret);
274 }
275 // 5 arg
276 template<typename PyRet, typename PyArgs1, typename PyArgs2, typename PyArgs3, typename PyArgs4, typename PyArgs5, typename CallArgs1, typename CallArgs2, typename CallArgs3, typename CallArgs4, typename CallArgs5>
277 inline typename MapRetType<PyRet>::type callPy(const char *file, int line, PyRet (*func)(PyArgs1, PyArgs2, PyArgs3, PyArgs4, PyArgs5), CallArgs1 args1, CallArgs2 args2, CallArgs3 args3, CallArgs4 args4, CallArgs5 args5) {
278  PyRet ret=func(convertArg(args1), convertArg(args2), convertArg(args3), convertArg(args4), convertArg(args5));
279  if(PyErr_Occurred())
280  throw PythonException(file, line);
281  return MapRetType<PyRet>::convert(ret);
282 }
283 
284 // Macro to call callPy(...)
285 // Use this macro to call a python function returning a new reference to a python object or any other return type.
286 // Note, if the python function steals a reference of any of this arguments you have to call PyIncRef on
287 // each such arguments after the call.
288 #define CALLPY(...) PythonCpp::callPy(__FILE__, __LINE__, __VA_ARGS__)
289 
290 // Macro to call PyIncRef(callPy(...))
291 // Use this macro to call a python function returning a borrowed reference to a python object.
292 // Note, if the python function steals a reference of any of this arguments you have to call PyIncRef on
293 // each such arguments after the call.
294 #define CALLPYB(...) PythonCpp::PyIncRef(PythonCpp::callPy(__FILE__, __LINE__, __VA_ARGS__))
295 
296 // increment the reference count of a python object.
297 // This function MUST be called after a reference is stolen by a python call.
298 inline const PyO& PyIncRef(const PyO &o) {
299  if(Py_REFCNT(o.get())<=0)
300  throw std::runtime_error("Internal error: Access object with reference count <= 0. Check the source code.");
301  Py_XINCREF(o.get());
302  return o;
303 }
304 
305 // c++ PythonException exception with the content of a python exception
306 PythonException::PythonException(const char *file_, int line_) : file(file_), line(line_) {
307  // fetch if error has occured
308  if(!PyErr_Occurred())
309  throw std::runtime_error("Internal error: PythonException object created but no python error occured.");
310  // fetch error objects and save objects
311  PyObject *type_, *value_, *traceback_;
312  PyErr_Fetch(&type_, &value_, &traceback_);
313  type=PyO(type_, &Py_DecRef);
314  value=PyO(value_, &Py_DecRef);
315  traceback=PyO(traceback_, &Py_DecRef);
316 }
317 
318 const char* PythonException::what() const throw() {
319  if(!msg.empty())
320  return msg.c_str();
321 
322  // redirect stderr
323  PyObject *savedstderr=PySys_GetObject(const_cast<char*>("stderr"));
324  if(!savedstderr)
325  throw std::runtime_error("Internal error: no sys.stderr available.");
326  PyObject *io=PyImport_ImportModule("io");
327  if(!io)
328  throw std::runtime_error("Internal error: cannot load io module.");
329 #if PY_MAJOR_VERSION < 3
330  PyObject *fileIO=PyObject_GetAttrString(io, "BytesIO"); // sys.stderr is a file is bytes mode
331 #else
332  PyObject *fileIO=PyObject_GetAttrString(io, "StringIO"); // sys.stderr is a file in text mode
333 #endif
334  if(!fileIO)
335  throw std::runtime_error("Internal error: cannot get in memory file class.");
336  Py_DECREF(io);
337  PyObject *buf=PyObject_CallObject(fileIO, NULL);
338  Py_DECREF(fileIO);
339  if(!buf)
340  throw std::runtime_error("Internal error: cannot create new in memory file instance");
341  if(PySys_SetObject(const_cast<char*>("stderr"), buf)!=0)
342  throw std::runtime_error("Internal error: cannot redirect stderr");
343  // restore error
344  PyErr_Restore(type.get(), value.get(), traceback.get());
345  Py_XINCREF(type.get());
346  Py_XINCREF(value.get());
347  Py_XINCREF(traceback.get());
348  // print to redirected stderr
349  PyErr_Print();
350  // unredirect stderr
351  if(PySys_SetObject(const_cast<char*>("stderr"), savedstderr)!=0)
352  throw std::runtime_error("Internal error: cannot revert redirect stderr");
353  // get redirected output as string
354  PyObject *getvalue=PyObject_GetAttrString(buf, "getvalue");
355  if(!getvalue)
356  throw std::runtime_error("Internal error: cannot get getvalue attribute");
357  PyObject *pybufstr=PyObject_CallObject(getvalue, NULL);
358  if(!pybufstr)
359  throw std::runtime_error("Internal error: cannot get string from in memory file output");
360  Py_DECREF(getvalue);
361  Py_DECREF(buf);
362 #if PY_MAJOR_VERSION < 3
363  char *strc=PyBytes_AsString(pybufstr); // sys.stderr is a file in bytes mode
364  if(!strc)
365  throw std::runtime_error("Internal error: cannot get c string");
366  std::string str(strc);
367 #else
368  std::string str=PyUnicode_AsUTF8(pybufstr); // sys.stderr is a file in text mode
369  if(PyErr_Occurred())
370  throw std::runtime_error("Internal error: cannot get c string");
371 #endif
372  Py_DECREF(pybufstr);
373  std::stringstream strstr;
374  strstr<<"Python exception";
375  if(!file.empty())
376  strstr<<" at "<<file<<":"<<line;
377  strstr<<":"<<std::endl<<str;;
378  msg=strstr.str();
379  return msg.c_str();
380 }
381 
382 }
383 
384 #endif
Definition: py2py3cppwrapper.h:165
Definition: py2py3cppwrapper.h:191

Impressum / Disclaimer / Datenschutz Generated by doxygen 1.8.5 Valid HTML