Mantid
Loading...
Searching...
No Matches
DataServiceExporter.h
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2014 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
8
13
14#include <boost/python/class.hpp>
15#include <boost/python/extract.hpp>
16#include <boost/python/list.hpp>
17#include <boost/python/str.hpp>
18
19#include <memory>
20#include <set>
21
22namespace Mantid {
23namespace PythonInterface {
29template <typename SvcType, typename SvcPtrType> struct DataServiceExporter {
30 // typedef the type created by boost.python
31 using PythonType = boost::python::class_<SvcType, boost::noncopyable>;
32 using WeakPtr = std::weak_ptr<typename SvcPtrType::element_type>;
33
49 static PythonType define(const char *pythonClassName) {
50 using namespace boost::python;
51 using namespace Mantid::Kernel;
52
53 auto classType =
54 PythonType(pythonClassName, no_init)
55 .def("add", &DataServiceExporter::addItem, (arg("self"), arg("name"), arg("item")),
56 "Adds the given object to the service with the given name. If "
57 "the name/object exists it will raise an error.")
58 .def("addOrReplace", &DataServiceExporter::addOrReplaceItem, (arg("self"), arg("name"), arg("item")),
59 "Adds the given object to the service with the given name. "
60 "If the name exists the object is replaced.")
61 .def("doesExist", &SvcType::doesExist, (arg("self"), arg("name")),
62 "Returns True if the object is found in the service.")
63 .def("retrieve", &DataServiceExporter::retrieveOrKeyError, (arg("self"), arg("name")),
64 "Retrieve the named object. Raises an exception if the name "
65 "does not exist")
66 .def("remove", &DataServiceExporter::removeItem, (arg("self"), arg("name")), "Remove a named object")
67 .def("clear", &DataServiceExporter::clearItems, (arg("self"), arg("silent") = false),
68 "Removes all objects managed by the service.")
69 .def("size", &SvcType::size, arg("self"), "Returns the number of objects within the service")
70 .def("getObjectNames", &DataServiceExporter::getObjectNamesAsList, (arg("self"), arg("contain") = ""),
71 "Return the list of names currently known to the ADS")
72
73 // Make it act like a dictionary
74 .def("__len__", &SvcType::size, arg("self"))
75 .def("__getitem__", &DataServiceExporter::retrieveOrKeyError, (arg("self"), arg("name")))
76 .def("__setitem__", &DataServiceExporter::addOrReplaceItem, (arg("self"), arg("name"), arg("item")))
77 .def("__contains__", &SvcType::doesExist, (arg("self"), arg("name")))
78 .def("__delitem__", &DataServiceExporter::removeItem, (arg("self"), arg("name")));
79
80 return classType;
81 }
82
89 static void addItem(SvcType &self, const std::string &name, const boost::python::object &item) {
91 self.add(name, extractCppValue(item));
92 }
93
101 static void addOrReplaceItem(SvcType &self, const std::string &name, const boost::python::object &item) {
103 self.addOrReplace(name, extractCppValue(item));
104 }
105
111 static void removeItem(SvcType &self, const std::string &name) {
113 self.remove(name);
114 }
115
121 static void clearItems(SvcType &self, const bool silent) {
122 if (self.size() > 0 && !silent) {
123 PyErr_Warn(PyExc_Warning, "Running ADS.clear() also removes all hidden workspaces.\n"
124 "Mantid interfaces might still need some of these, for instance, MSlice.");
125 }
126
128 self.clear();
129 }
130
136 static SvcPtrType extractCppValue(const boost::python::object &pyvalue) {
137 // Test for a weak pointer first
138 boost::python::extract<WeakPtr &> extractWeak(pyvalue);
139 if (extractWeak.check()) {
140 return extractWeak().lock();
141 }
142 boost::python::extract<SvcPtrType &> extractRefShared(pyvalue);
143 if (extractRefShared.check()) {
144 return extractRefShared();
145 } else {
146 throw std::invalid_argument("Cannot extract pointer from Python object argument. Incorrect type");
147 }
148 }
149
160 static WeakPtr retrieveOrKeyError(const SvcType *const self, const std::string &name) {
161 using namespace Mantid::Kernel;
162
163 SvcPtrType item;
164 try {
165 item = self->retrieve(name);
166 } catch (Exception::NotFoundError &) {
167 // Translate into a Python KeyError
168 std::string err = "'" + name + "' does not exist.";
169 PyErr_SetString(PyExc_KeyError, err.c_str());
170 throw boost::python::error_already_set();
171 }
172 return WeakPtr(item);
173 }
174
183 static boost::python::list getObjectNamesAsList(SvcType const *const self, const std::string &contain) {
184 boost::python::list names;
185 const auto keys = self->getObjectNames(Mantid::Kernel::DataServiceSort::Unsorted,
187 for (auto itr = keys.begin(); itr != keys.end(); ++itr) {
188 names.append(*itr);
189 }
190 assert(names.attr("__len__")() == keys.size());
191 return names;
192 }
193};
194} // namespace PythonInterface
195} // namespace Mantid
std::string name
Definition Run.cpp:60
Exception for when an item is not found in a collection.
Definition Exception.h:145
Defines a structure for releasing the Python GIL using the RAII pattern.
Helper class which provides the Collimation Length for SANS instruments.
A helper struct to export templated DataService<> types to Python.
boost::python::class_< SvcType, boost::noncopyable > PythonType
static void addOrReplaceItem(SvcType &self, const std::string &name, const boost::python::object &item)
Add or replace an item into the service, if it exists then an error is raised.
static PythonType define(const char *pythonClassName)
Define the necessary boost.python framework to expor the templated DataService type Note: This does n...
static WeakPtr retrieveOrKeyError(const SvcType *const self, const std::string &name)
Retrieves a shared_ptr from the ADS and raises a Python KeyError if it does not exist.
static void removeItem(SvcType &self, const std::string &name)
Remove an item from the service.
static boost::python::list getObjectNamesAsList(SvcType const *const self, const std::string &contain)
Return a Python list of object names from the ADS as this is far easier to work with than a set.
std::weak_ptr< typename SvcPtrType::element_type > WeakPtr
static void clearItems(SvcType &self, const bool silent)
Remove an item from the service.
static SvcPtrType extractCppValue(const boost::python::object &pyvalue)
Extract a SvcPtrType C++ value from the Python object.
static void addItem(SvcType &self, const std::string &name, const boost::python::object &item)
Add an item into the service, if it exists then an error is raised.