Mantid
Loading...
Searching...
No Matches
AlgorithmAdapter.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2018 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 +
18
19#include <boost/python/class.hpp>
20#include <boost/python/dict.hpp>
21
22//-----------------------------------------------------------------------------
23// AlgorithmAdapter definition
24//-----------------------------------------------------------------------------
26using namespace boost::python;
27
32template <typename BaseAlgorithm>
34 : BaseAlgorithm(), m_self(self), m_isRunningObj(nullptr), m_wikiSummary("") {
35 // Only cache the isRunning attribute if it is overridden by the
36 // inheriting type otherwise we end up with an infinite recursive call
37 // as isRunning always exists from the interface
38 if (typeHasAttribute(self, "isRunning"))
39 m_isRunningObj = PyObject_GetAttrString(self, "isRunning");
40}
41
45template <typename BaseAlgorithm> const std::string AlgorithmAdapter<BaseAlgorithm>::name() const {
46 return std::string(getSelf()->ob_type->tp_name);
48
53template <typename BaseAlgorithm> int AlgorithmAdapter<BaseAlgorithm>::version() const {
54 try {
55 return callMethod<int>(getSelf(), "version");
56 } catch (UndefinedAttributeError &) {
57 return 1;
58 }
59}
60
66template <typename BaseAlgorithm> bool AlgorithmAdapter<BaseAlgorithm>::checkGroups() {
67 try {
68 return callMethod<bool>(getSelf(), "checkGroups");
69 } catch (UndefinedAttributeError &) {
70 return BaseAlgorithm::checkGroups();
71 }
73
78template <typename BaseAlgorithm> const std::string AlgorithmAdapter<BaseAlgorithm>::category() const {
79 const static std::string defaultCategory = "PythonAlgorithms";
80 std::string category = defaultCategory;
81 try {
82 category = callMethod<std::string>(getSelf(), "category");
83 } catch (UndefinedAttributeError &) {
84 }
85 if (category == defaultCategory) {
86 // output a warning
87 this->getLogger().warning() << "Python Algorithm " << this->name() << " v" << this->version()
88 << " does not have a category defined. See "
89 "http://www.mantidproject.org/Basic_PythonAlgorithm_Structure\n";
90 }
91 return category;
92}
93
98template <typename BaseAlgorithm> const std::vector<std::string> AlgorithmAdapter<BaseAlgorithm>::seeAlso() const {
99 try {
100 // The GIL is required so that the the reference count of the
101 // list object can be decremented safely
103 return Converters::PySequenceToVector<std::string>(callMethod<list>(getSelf(), "seeAlso"))();
104 } catch (UndefinedAttributeError &) {
105 return {};
106 }
107}
108
112template <typename BaseAlgorithm> const std::string AlgorithmAdapter<BaseAlgorithm>::alias() const {
113 try {
114 return callMethod<std::string>(getSelf(), "alias");
116 return BaseAlgorithm::alias();
117 }
118}
119
124template <typename BaseAlgorithm> const std::string AlgorithmAdapter<BaseAlgorithm>::aliasDeprecated() const {
125 try {
126 return callMethod<std::string>(getSelf(), "aliasDeprecated");
127 } catch (UndefinedAttributeError &) {
128 return BaseAlgorithm::aliasDeprecated();
129 }
130}
131
136template <typename BaseAlgorithm> const std::string AlgorithmAdapter<BaseAlgorithm>::summary() const {
137 try {
138 return callMethod<std::string>(getSelf(), "summary");
139 } catch (UndefinedAttributeError &) {
140 return m_wikiSummary;
141 }
142}
143
147template <typename BaseAlgorithm> const std::string AlgorithmAdapter<BaseAlgorithm>::helpURL() const {
148 try {
149 return callMethod<std::string>(getSelf(), "helpURL");
150 } catch (UndefinedAttributeError &) {
151 return std::string();
152 }
153}
154
158template <typename BaseAlgorithm> bool AlgorithmAdapter<BaseAlgorithm>::isRunning() const {
159 if (!m_isRunningObj) {
160 return SuperClass::isRunning();
161 } else {
163
164 GNU_DIAG_OFF("parentheses-equality")
165 PyObject *result = PyObject_CallObject(m_isRunningObj, nullptr);
166 if (PyErr_Occurred())
167 throw PythonException();
168 if (PyBool_Check(result)) {
169 return static_cast<bool>(PyLong_AsLong(result));
170 } else
171 throw std::runtime_error("Algorithm.isRunning - Expected bool return type.");
172 }
173 GNU_DIAG_ON("parentheses-equality")
174}
175
176template <typename BaseAlgorithm> void AlgorithmAdapter<BaseAlgorithm>::cancel() {
177 try {
178 return callMethod<void>(getSelf(), "cancel");
179 } catch (UndefinedAttributeError &) {
180 SuperClass::cancel();
181 }
182}
183
187template <typename BaseAlgorithm> std::map<std::string, std::string> AlgorithmAdapter<BaseAlgorithm>::validateInputs() {
188 using boost::python::dict;
189 std::map<std::string, std::string> resultMap;
190
191 try {
193 dict resultDict = callMethod<dict>(getSelf(), "validateInputs");
194 // convert to a map<string,string>
195 boost::python::list keys = resultDict.keys();
196 size_t numItems = boost::python::len(keys);
197 for (size_t i = 0; i < numItems; ++i) {
198 boost::python::object key = keys[i];
199 boost::python::object value = resultDict[key];
200 if (value) {
201 try {
202 std::string keyAsString = boost::python::extract<std::string>(key);
203 std::string valueAsString = boost::python::extract<std::string>(value);
204 resultMap[std::move(keyAsString)] = std::move(valueAsString);
205 } catch (boost::python::error_already_set &) {
206 this->getLogger().error() << "In validateInputs(self): Invalid type for key/value pair "
207 << "detected in dict.\n"
208 << "All keys and values must be strings\n";
209 }
210 }
211 }
212 } catch (UndefinedAttributeError &) {
213 return resultMap;
214 }
215
216 return resultMap;
217}
218
221template <typename BaseAlgorithm> void AlgorithmAdapter<BaseAlgorithm>::setWikiSummary(const std::string &summary) {
222 std::string msg = "self.setWikiSummary() is deprecated and will be removed in a future "
223 "release.\n"
224 "To ensure continued functionality remove the line containing "
225 "'self.setWikiSummary'\n"
226 "and add a new function outside of the current one defined like so:\n"
227 "def summary(self):\n"
228 " \"" +
229 summary + "\"\n";
230
231 PyErr_Warn(PyExc_DeprecationWarning, msg.c_str());
232 m_wikiSummary = summary;
233}
234
241template <typename BaseAlgorithm>
243 const std::string &doc) {
244 BaseAlgorithm &caller = extract<BaseAlgorithm &>(self);
245 // We need to clone the property so that python doesn't own the object that
246 // gets inserted
247 // into the manager
248 caller.declareProperty(std::unique_ptr<Kernel::Property>(prop->clone()), doc);
249}
250
263template <typename BaseAlgorithm>
264void AlgorithmAdapter<BaseAlgorithm>::declarePyAlgProperty(boost::python::object &self, const std::string &name,
265 const boost::python::object &defaultValue,
266 const boost::python::object &validator,
267 const std::string &doc, const int direction) {
268 BaseAlgorithm &caller = extract<BaseAlgorithm &>(self);
269 auto prop = std::unique_ptr<Kernel::Property>(
270 Registry::PropertyWithValueFactory::create(name, defaultValue, validator, direction));
271 caller.declareProperty(std::move(prop), doc);
272}
273
284template <typename BaseAlgorithm>
285void AlgorithmAdapter<BaseAlgorithm>::declarePyAlgProperty(boost::python::object &self, const std::string &name,
286 const boost::python::object &defaultValue,
287 const std::string &doc, const int direction) {
288 BaseAlgorithm &caller = extract<BaseAlgorithm &>(self);
289 auto prop =
290 std::unique_ptr<Kernel::Property>(Registry::PropertyWithValueFactory::create(name, defaultValue, direction));
291 caller.declareProperty(std::move(prop), doc);
292}
293
302template <typename BaseAlgorithm>
303void AlgorithmAdapter<BaseAlgorithm>::declarePyAlgProperty(boost::python::object &self, const std::string &name,
304 const boost::python::object &defaultValue,
305 const int direction) {
306 declarePyAlgProperty(self, name, defaultValue, "", direction);
307}
308
309//---------------------------------------------------------------------------------------------
310// Private members
311//---------------------------------------------------------------------------------------------
312
317template <typename BaseAlgorithm> void AlgorithmAdapter<BaseAlgorithm>::init() {
318 callMethod<void>(getSelf(), "PyInit");
319}
320
325template <typename BaseAlgorithm> void AlgorithmAdapter<BaseAlgorithm>::exec() {
326 try {
327 callMethod<void>(getSelf(), "PyExec");
329 if (BaseAlgorithm::getCancel())
331 else
332 throw;
333 }
334}
335
336//-----------------------------------------------------------------------------------------------------------------------------
337// Concete instantiations (avoids definitions being all in the headers)
338//-----------------------------------------------------------------------------------------------------------------------------
349} // namespace Mantid::PythonInterface
double value
The value of the point.
Definition: FitMW.cpp:51
std::unique_ptr< ConceptT > m_self
#define GNU_DIAG_ON(x)
#define GNU_DIAG_OFF(x)
This is a collection of macros for turning compiler warnings off in a controlled manner.
CancelException is thrown to cancel execution of the algorithm.
Definition: Algorithm.h:145
Base class for properties.
Definition: Property.h:94
virtual Property * clone() const =0
'Virtual copy constructor'
Provides a layer class for boost::python to allow C++ virtual functions to be overridden in a Python ...
const std::string helpURL() const override
Optional documentation URL of the algorithm, empty string if not overridden.
void setWikiSummary(const std::string &summary)
Set the summary text.
void cancel() override
Allow the cancel method to be overridden.
std::map< std::string, std::string > validateInputs() override
Returns the validateInputs result of the algorithm.
AlgorithmAdapter()=delete
Disable default constructor - The PyObject must be supplied to construct the object.
const std::string alias() const override
Allow the method returning the algorithm aliases to be overridden.
const std::string name() const override
Returns the name of the algorithm.
PyObject * m_isRunningObj
A pointer to an overridden isRunning method.
bool checkGroups() override
A return of false will allow processing workspace groups as a whole.
const std::string aliasDeprecated() const override
Returns optional documentation URL of the algorithm.
const std::string summary() const override
Returns the summary for the algorithm.
void exec() override
Private exec for this algorithm.
int version() const override
Returns a version of the algorithm.
const std::vector< std::string > seeAlso() const override
Returns seeAlso related algorithms.
static void declarePyAlgProperty(boost::python::object &self, Kernel::Property *prop, const std::string &doc="")
Declare a preconstructed property.
const std::string category() const override
Returns a category of the algorithm.
void init() override
Private init for this algorithm.
bool isRunning() const override
Allow the isRunning method to be overridden.
Defines a structure for acquiring/releasing the Python GIL using the RAII pattern.
Exception type that captures the current Python error state as a generic C++ exception for any genera...
Definition: ErrorHandling.h:24
static std::unique_ptr< Kernel::Property > create(const std::string &name, const boost::python::object &defaultValue, const boost::python::object &validator, const unsigned int direction)
Creates a PropertyWithValue<Type> instance from the given information.
bool MANTID_PYTHONINTERFACE_CORE_DLL typeHasAttribute(PyObject *obj, const char *attr)
This namespace contains helper functions for classes that are overridden in Python.
Converts a Python sequence type to a C++ std::vector, where the element type is defined by the templa...
Defines an exception for an undefined attribute.
Definition: CallMethod.h:20