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 +
15
16#include <boost/python/class.hpp>
17#include <boost/python/dict.hpp>
18
19namespace {
20auto PYALG_STRUCTURE_DOCS = "https://docs.mantidproject.org/tutorials/extending_mantid_with_python/"
21 "python_algorithms/01_basic_algorithm_structure.html#basic-algorithm-structure";
22}
23
24//-----------------------------------------------------------------------------
25// AlgorithmAdapter definition
26//-----------------------------------------------------------------------------
28using namespace boost::python;
29
34template <typename BaseAlgorithm>
36 : BaseAlgorithm(), m_self(self), m_isRunningObj(nullptr), m_wikiSummary("") {
37 // Only cache the isRunning attribute if it is overridden by the
38 // inheriting type otherwise we end up with an infinite recursive call
39 // as isRunning always exists from the interface
40 if (typeHasAttribute(self, "isRunning"))
41 m_isRunningObj = PyObject_GetAttrString(self, "isRunning");
42}
43
47template <typename BaseAlgorithm> const std::string AlgorithmAdapter<BaseAlgorithm>::name() const {
48 return std::string(getSelf()->ob_type->tp_name);
50
55template <typename BaseAlgorithm> int AlgorithmAdapter<BaseAlgorithm>::version() const {
56 try {
57 return callMethod<int>(getSelf(), "version");
59 return 1;
60 }
61}
68template <typename BaseAlgorithm> bool AlgorithmAdapter<BaseAlgorithm>::checkGroups() {
69 try {
70 return callMethod<bool>(getSelf(), "checkGroups");
71 } catch (UndefinedAttributeError &) {
72 return BaseAlgorithm::checkGroups();
73 }
74}
75
80template <typename BaseAlgorithm> const std::string AlgorithmAdapter<BaseAlgorithm>::category() const {
81 const static std::string defaultCategory = "PythonAlgorithms";
82 std::string category = defaultCategory;
83 try {
84 category = callMethod<std::string>(getSelf(), "category");
85 } catch (UndefinedAttributeError &) {
86 }
87 if (category == defaultCategory) {
88 // output a warning
89 this->getLogger().warning() << "Python Algorithm " << this->name() << " v" << this->version()
90 << " does not have a category defined. See " << PYALG_STRUCTURE_DOCS << "\n";
91 }
92 return category;
93}
94
99template <typename BaseAlgorithm> const std::vector<std::string> AlgorithmAdapter<BaseAlgorithm>::seeAlso() const {
100 try {
101 // The GIL is required so that the reference count of the
102 // list object can be decremented safely
104 return Converters::PySequenceToVector<std::string>(callMethod<list>(getSelf(), "seeAlso"))();
105 } catch (UndefinedAttributeError &) {
106 return {};
108}
109
113template <typename BaseAlgorithm> const std::string AlgorithmAdapter<BaseAlgorithm>::alias() const {
114 try {
115 return callMethod<std::string>(getSelf(), "alias");
116 } catch (UndefinedAttributeError &) {
117 return BaseAlgorithm::alias();
118 }
119}
120
125template <typename BaseAlgorithm> const std::string AlgorithmAdapter<BaseAlgorithm>::aliasDeprecated() const {
126 try {
127 return callMethod<std::string>(getSelf(), "aliasDeprecated");
128 } catch (UndefinedAttributeError &) {
129 return BaseAlgorithm::aliasDeprecated();
130 }
131}
132
137template <typename BaseAlgorithm> const std::string AlgorithmAdapter<BaseAlgorithm>::summary() const {
138 try {
139 return callMethod<std::string>(getSelf(), "summary");
140 } catch (UndefinedAttributeError &) {
141 return m_wikiSummary;
142 }
143}
144
148template <typename BaseAlgorithm> const std::string AlgorithmAdapter<BaseAlgorithm>::helpURL() const {
149 try {
150 return callMethod<std::string>(getSelf(), "helpURL");
151 } catch (UndefinedAttributeError &) {
152 return std::string();
153 }
154}
155
159template <typename BaseAlgorithm> bool AlgorithmAdapter<BaseAlgorithm>::isRunning() const {
160 if (!m_isRunningObj) {
161 return SuperClass::isRunning();
162 } else {
164
165 GNU_DIAG_OFF("parentheses-equality")
166 PyObject *result = PyObject_CallObject(m_isRunningObj, nullptr);
167 if (PyErr_Occurred())
168 throw PythonException();
169 if (PyBool_Check(result)) {
170 return static_cast<bool>(PyLong_AsLong(result));
171 } else
172 throw std::runtime_error("Algorithm.isRunning - Expected bool return type.");
173 }
174 GNU_DIAG_ON("parentheses-equality")
175}
176
177template <typename BaseAlgorithm> void AlgorithmAdapter<BaseAlgorithm>::cancel() {
178 try {
179 return callMethod<void>(getSelf(), "cancel");
180 } catch (UndefinedAttributeError &) {
181 SuperClass::cancel();
182 }
183}
184
188template <typename BaseAlgorithm> std::map<std::string, std::string> AlgorithmAdapter<BaseAlgorithm>::validateInputs() {
189 using boost::python::dict;
190 std::map<std::string, std::string> resultMap;
191
192 try {
194 dict resultDict = callMethod<dict>(getSelf(), "validateInputs");
195 // convert to a map<string,string>
196 boost::python::list keys = resultDict.keys();
197 size_t numItems = boost::python::len(keys);
198 for (size_t i = 0; i < numItems; ++i) {
199 boost::python::object key = keys[i];
200 boost::python::object value = resultDict[key];
201 if (value) {
202 try {
203 std::string keyAsString = boost::python::extract<std::string>(key);
204 std::string valueAsString = boost::python::extract<std::string>(value);
205 resultMap[std::move(keyAsString)] = std::move(valueAsString);
206 } catch (boost::python::error_already_set &) {
207 this->getLogger().error() << "In validateInputs(self): Invalid type for key/value pair "
208 << "detected in dict.\n"
209 << "All keys and values must be strings\n";
210 }
211 }
212 }
213 } catch (UndefinedAttributeError &) {
214 return resultMap;
215 }
216
217 return resultMap;
218}
219
222template <typename BaseAlgorithm> void AlgorithmAdapter<BaseAlgorithm>::setWikiSummary(const std::string &summary) {
223 std::string msg = "self.setWikiSummary() is deprecated and will be removed in a future "
224 "release.\n"
225 "To ensure continued functionality remove the line containing "
226 "'self.setWikiSummary'\n"
227 "and add a new function outside of the current one defined like so:\n"
228 "def summary(self):\n"
229 " \"" +
230 summary + "\"\n";
231
232 PyErr_Warn(PyExc_DeprecationWarning, msg.c_str());
233 m_wikiSummary = summary;
234}
235
242template <typename BaseAlgorithm>
244 const std::string &doc) {
245 BaseAlgorithm &caller = extract<BaseAlgorithm &>(self);
246 // We need to clone the property so that python doesn't own the object that
247 // gets inserted
248 // into the manager
249 caller.declareProperty(std::unique_ptr<Kernel::Property>(prop->clone()), doc);
250}
251
264template <typename BaseAlgorithm>
265void AlgorithmAdapter<BaseAlgorithm>::declarePyAlgProperty(boost::python::object &self, const std::string &name,
266 const boost::python::object &defaultValue,
267 const boost::python::object &validator,
268 const std::string &doc, const int direction) {
269 BaseAlgorithm &caller = extract<BaseAlgorithm &>(self);
270 auto prop = std::unique_ptr<Kernel::Property>(
271 Registry::PropertyWithValueFactory::create(name, defaultValue, validator, direction));
272 caller.declareProperty(std::move(prop), doc);
273}
274
285template <typename BaseAlgorithm>
286void AlgorithmAdapter<BaseAlgorithm>::declarePyAlgProperty(boost::python::object &self, const std::string &name,
287 const boost::python::object &defaultValue,
288 const std::string &doc, const int direction) {
289 BaseAlgorithm &caller = extract<BaseAlgorithm &>(self);
290 auto prop =
291 std::unique_ptr<Kernel::Property>(Registry::PropertyWithValueFactory::create(name, defaultValue, direction));
292 caller.declareProperty(std::move(prop), doc);
293}
294
303template <typename BaseAlgorithm>
304void AlgorithmAdapter<BaseAlgorithm>::declarePyAlgProperty(boost::python::object &self, const std::string &name,
305 const boost::python::object &defaultValue,
306 const int direction) {
307 declarePyAlgProperty(self, name, defaultValue, "", direction);
308}
309
322template <typename BaseAlgorithm>
324 const std::string &name,
325 const boost::python::object &defaultValue,
326 const boost::python::object &validator,
327 const std::string &doc, const int direction) {
328 BaseAlgorithm &caller = extract<BaseAlgorithm &>(self);
329 auto prop = std::unique_ptr<Kernel::Property>(
330 Registry::PropertyWithValueFactory::create(name, defaultValue, validator, direction));
331 caller.declareOrReplaceProperty(std::move(prop), doc);
332}
333
334//---------------------------------------------------------------------------------------------
335// Private members
336//---------------------------------------------------------------------------------------------
337
342template <typename BaseAlgorithm> void AlgorithmAdapter<BaseAlgorithm>::init() {
343 callMethod<void>(getSelf(), "PyInit");
344}
345
350template <typename BaseAlgorithm> void AlgorithmAdapter<BaseAlgorithm>::exec() {
351 try {
352 callMethod<void>(getSelf(), "PyExec");
354 if (BaseAlgorithm::getCancel())
356 else
357 throw;
358 }
359}
360
361//-----------------------------------------------------------------------------------------------------------------------------
362// Concrete instantiations (allows explicit locating of tempate-body definitions)
363//-----------------------------------------------------------------------------------------------------------------------------
364
367
370} // namespace Mantid::PythonInterface
std::string name
Definition Run.cpp:60
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:136
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.
static void declareOrReplacePyAlgProperty(boost::python::object &self, const std::string &name, const boost::python::object &defaultValue, const boost::python::object &validator=boost::python::object(), const std::string &doc="", const int direction=Kernel::Direction::Input)
Declare or replace a property using the type of the defaultValue with a validator and doc string.
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...
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