Mantid
Loading...
Searching...
No Matches
AlgorithmFactory.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 +
14
15#include <boost/python/class.hpp>
16#include <boost/python/def.hpp>
17#include <boost/python/dict.hpp>
18#include <boost/python/list.hpp>
19#include <boost/python/overloads.hpp>
20#include <mutex>
21
22// Python frameobject. This is under the boost includes so that boost will have
23// done the
24// include of Python.h which it ensures is done correctly
25#include <frameobject.h>
26
27using namespace Mantid::API;
28using namespace boost::python;
31
33
34namespace {
36
37//------------------------------------------------------------------------------------------------------
47dict getRegisteredAlgorithms(AlgorithmFactoryImpl const *const self, bool includeHidden) {
48 const auto keys = self->getKeys(includeHidden);
49 dict inventory;
50 for (const auto &key : keys) {
51 auto algInfo = self->decodeName(key);
52 object name(handle<>(to_python_value<const std::string &>()(algInfo.first)));
53 object ver(handle<>(to_python_value<const int &>()(algInfo.second)));
54 // There seems to be no way to "promote" the return of .get to a list
55 // without copying it
56 object versions;
57 if (inventory.has_key(name)) {
58 versions = inventory.get(name);
59 } else {
60 versions = list();
61 inventory[name] = versions;
62 }
63 versions.attr("append")(ver);
64 }
65 return inventory;
66}
67
73list getDescriptors(AlgorithmFactoryImpl const *const self, bool includeHidden = false, bool includeAlias = false) {
74 const auto descriptors = self->getDescriptors(includeHidden, includeAlias);
75 list pyDescriptors;
76 for (const auto &descr : descriptors) {
77 pyDescriptors.append(boost::python::object(descr));
78 }
79 return pyDescriptors;
80}
81
91dict getCategoriesandState(AlgorithmFactoryImpl const *const self) {
92 const auto categories = self->getCategoriesWithState();
93 dict pythonCategories;
94 for (auto &it : categories) {
95 object categoryName(handle<>(to_python_value<const std::string &>()(it.first)));
96 pythonCategories[categoryName] = it.second;
97 }
98
99 return pythonCategories;
100}
101
102//------------------------------------------------------------------------------
103// Python algorithm subscription
104//------------------------------------------------------------------------------
105
106// Python algorithm registration mutex in anonymous namespace (aka static)
107std::recursive_mutex PYALG_REGISTER_MUTEX;
108
109GNU_DIAG_OFF("cast-qual")
110
111
117void subscribe(AlgorithmFactoryImpl &self, const boost::python::object &obj) {
118 UninstallTrace uninstallTrace;
119 std::lock_guard<std::recursive_mutex> lock(PYALG_REGISTER_MUTEX);
120
121 static auto *const pyAlgClass = (PyObject *)converter::registered<Algorithm>::converters.to_python_target_type();
122 // obj could be or instance/class, check instance first
123 PyObject *classObject(nullptr);
124 if (PyObject_IsInstance(obj.ptr(), pyAlgClass)) {
125 classObject = PyObject_GetAttrString(obj.ptr(), "__class__");
126 } else if (PyObject_IsSubclass(obj.ptr(), pyAlgClass)) {
127 classObject = obj.ptr(); // We need to ensure the type of lifetime
128 // management so grab the raw pointer
129 } else {
130 throw std::invalid_argument("Cannot register an algorithm that does not derive from Algorithm.");
131 }
132 boost::python::object classType(handle<>(borrowed(classObject)));
133 // Takes ownership of instantiator and replaces any existing algorithm
134 std::unique_ptr<Mantid::Kernel::AbstractInstantiator<Algorithm>> temp =
135 std::make_unique<PythonObjectInstantiator<Algorithm>>(classType);
136 auto descr = self.subscribe(std::move(temp), AlgorithmFactoryImpl::OverwriteCurrent);
137
138 // Python algorithms cannot yet act as loaders so remove any registered ones
139 // from the FileLoaderRegistry
140 FileLoaderRegistry::Instance().unsubscribe(descr.first, descr.second);
141}
142
143GNU_DIAG_OFF("unused-local-typedef")
144// Ignore -Wconversion warnings coming from boost::python
145// Seen with GCC 7.1.1 and Boost 1.63.0
146GNU_DIAG_OFF("conversion")
147
148BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(existsOverloader, exists, 1, 2)
149BOOST_PYTHON_FUNCTION_OVERLOADS(getDescriptors_overloads, getDescriptors, 1, 3)
150
151GNU_DIAG_ON("conversion")
152GNU_DIAG_ON("unused-local-typedef")
153
155} // namespace
156GNU_DIAG_ON("cast-qual")
157
159
160 class_<AlgorithmDescriptor>("AlgorithmDescriptor")
161 .def_readonly("name", &AlgorithmDescriptor::name)
162 .def_readonly("alias", &AlgorithmDescriptor::alias)
163 .def_readonly("category", &AlgorithmDescriptor::category)
164 .def_readonly("version", &AlgorithmDescriptor::version);
165
166 class_<AlgorithmFactoryImpl, boost::noncopyable>("AlgorithmFactoryImpl", no_init)
167 .def("exists", &AlgorithmFactoryImpl::exists,
168 existsOverloader((arg("name"), arg("version") = -1), "Returns true if the given algorithm exists with "
169 "an option to specify the version"))
170
171 .def("getRegisteredAlgorithms", &getRegisteredAlgorithms, (arg("self"), arg("include_hidden")),
172 "Returns a Python dictionary of currently registered algorithms")
173 .def("highestVersion", &AlgorithmFactoryImpl::highestVersion, (arg("self"), arg("algorithm_name")),
174 "Returns the highest version of the named algorithm. Throws "
175 "ValueError if no algorithm can be found")
176 .def("subscribe", &subscribe, (arg("self"), arg("object")),
177 "Register a Python class derived from "
178 "PythonAlgorithm into the factory")
179 .def("getDescriptors", &getDescriptors,
180 getDescriptors_overloads((arg("self"), arg("include_hidden") = false, arg("include_alias") = false),
181 "Return a list of descriptors of registered algorithms. Each "
182 "descriptor is a list: [name, version, category, alias]."))
183 .def("getCategoriesandState", &getCategoriesandState,
184 "Return the categories of the algorithms. This includes those within "
185 "the Factory itself and any cleanly constructed algorithms stored "
186 "here")
187 .def("unsubscribe", &AlgorithmFactoryImpl::unsubscribe, (arg("self"), arg("name"), arg("version")),
188 "Returns the highest version of the named algorithm. Throws "
189 "ValueError if no algorithm can be found")
190 .def("enableNotifications", &AlgorithmFactoryImpl::enableNotifications)
191 .def("disableNotifications", &AlgorithmFactoryImpl::disableNotifications)
192
193 .def("Instance", &AlgorithmFactory::Instance, return_value_policy<reference_existing_object>(),
194 "Returns a reference to the AlgorithmFactory singleton")
195 .staticmethod("Instance");
196}
#define GET_POINTER_SPECIALIZATION(TYPE)
Definition: GetPointer.h:17
void export_AlgorithmFactory()
BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(valueAsPrettyStrOverloader, valueAsPrettyStr, 0, 2) void export_Property()
Definition: Property.cpp:102
double obj
the value of the quadratic function
#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.
The AlgorithmFactory class is in charge of the creation of concrete instances of Algorithms.
bool exists(const std::string &algorithmName, const int version=-1)
Does an algorithm of the given name and version exist.
int highestVersion(const std::string &algorithmName) const
Returns the highest version of the algorithm currently registered.
std::vector< AlgorithmDescriptor > getDescriptors(bool includeHidden=false, bool includeAliases=false) const
Returns algorithm descriptors.
void unsubscribe(const std::string &algorithmName, const int version)
Unsubscribe the given algorithm.
std::pair< std::string, int > decodeName(const std::string &mangledName) const
unmangles the names used as keys into the name and version
const std::vector< std::string > getKeys() const override
Get the algorithm names and version - mangled use decodeName to separate.
const std::map< std::string, bool > getCategoriesWithState() const
Get the algorithm categories.
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
RAII handler to temporarily remove and reinstall a Python trace function.
Definition: NDArray.h:49
std::string name
Algorithm Name.