| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent e09db39 commit dfdab7c
2 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,93 @@ | |||
| 1 | + /* This program is free software; you can redistribute it and/or modify | ||
| 2 | + * it under the terms of the GNU General Public License as published by | ||
| 3 | + * the Free Software Foundation; either version 3 of the License, or | ||
| 4 | + * (at your option) any later version. | ||
| 5 | + * | ||
| 6 | + * This program is distributed in the hope that it will be useful, | ||
| 7 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 8 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 9 | + * GNU General Public License for more details. | ||
| 10 | + * | ||
| 11 | + * You should have received a copy of the GNU General Public License | ||
| 12 | + * along with this program; if not, write to the Free Software | ||
| 13 | + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, | ||
| 14 | + * MA 02110-1301, USA. | ||
| 15 | + * | ||
| 16 | + * Author: | ||
| 17 | + * Matias Fontanini | ||
| 18 | + * | ||
| 19 | + */ | ||
| 20 | + | ||
| 21 | + #include <array> | ||
| 22 | + #include "pywrapper.h" | ||
| 23 | + | ||
| 24 | + using std::runtime_error; | ||
| 25 | + using std::string; | ||
| 26 | + | ||
| 27 | + Python::Script::Script(const string &script_path) | ||
| 28 | + throw(runtime_error) { | ||
| 29 | + Py_Initialize(); | ||
| 30 | + char arr[] = "path"; | ||
| 31 | + //pyunique_ptr path(PySys_GetObject("path")); | ||
| 32 | + PyObject *path(PySys_GetObject(arr)); | ||
| 33 | + pyunique_ptr pwd(PyString_FromString(".")); | ||
| 34 | + PyList_Insert(path, 0, pwd.get()); | ||
| 35 | + /* We don't need that string value anymore, so deref it */ | ||
| 36 | + module.reset(PyImport_ImportModule(script_path.c_str())); | ||
| 37 | + if(!module.get()) | ||
| 38 | + throw runtime_error("Failed to load script"); | ||
| 39 | + } | ||
| 40 | + | ||
| 41 | + PyObject *Python::Script::load_function(const std::string &name) | ||
| 42 | + throw(runtime_error) { | ||
| 43 | + auto it(functions.find(name)); | ||
| 44 | + // Is it cached? | ||
| 45 | + if(it == functions.end()) { | ||
| 46 | + PyObject *obj(PyObject_GetAttrString(module.get(), name.c_str())); | ||
| 47 | + if(!obj) | ||
| 48 | + throw std::runtime_error("Failed to load function"); | ||
| 49 | + functions[name] = obj; | ||
| 50 | + return obj; | ||
| 51 | + } | ||
| 52 | + else | ||
| 53 | + return it->second; | ||
| 54 | + } | ||
| 55 | + | ||
| 56 | + PyObject *Python::alloc_pyobject(const std::string &str) { | ||
| 57 | + return PyString_FromString(str.c_str()); | ||
| 58 | + } | ||
| 59 | + | ||
| 60 | + PyObject *Python::alloc_pyobject(int num) { | ||
| 61 | + return PyInt_FromLong(num); | ||
| 62 | + } | ||
| 63 | + | ||
| 64 | + PyObject *Python::alloc_pyobject(double num) { | ||
| 65 | + return PyFloat_FromDouble(num); | ||
| 66 | + } | ||
| 67 | + | ||
| 68 | + bool is_py_int(PyObject *obj) { | ||
| 69 | + return PyInt_Check(obj); | ||
| 70 | + } | ||
| 71 | + | ||
| 72 | + bool is_py_float(PyObject *obj) { | ||
| 73 | + return PyFloat_Check(obj); | ||
| 74 | + } | ||
| 75 | + | ||
| 76 | + bool Python::convert(PyObject *obj, std::string &val) { | ||
| 77 | + if(!PyString_Check(obj)) | ||
| 78 | + return false; | ||
| 79 | + val = PyString_AsString(obj); | ||
| 80 | + return true; | ||
| 81 | + } | ||
| 82 | + | ||
| 83 | + bool Python::convert(PyObject *obj, Py_ssize_t &val) { | ||
| 84 | + return generic_convert<Py_ssize_t>(obj, is_py_int, PyInt_AsSsize_t, val); | ||
| 85 | + } | ||
| 86 | + | ||
| 87 | + bool Python::convert(PyObject *obj, double &val) { | ||
| 88 | + return generic_convert<double>(obj, is_py_float, PyFloat_AsDouble, val); | ||
| 89 | + } | ||
| 90 | + | ||
| 91 | + bool Python::convert(PyObject *obj, long &val) { | ||
| 92 | + return generic_convert<long>(obj, is_py_int, PyInt_AsLong, val); | ||
| 93 | + } | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,229 @@ | |||
| 1 | + /* This program is free software; you can redistribute it and/or modify | ||
| 2 | + * it under the terms of the GNU General Public License as published by | ||
| 3 | + * the Free Software Foundation; either version 3 of the License, or | ||
| 4 | + * (at your option) any later version. | ||
| 5 | + * | ||
| 6 | + * This program is distributed in the hope that it will be useful, | ||
| 7 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 8 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 9 | + * GNU General Public License for more details. | ||
| 10 | + * | ||
| 11 | + * You should have received a copy of the GNU General Public License | ||
| 12 | + * along with this program; if not, write to the Free Software | ||
| 13 | + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, | ||
| 14 | + * MA 02110-1301, USA. | ||
| 15 | + * | ||
| 16 | + * Author: | ||
| 17 | + * Matias Fontanini | ||
| 18 | + * | ||
| 19 | + */ | ||
| 20 | + | ||
| 21 | + #ifndef __PYWRAPPER_H | ||
| 22 | + #define __PYWRAPPER_H | ||
| 23 | + | ||
| 24 | + #include <string> | ||
| 25 | + #include <stdexcept> | ||
| 26 | + #include <utility> | ||
| 27 | + #include <memory> | ||
| 28 | + #include <map> | ||
| 29 | + #include <vector> | ||
| 30 | + #include <list> | ||
| 31 | + #include <tuple> | ||
| 32 | + #include <python2.7/Python.h> | ||
| 33 | + | ||
| 34 | + | ||
| 35 | + namespace Python { | ||
| 36 | + // Deleter that calls Py_XDECREF on the PyObject parameter. | ||
| 37 | + struct PyObjectDeleter { | ||
| 38 | + void operator()(PyObject *obj) { | ||
| 39 | + Py_XDECREF(obj); | ||
| 40 | + } | ||
| 41 | + }; | ||
| 42 | + // unique_ptr that uses Py_XDECREF as the destructor function. | ||
| 43 | + typedef std::unique_ptr<PyObject, PyObjectDeleter> pyunique_ptr; | ||
| 44 | + | ||
| 45 | + // ------------ Conversion functions ------------ | ||
| 46 | + | ||
| 47 | + // Convert a PyObject to a std::string. | ||
| 48 | + bool convert(PyObject *obj, std::string &val); | ||
| 49 | + // Convert a PyObject to a ssize_t. | ||
| 50 | + bool convert(PyObject *obj, Py_ssize_t &val); | ||
| 51 | + // Convert a PyObject to a long. | ||
| 52 | + bool convert(PyObject *obj, long &val); | ||
| 53 | + // Convert a PyObject to an float. | ||
| 54 | + bool convert(PyObject *obj, double &val); | ||
| 55 | + | ||
| 56 | + // Helper class to use when constructing tuples from PyObjects | ||
| 57 | + template<class Tuple, std::size_t N> | ||
| 58 | + struct TupleCreater { | ||
| 59 | + static bool initialize(PyObject *obj, Tuple &tup) { | ||
| 60 | + TupleCreater<Tuple, N-1>::initialize(obj, tup); | ||
| 61 | + return convert(PyTuple_GetItem(obj, N-1), std::get<N-1>(tup)); | ||
| 62 | + } | ||
| 63 | + }; | ||
| 64 | + template<class Tuple> | ||
| 65 | + struct TupleCreater<Tuple, 1> { | ||
| 66 | + static bool initialize(PyObject *obj, Tuple &tup) { | ||
| 67 | + return convert(PyTuple_GetItem(obj, 0), std::get<0>(tup)); | ||
| 68 | + } | ||
| 69 | + }; | ||
| 70 | + // Convert a PyObject to a std::tuple. | ||
| 71 | + template<class... Args> | ||
| 72 | + bool convert(PyObject *obj, std::tuple<Args...> &tup) { | ||
| 73 | + if(!PyTuple_Check(obj) || | ||
| 74 | + PyTuple_Size(obj) != sizeof...(Args)) | ||
| 75 | + return false; | ||
| 76 | + return TupleCreater<decltype(tup), sizeof...(Args)>::initialize(obj, tup); | ||
| 77 | + } | ||
| 78 | + // Convert a PyObject to a std::map | ||
| 79 | + template<class K, class V> | ||
| 80 | + bool convert(PyObject *obj, std::map<K, V> &mp) { | ||
| 81 | + if(!PyDict_Check(obj)) | ||
| 82 | + return false; | ||
| 83 | + PyObject *py_key, *py_val; | ||
| 84 | + Py_ssize_t pos(0); | ||
| 85 | + while (PyDict_Next(obj, &pos, &py_key, &py_val)) { | ||
| 86 | + K key; | ||
| 87 | + if(!convert(py_key, key)) | ||
| 88 | + return false; | ||
| 89 | + V val; | ||
| 90 | + if(!convert(py_val, val)) | ||
| 91 | + return false; | ||
| 92 | + mp.insert(std::make_pair(key, val)); | ||
| 93 | + } | ||
| 94 | + return true; | ||
| 95 | + } | ||
| 96 | + // Convert a PyObject to a generic container. | ||
| 97 | + template<class T, class C> | ||
| 98 | + bool convert_list(PyObject *obj, C &container) { | ||
| 99 | + if(!PyList_Check(obj)) | ||
| 100 | + return false; | ||
| 101 | + for(Py_ssize_t i(0); i < PyList_Size(obj); ++i) { | ||
| 102 | + T val; | ||
| 103 | + if(!convert(PyList_GetItem(obj, i), val)) | ||
| 104 | + return false; | ||
| 105 | + container.push_back(std::move(val)); | ||
| 106 | + } | ||
| 107 | + return true; | ||
| 108 | + } | ||
| 109 | + // Convert a PyObject to a std::list. | ||
| 110 | + template<class T> bool convert(PyObject *obj, std::list<T> &lst) { | ||
| 111 | + return convert_list<T, std::list<T>>(obj, lst); | ||
| 112 | + } | ||
| 113 | + // Convert a PyObject to a std::vector. | ||
| 114 | + template<class T> bool convert(PyObject *obj, std::vector<T> &vec) { | ||
| 115 | + return convert_list<T, std::vector<T>>(obj, vec); | ||
| 116 | + } | ||
| 117 | + | ||
| 118 | + template<class T> bool generic_convert(PyObject *obj, | ||
| 119 | + const std::function<bool(PyObject*)> &is_obj, | ||
| 120 | + const std::function<T(PyObject*)> &converter, | ||
| 121 | + T &val) { | ||
| 122 | + if(!is_obj(obj)) | ||
| 123 | + return false; | ||
| 124 | + val = converter(obj); | ||
| 125 | + return true; | ||
| 126 | + } | ||
| 127 | + | ||
| 128 | + // -------------- PyObject allocators ---------------- | ||
| 129 | + | ||
| 130 | + // Generic python list allocation | ||
| 131 | + template<class T> static PyObject *alloc_list(const T &container) { | ||
| 132 | + PyObject *lst(PyList_New(container.size())); | ||
| 133 | + | ||
| 134 | + Py_ssize_t i(0); | ||
| 135 | + for(auto it(container.begin()); it != container.end(); ++it) | ||
| 136 | + PyList_SetItem(lst, i++, alloc_pyobject(*it)); | ||
| 137 | + | ||
| 138 | + return lst; | ||
| 139 | + } | ||
| 140 | + // Creates a PyObject from a std::string | ||
| 141 | + PyObject *alloc_pyobject(const std::string &str); | ||
| 142 | + // Creates a PyObject from an int | ||
| 143 | + PyObject *alloc_pyobject(int num); | ||
| 144 | + // Creates a PyObject from a double | ||
| 145 | + PyObject *alloc_pyobject(double num); | ||
| 146 | + // Creates a PyObject from a std::vector | ||
| 147 | + template<class T> PyObject *alloc_pyobject(const std::vector<T> &container) { | ||
| 148 | + return alloc_list(container); | ||
| 149 | + } | ||
| 150 | + // Creates a PyObject from a std::list | ||
| 151 | + template<class T> PyObject *alloc_pyobject(const std::list<T> &container) { | ||
| 152 | + return alloc_list(container); | ||
| 153 | + } | ||
| 154 | + // Creates a PyObject from a std::map | ||
| 155 | + template<class T, class K> PyObject *alloc_pyobject( | ||
| 156 | + const std::map<T, K> &container) { | ||
| 157 | + PyObject *dict(PyDict_New()); | ||
| 158 | + | ||
| 159 | + for(auto it(container.begin()); it != container.end(); ++it) | ||
| 160 | + PyDict_SetItem(dict, | ||
| 161 | + alloc_pyobject(it->first), | ||
| 162 | + alloc_pyobject(it->second) | ||
| 163 | + ); | ||
| 164 | + | ||
| 165 | + return dict; | ||
| 166 | + } | ||
| 167 | + | ||
| 168 | + // This class is an abstraction of a python script. | ||
| 169 | + class Script { | ||
| 170 | + public: | ||
| 171 | + // Script constructor that takes the script path as the name. | ||
| 172 | + Script(const std::string &script_path) throw(std::runtime_error); | ||
| 173 | + | ||
| 174 | + // Calls the function named "name" using the arguments "args". | ||
| 175 | + template<typename... Args> | ||
| 176 | + pyunique_ptr call_function(const std::string &name, Args... args) | ||
| 177 | + throw(std::runtime_error) { | ||
| 178 | + PyObject *func(load_function(name)); | ||
| 179 | + // Create the tuple argument | ||
| 180 | + pyunique_ptr tup(PyTuple_New(sizeof...(args))); | ||
| 181 | + add_tuple_vars(tup, args...); | ||
| 182 | + // Call our object | ||
| 183 | + PyObject *ret(PyObject_CallObject(func, tup.get())); | ||
| 184 | + if(!ret) | ||
| 185 | + throw std::runtime_error("Failed to call function"); | ||
| 186 | + return pyunique_ptr(ret); | ||
| 187 | + } | ||
| 188 | + | ||
| 189 | + pyunique_ptr call_function(const std::string &name) | ||
| 190 | + throw(std::runtime_error) { | ||
| 191 | + PyObject *func(load_function(name)); | ||
| 192 | + PyObject *ret(PyObject_CallObject(func, 0)); | ||
| 193 | + if(!ret) | ||
| 194 | + throw std::runtime_error("Failed to call function"); | ||
| 195 | + return pyunique_ptr(ret); | ||
| 196 | + } | ||
| 197 | + private: | ||
| 198 | + PyObject *load_function(const std::string &name) | ||
| 199 | + throw(std::runtime_error); | ||
| 200 | + | ||
| 201 | + // Variadic template method to add items to a tuple | ||
| 202 | + template<typename First, typename... Rest> | ||
| 203 | + void add_tuple_vars(pyunique_ptr &tup, First head, Rest... tail) { | ||
| 204 | + add_tuple_var( | ||
| 205 | + tup, | ||
| 206 | + PyTuple_Size(tup.get()) - sizeof...(tail) - 1, | ||
| 207 | + alloc_pyobject(head) | ||
| 208 | + ); | ||
| 209 | + add_tuple_vars(tup, tail...); | ||
| 210 | + } | ||
| 211 | + | ||
| 212 | + // Base case for add_tuple_vars | ||
| 213 | + template<typename Arg> | ||
| 214 | + void add_tuple_vars(pyunique_ptr &tup, Arg arg) { | ||
| 215 | + add_tuple_var(tup, PyTuple_Size(tup.get()) - 1, alloc_pyobject(arg)); | ||
| 216 | + } | ||
| 217 | + | ||
| 218 | + // Adds a PyObject* to the tuple object | ||
| 219 | + void add_tuple_var(pyunique_ptr &tup, Py_ssize_t i, PyObject *pobj) { | ||
| 220 | + PyTuple_SetItem(tup.get(), i, pobj); | ||
| 221 | + } | ||
| 222 | + | ||
| 223 | + pyunique_ptr module; | ||
| 224 | + std::map<std::string, PyObject*> functions; | ||
| 225 | + }; | ||
| 226 | + | ||
| 227 | + }; | ||
| 228 | + | ||
| 229 | + #endif // __PYWRAPPER_H | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments