13 #include <boost/python/object.hpp>
14 #include <boost/python/list.hpp>
15 #include <boost/python/tuple.hpp>
16 #include <boost/python/dict.hpp>
17 #include <boost/python/extract.hpp>
19 #include <boost/variant.hpp>
20 #include <boost/optional.hpp>
43 namespace PyObjConvUtils {
62 bool checkPythonObject(
const boost::python::object& pyObject,
const std::string&);
63 template<
typename Key,
typename Value>
64 bool checkPythonObject(
const boost::python::object& pyObject,
const std::map<Key, Value>&);
66 template<
typename Value>
67 bool checkPythonObject(
const boost::python::object& pyObject,
const std::vector<Value>&);
69 template<
typename Value>
70 bool checkPythonObject(
const boost::python::object& pyObject,
const std::set<Value>&);
72 template<
typename... Types>
73 bool checkPythonObject(
const boost::python::object& pyObject,
const std::tuple<Types...>&);
75 template<
typename... Types>
76 bool checkPythonObject(
const boost::python::object& pyObject,
const boost::variant<Types...>&);
78 template<
typename Type>
79 bool checkPythonObject(
const boost::python::object& pyObject,
const boost::optional<Type>&);
82 template<
typename Scalar>
85 template<
typename Key,
typename Value>
86 std::map<Key, Value>
convertPythonObject(
const boost::python::object& pyObject,
const std::map<Key, Value>&);
88 template<
typename Value>
89 std::vector<Value>
convertPythonObject(
const boost::python::object& pyObject,
const std::vector<Value>&);
91 template<
typename Value>
92 std::set<Value>
convertPythonObject(
const boost::python::object& pyObject,
const std::set<Value>&);
94 template<
typename... Types>
95 std::tuple<Types...>
convertPythonObject(
const boost::python::object& pyObject,
const std::tuple<Types...>&);
97 template<
typename... Types>
98 boost::variant<Types...>
convertPythonObject(
const boost::python::object& pyObject,
const boost::variant<Types...>&);
100 template<
typename Type>
101 boost::optional<Type>
convertPythonObject(
const boost::python::object& pyObject,
const boost::optional<Type>&);
103 template<
typename Scalar>
105 template<
typename Value>
108 template<
typename Value>
110 template<
typename Key,
typename Value>
112 template<
typename... Types>
114 template<
typename... Types>
117 template<
typename Type>
120 template<
typename T>
struct Type;
121 template<
typename T>
struct Type<std::vector<T> >;
122 template<typename T> struct Type<std::set<T>>;
123 template<typename A, typename B> struct Type<std::map<A, B> >;
124 template<typename... Types> struct Type<std::tuple<Types...> >;
125 template<typename... Types> struct Type<boost::variant<Types...> >;
126 template<> struct Type<int>;
127 template<> struct Type<bool>;
129 template<> struct
Type<double>;
130 template<> struct
Type<std::string>;
132 template< typename T, typename... Types> struct
VariadicType;
136 template<
typename T,
typename... Types>
struct VariadicType {
138 static std::string
name()
148 template<
typename T>
struct Type {
static std::string
name() {
return "???";} };
150 template<
typename T>
struct Type<std::vector<T> > {
static std::string
name() {
return std::string(
"list(") +
Type<T>::name() +
")"; } };
152 template<
typename T>
struct Type<std::set<T>> {
static std::string
name() {
return std::string(
"set(") +
Type<T>::name() +
")"; }};
154 template<
typename A,
typename B>
struct Type<std::map<A, B> > {
static std::string
name() {
return std::string(
"dict(") +
Type<A>::name() +
" -> " +
Type<B>::name() +
")"; } };
157 template<>
struct Type<unsigned int> {
static std::string
name() {
return "unsigned int"; } };
159 template<>
struct Type<unsigned long int> {
static std::string
name() {
return "unsigned long int"; } };
161 template<>
struct Type<int> {
static std::string
name() {
return "int"; } };
163 template<>
struct Type<bool> {
static std::string
name() {
return "bool"; } };
165 template<>
struct Type<float> {
static std::string
name() {
return "float"; } };
167 template<>
struct Type<double> {
static std::string
name() {
return "float"; } };
169 template<>
struct Type<std::string> {
static std::string
name() {
return "str"; } };
172 template<
typename T>
struct Type<boost::optional<T>> {
static std::string
name() {
return Type<T>::name() +
" or None"; } };
181 template<>
struct Type<std::shared_ptr<Path>> {
183 static std::string
name() {
return std::string(
"Path"); }
188 template <
size_t >
struct SizeT { };
197 return PyBool_Check(pyObject.ptr());
203 return PyLong_CheckExact(pyObject.ptr());
206 inline bool checkPythonObject(
const boost::python::object& pyObject,
unsigned int )
208 return PyLong_CheckExact(pyObject.ptr());
212 inline bool checkPythonObject(
const boost::python::object& pyObject,
unsigned long int )
214 return PyLong_CheckExact(pyObject.ptr());
220 return PyFloat_CheckExact(pyObject.ptr());
226 return PyFloat_CheckExact(pyObject.ptr());
230 inline bool checkPythonObject(
const boost::python::object& pyObject,
const std::string& )
232 return PyUnicode_Check(pyObject.ptr());
236 template<
typename Key,
typename Value>
237 bool checkPythonObject(
const boost::python::object& pyObject,
const std::map<Key, Value>& )
239 if (not PyDict_Check(pyObject.ptr()))
return false;
240 const boost::python::dict& pyDict =
static_cast<const boost::python::dict&
>(pyObject);
241 boost::python::list keys = pyDict.keys();
242 boost::python::list values = pyDict.values();
243 for (
int i = 0; i < boost::python::len(keys); ++i) {
257 template<
class Functor>
260 boost::python::object iterator(boost::python::handle<>(PyObject_GetIter(pyObject.ptr())));
261 PyObject* item{
nullptr};
263 while ((item = PyIter_Next(iterator.ptr()))) {
264 boost::python::object obj{boost::python::handle<>(item)};
265 if (not
function(obj))
return false;
271 template<
typename Value>
272 bool checkPythonObject(
const boost::python::object& pyObject,
const std::vector<Value>& )
274 if (not PyList_Check(pyObject.ptr()))
return false;
280 template<
typename Value>
281 bool checkPythonObject(
const boost::python::object& pyObject,
const std::set<Value>&)
283 if (not PyAnySet_Check(pyObject.ptr()))
return false;
290 template<
typename... Types, std::size_t ... Is>
291 bool CheckTuple(
const std::tuple<Types...>& tuple,
const boost::python::tuple& pyTuple,
292 std::index_sequence<Is...>)
298 template<
typename... Types>
299 bool checkPythonObject(
const boost::python::object& pyObject,
const std::tuple<Types...>& tuple)
301 if (not PyTuple_Check(pyObject.ptr()))
return false;
302 const boost::python::tuple& pyTuple =
static_cast<const boost::python::tuple&
>(pyObject);
303 return CheckTuple(tuple, pyTuple, std::index_sequence_for<Types ...>());
307 template<
typename VariantType>
309 const boost::python::object&,
316 template<
typename... Types,
size_t N>
317 bool CheckVariant(
const boost::variant<Types...>& variant,
318 const boost::python::object& pyObject,
321 using Scalar =
typename std::tuple_element < N - 1, std::tuple<Types...> >::type;
329 template<
typename... Types>
330 bool checkPythonObject(
const boost::python::object& pyObject,
const boost::variant<Types...> variant)
332 return CheckVariant(variant, pyObject, SizeT<
sizeof...(Types)>());
338 template<
typename Type>
339 bool checkPythonObject(
const boost::python::object& pyObject,
const boost::optional<Type>&)
354 template<
typename Scalar>
357 return boost::python::object(value);
366 template<
typename Value>
369 boost::python::list outputList;
370 for (
const auto& value : vector) {
380 template<
typename Value>
383 boost::python::object result(boost::python::handle<>(PySet_New(
nullptr)));
384 for (
const auto& value : set) {
396 template<
typename Key,
typename Value>
399 boost::python::dict outputDict;
400 for (
auto pair : map) {
414 template <
typename TupleType >
415 inline void GetTuple(
const TupleType& tuple, boost::python::list& pyList)
417 GetTuple(tuple, pyList,
SizeT<std::tuple_size<TupleType>::value>());
421 template <
typename TupleType >
422 inline void GetTuple(
const TupleType&, boost::python::list&, SizeT<0>) { }
426 template <
typename TupleType,
size_t N >
427 inline void GetTuple(
const TupleType& tuple, boost::python::list& pyList,
SizeT<N>)
440 template<
typename... Types>
443 boost::python::list outputList;
445 boost::python::tuple outputTuple(outputList);
452 class convertToPythonObjectVisitor :
public boost::static_visitor<boost::python::object> {
456 boost::python::object
operator()(
const T& value)
const
468 template<
typename... Types>
481 template<
typename Type>
487 return boost::python::object();
501 template<
typename Scalar>
506 boost::python::extract<Scalar> valueProxy(pyObject);
507 if (valueProxy.check()) {
508 tmpValue =
static_cast<Scalar
>(valueProxy);
510 throw std::runtime_error(std::string(
"Could not convert value: Expected type '") +
Type<Scalar>::name() +
"' instead of '" +
511 pyObject.ptr()->ob_type->tp_name +
"'.");
524 template<
typename Value>
525 std::vector<Value>
convertPythonObject(
const boost::python::object& pyObject,
const std::vector<Value>&)
528 std::vector<Value> tmpVector;
529 if (PyList_Check(pyObject.ptr()) or PyGen_Check(pyObject.ptr())) {
541 template<
typename Value>
542 std::set<Value>
convertPythonObject(
const boost::python::object& pyObject,
const std::set<Value>&)
544 std::set<Value> result;
545 if (PyAnySet_Check(pyObject.ptr())) {
563 template<
typename Key,
typename Value>
564 std::map<Key, Value>
convertPythonObject(
const boost::python::object& pyObject,
const std::map<Key, Value>&)
566 std::map<Key, Value> tmpMap;
567 const boost::python::dict& pyDict =
static_cast<const boost::python::dict&
>(pyObject);
568 boost::python::list keys = pyDict.keys();
570 for (
int i = 0; i < boost::python::len(keys); ++i) {
573 tmpMap.insert(std::pair<Key, Value>(key, value));
587 template <
typename TupleType >
588 inline void SetTuple(TupleType& tuple,
const boost::python::tuple& pyTuple)
590 static const unsigned N = std::tuple_size<TupleType>::value;
591 if ((
unsigned)boost::python::len(pyTuple) != N) {
592 throw std::runtime_error(std::string(
"Given python tuple has length ") +
593 std::to_string(boost::python::len(pyTuple)) +
594 ", expected " + std::to_string(N));
600 template <
typename TupleType >
601 inline void SetTuple(TupleType&,
const boost::python::tuple&, SizeT<0>) { }
605 template <
typename TupleType,
size_t N >
606 inline void SetTuple(TupleType& tuple,
const boost::python::tuple& pyTuple, SizeT<N>)
608 SetTuple(tuple, pyTuple, SizeT < N - 1 > ());
619 template<
typename... Types>
620 std::tuple<Types...>
convertPythonObject(
const boost::python::object& pyObject,
const std::tuple<Types...>&)
622 std::tuple<Types...> tmpTuple;
623 const boost::python::tuple& pyTuple =
static_cast<const boost::python::tuple&
>(pyObject);
636 template <
typename... Types>
637 inline void SetVariant(boost::variant<Types...>&,
const boost::python::object& pyObject, SizeT<0>)
639 throw std::runtime_error(std::string(
"Could not set module parameter: Expected type '") +
640 Type<boost::variant<Types...> >::name() +
"' instead of '" +
641 pyObject.ptr()->ob_type->tp_name +
"'.");
645 template <
typename... Types,
size_t N >
646 inline void SetVariant(boost::variant<Types...>& variant,
const boost::python::object& pyObject,
SizeT<N>)
648 using Scalar =
typename std::tuple_element < N - 1, std::tuple<Types...> >::type;
654 }
catch (std::runtime_error& e) {
658 SetVariant(variant, pyObject, SizeT < N - 1 > ());
668 template<
typename... Types>
669 boost::variant<Types...>
convertPythonObject(
const boost::python::object& pyObject,
const boost::variant<Types...>&)
671 boost::variant<Types...> tmpVariant;
672 SetVariant(tmpVariant, pyObject, SizeT<
sizeof...(Types)>());
682 template<
typename Type>
683 boost::optional<Type>
convertPythonObject(
const boost::python::object& pyObject,
const boost::optional<Type>&)
685 boost::optional<Type> tmpOptional = boost::none;
686 if (!pyObject.is_none()) {