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 "The 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"), "Removes all objects managed by the service.")
68 .def("size", &SvcType::size, arg("self"), "Returns the number of objects within the service")
69 .def("getObjectNames", &DataServiceExporter::getObjectNamesAsList, (arg("self"), arg("contain") = ""),
70 "Return the list of names currently known to the ADS")
71
72 // Make it act like a dictionary
73 .def("__len__", &SvcType::size, arg("self"))
74 .def("__getitem__", &DataServiceExporter::retrieveOrKeyError, (arg("self"), arg("name")))
75 .def("__setitem__", &DataServiceExporter::addOrReplaceItem, (arg("self"), arg("name"), arg("item")))
76 .def("__contains__", &SvcType::doesExist, (arg("self"), arg("name")))
77 .def("__delitem__", &DataServiceExporter::removeItem, (arg("self"), arg("name")));
78
79 return classType;
80 }
81
88 static void addItem(SvcType &self, const std::string &name, const boost::python::object &item) {
90 self.add(name, extractCppValue(item));
91 }
92
100 static void addOrReplaceItem(SvcType &self, const std::string &name, const boost::python::object &item) {
102 self.addOrReplace(name, extractCppValue(item));
103 }
104
110 static void removeItem(SvcType &self, const std::string &name) {
112 self.remove(name);
113 }
114
119 static void clearItems(SvcType &self) {
121 self.clear();
122 }
123
129 static SvcPtrType extractCppValue(const boost::python::object &pyvalue) {
130 // Test for a weak pointer first
131 boost::python::extract<WeakPtr &> extractWeak(pyvalue);
132 if (extractWeak.check()) {
133 return extractWeak().lock();
134 }
135 boost::python::extract<SvcPtrType &> extractRefShared(pyvalue);
136 if (extractRefShared.check()) {
137 return extractRefShared();
138 } else {
139 throw std::invalid_argument("Cannot extract pointer from Python object argument. Incorrect type");
140 }
141 }
142
153 static WeakPtr retrieveOrKeyError(SvcType &self, const std::string &name) {
154 using namespace Mantid::Kernel;
155
156 SvcPtrType item;
157 try {
158 item = self.retrieve(name);
159 } catch (Exception::NotFoundError &) {
160 // Translate into a Python KeyError
161 std::string err = "'" + name + "' does not exist.";
162 PyErr_SetString(PyExc_KeyError, err.c_str());
163 throw boost::python::error_already_set();
164 }
165 return WeakPtr(item);
166 }
167
176 static boost::python::list getObjectNamesAsList(SvcType const *const self, const std::string &contain) {
177 boost::python::list names;
178 const auto keys = self->getObjectNames(Mantid::Kernel::DataServiceSort::Unsorted,
180 for (auto itr = keys.begin(); itr != keys.end(); ++itr) {
181 names.append(*itr);
182 }
183 assert(names.attr("__len__")() == keys.size());
184 return names;
185 }
186};
187} // namespace PythonInterface
188} // namespace Mantid
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 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)
Remove an item from the service.
static WeakPtr retrieveOrKeyError(SvcType &self, const std::string &name)
Retrieves a shared_ptr from the ADS and raises a Python KeyError if it does not exist.
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.