Mantid
Loading...
Searching...
No Matches
PyNativeTypeExtractor.h
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2021 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
7#pragma once
10
11#include <boost/python/extract.hpp>
12#include <boost/python/list.hpp>
13#include <boost/python/object.hpp>
14#include <boost/variant.hpp>
15
16#include <exception>
17#include <string>
18#include <variant>
19#include <vector>
20
21namespace {
22Mantid::Kernel::Logger g_log("Python Type Extractor");
23}
24
26
28 using PythonOutputT = boost::make_recursive_variant<bool, long, double, std::string, Mantid::API::Workspace_sptr,
29 std::vector<boost::recursive_variant_>>::type;
30
31 static PythonOutputT convert(const boost::python::object &obj) {
32 using namespace boost::python;
33 PyObject *rawptr = obj.ptr();
34 PythonOutputT out;
35
36 if (PyList_Check(rawptr)) {
37 out = handleList(obj);
38 } else if (PyBool_Check(rawptr)) {
39 out = extract<bool>(obj);
40 } else if (PyFloat_Check(rawptr)) {
41 out = extract<double>(obj);
42 } else if (PyLong_Check(rawptr)) {
43 out = extract<long>(obj);
44 } else if (PyUnicode_Check(rawptr)) {
45 out = extract<std::string>(obj);
46 } else if (auto extractor = extract<Mantid::API::Workspace_sptr>(obj); extractor.check()) {
47 out = extractor();
48 } else {
49 throw std::invalid_argument("Unrecognised Python type");
50 }
51 return out;
52 }
53
54private:
55 static PythonOutputT handleList(const boost::python::object &obj) {
56 auto rawptr = obj.ptr();
57 auto n = PyList_Size(rawptr);
58 auto vec = std::vector<PythonOutputT>();
59 vec.reserve(n);
60 for (Py_ssize_t i = 0; i < n; ++i) {
61 vec.emplace_back(convert(obj[i]));
62 }
63 return vec;
64 }
65};
66
67class IPyTypeVisitor : public boost::static_visitor<> {
68public:
80 virtual ~IPyTypeVisitor() = default;
81 virtual void operator()(bool value) const = 0;
82 virtual void operator()(long value) const = 0;
83 virtual void operator()(double value) const = 0;
84 virtual void operator()(std::string) const = 0;
85 virtual void operator()(Mantid::API::Workspace_sptr) const = 0;
86
87 virtual void operator()(std::vector<bool>) const = 0;
88 virtual void operator()(std::vector<long>) const = 0;
89 virtual void operator()(std::vector<double>) const = 0;
90 virtual void operator()(std::vector<std::string>) const = 0;
91
92 void operator()(std::vector<PyNativeTypeExtractor::PythonOutputT> const &values) const {
93 if (values.size() == 0)
94 return;
95 const auto &elemType = values[0].type();
96
97 // We must manually dispatch for container types, as boost will try
98 // to recurse down to scalar values.
99 if (elemType == typeid(bool)) {
100 applyVectorProp<bool>(values);
101 } else if (elemType == typeid(double)) {
102 applyVectorProp<double>(values);
103 } else if (elemType == typeid(long)) {
104 applyVectorProp<long>(values);
105 } else if (elemType == typeid(std::string)) {
106 applyVectorProp<std::string>(values);
107 } else {
108 // Recurse down
109 for (const auto &val : values) {
110 boost::apply_visitor(*this, val);
111 }
112 }
113 }
114
115private:
116 template <typename ScalarT>
117 void applyVectorProp(const std::vector<Mantid::PythonInterface::PyNativeTypeExtractor::PythonOutputT> &values) const {
118 std::vector<ScalarT> propVals;
119 propVals.reserve(values.size());
120
121 // Explicitly copy so we don't have to think about Python lifetimes with refs
122 try {
123
124 std::transform(values.cbegin(), values.cend(), std::back_inserter(propVals),
126 return boost::get<ScalarT>(varadicVal);
127 });
128 } catch (boost::bad_get &e) {
129 std::string err{
130 "A list with mixed types is unsupported as precision loss can occur trying to determine a common type."
131 " \nOriginal exception: "};
132 // Boost will convert bad_get into runtime_error anyway....
133 throw std::runtime_error(err + e.what());
134 }
135 this->operator()(std::move(propVals));
136 }
137};
138
139} // namespace Mantid::PythonInterface
double value
The value of the point.
Definition: FitMW.cpp:51
double obj
the value of the quadratic function
The Logger class is in charge of the publishing messages from the framework through various channels.
Definition: Logger.h:52
void operator()(std::vector< PyNativeTypeExtractor::PythonOutputT > const &values) const
virtual void operator()(bool value) const =0
void applyVectorProp(const std::vector< Mantid::PythonInterface::PyNativeTypeExtractor::PythonOutputT > &values) const
virtual void operator()(std::vector< bool >) const =0
virtual void operator()(std::vector< long >) const =0
virtual void operator()(std::vector< std::string >) const =0
virtual ~IPyTypeVisitor()=default
Dynamically dispatches to overloaded operator depending on the underlying type.
virtual void operator()(std::vector< double >) const =0
virtual void operator()(std::string) const =0
virtual void operator()(long value) const =0
virtual void operator()(Mantid::API::Workspace_sptr) const =0
virtual void operator()(double value) const =0
std::shared_ptr< Workspace > Workspace_sptr
shared pointer to Mantid::API::Workspace
Definition: Workspace_fwd.h:20
Kernel::Logger g_log("ExperimentInfo")
static logger object
static PythonOutputT convert(const boost::python::object &obj)
static PythonOutputT handleList(const boost::python::object &obj)
boost::make_recursive_variant< bool, long, double, std::string, Mantid::API::Workspace_sptr, std::vector< boost::recursive_variant_ > >::type PythonOutputT