Skip to content

Commit

Permalink
Amalgamate code for the DataService exports.
Browse files Browse the repository at this point in the history
Refs #10649
  • Loading branch information
martyngigg committed Jun 17, 2015
1 parent 6801884 commit 9beab64
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 70 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@

#include <boost/python/class.hpp>
#include <boost/python/list.hpp>
#include <boost/python/extract.hpp>

#include <set>

Expand All @@ -38,8 +39,7 @@ namespace PythonInterface {
* @tparam SvcType Type of DataService to export
* @tparam SvcHeldType The type held within the DataService map
*/
template <typename SvcType, typename SvcPtrType>
struct DataServiceExporter {
template <typename SvcType, typename SvcPtrType> struct DataServiceExporter {
// typedef the type created by boost.python
typedef boost::python::class_<SvcType, boost::noncopyable> PythonType;
typedef boost::weak_ptr<typename SvcPtrType::element_type> WeakPtr;
Expand All @@ -65,10 +65,10 @@ struct DataServiceExporter {

auto classType =
PythonType(pythonClassName, no_init)
.def("add", &SvcType::add,
.def("add", &DataServiceExporter::addItem,
"Adds the given object to the service with the given name. If "
"the name/object exists it will raise an error.")
.def("addOrReplace", &SvcType::addOrReplace,
.def("addOrReplace", &DataServiceExporter::addOrReplaceItem,
"Adds the given object to the service with the given name. "
"The the name exists the object is replaced.")
.def("doesExist", &SvcType::doesExist,
Expand All @@ -87,13 +87,56 @@ struct DataServiceExporter {
// Make it act like a dictionary
.def("__len__", &SvcType::size)
.def("__getitem__", &DataServiceExporter::retrieveOrKeyError)
.def("__setitem__", &SvcType::addOrReplace)
.def("__setitem__", &DataServiceExporter::addOrReplaceItem)
.def("__contains__", &SvcType::doesExist)
.def("__delitem__", &SvcType::remove);

return classType;
}

/**
* Add an item into the service, if it exists then an error is raised
* @param self A reference to the calling object
* @param name The name to assign to this in the service
* @param item A boost.python wrapped SvcHeldType object
*/
static void addItem(SvcType &self, const std::string &name,
const boost::python::object &item) {
self.add(name, extractCppValue(item));
}

/**
* Add or replace an item into the service, if it exists then an error is
* raised
* @param self A reference to the calling object
* @param name The name to assign to this in the service
* @param item A boost.python wrapped SvcHeldType object
*/
static void addOrReplaceItem(SvcType &self, const std::string &name,
const boost::python::object &item) {
self.addOrReplace(name, extractCppValue(item));
}

/**
* Extract a SvcPtrType C++ value from the Python object
* @param pyvalue Value of the
* @return The extracted value or thows an std::invalid_argument error
*/
static SvcPtrType extractCppValue(const boost::python::object &pyvalue) {
// Test for a weak pointer first
boost::python::extract<WeakPtr &> extractWeak(pyvalue);
if (extractWeak.check()) {
return extractWeak().lock();
}
boost::python::extract<SvcPtrType &> extractShared(pyvalue);
if (extractShared.check()) {
return extractShared();
} else {
throw std::invalid_argument(
"Cannot extract pointer from Python object argument. Incorrect type");
}
}

/**
* Retrieves a shared_ptr from the ADS and raises a Python KeyError if it does
* not exist
Expand All @@ -104,8 +147,7 @@ struct DataServiceExporter {
* @return A shared_ptr to the named object. If the name does not exist it
* sets a KeyError error indicator.
*/
static WeakPtr retrieveOrKeyError(SvcType &self,
const std::string &name) {
static WeakPtr retrieveOrKeyError(SvcType &self, const std::string &name) {
using namespace Mantid::Kernel;
SvcPtrType item;
try {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,69 +1,19 @@
#include "MantidPythonInterface/api/ExtractWorkspace.h"
#include "MantidPythonInterface/kernel/DataServiceExporter.h"
#include "MantidPythonInterface/kernel/TrackingInstanceMethod.h"

#include "MantidAPI/AnalysisDataService.h"
#include "MantidAPI/Workspace_fwd.h"

using namespace Mantid::API;
using namespace Mantid::Kernel;
using namespace Mantid::PythonInterface;
using namespace boost::python;


namespace {

/**
* Add an item into the ADS, if it exists then an error is raised
* @param self A reference to the calling object
* @param name The name to assign to this in the service
* @param item A boost.python wrapped SvcHeldType object
*/
void addItem(AnalysisDataServiceImpl &self, const std::string &name,
const boost::python::object &item) {
ExtractWorkspace extractWS(item);
if(extractWS.check()) {
self.add(name, extractWS());
} else {
throw std::runtime_error("Unable to add unknown object type to ADS");
}
}

/**
* Add or replace an item into the service, if it exists then an error is raised
* @param self A reference to the calling object
* @param name The name to assign to this in the service
* @param item A boost.python wrapped SvcHeldType object
*/
void addOrReplaceItem(AnalysisDataServiceImpl &self, const std::string &name,
const boost::python::object &item) {
ExtractWorkspace extractWS(item);
if(extractWS.check()) {
self.addOrReplace(name, extractWS());
} else {
throw std::runtime_error("Unable to add/replace unknown object type to ADS");
}
}

}


void export_AnalysisDataService() {
typedef DataServiceExporter<AnalysisDataServiceImpl, Workspace_sptr>
ADSExporter;
auto pythonClass = ADSExporter::define("AnalysisDataServiceImpl");

// -- special ADS behaviour --
// replace the add/addOrReplace,__setitem__ methods as we need to extract the
// exact stored type
pythonClass.def("add", &addItem, "Adds the given object to the service with "
"the given name. If the name/object exists "
"it will raise an error.");
pythonClass.def("addOrReplace", &addOrReplaceItem,
"Adds the given object to the service with the given name. "
"The the name exists the object is replaced.");
pythonClass.def("__setitem__", &addOrReplaceItem);

// Instance method
TrackingInstanceMethod<AnalysisDataService, ADSExporter::PythonType>::define(
pythonClass);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,25 @@

#include "MantidKernel/IPropertyManager.h"
#include "MantidKernel/PropertyManager.h"
#include "MantidPythonInterface/kernel/Registry/TypeRegistry.h"
#include "MantidPythonInterface/kernel/Registry/PropertyValueHandler.h"
#include "MantidPythonInterface/kernel/Registry/PropertyWithValueFactory.h"

#include <boost/python/class.hpp>
#include <boost/python/dict.hpp>
#include <boost/python/list.hpp>
#include <boost/python/register_ptr_to_python.hpp>
#include <boost/python/copy_const_reference.hpp>

using Mantid::Kernel::IPropertyManager;
using Mantid::Kernel::Property;
using Mantid::Kernel::PropertyManager;
namespace Registry = Mantid::PythonInterface::Registry;

using namespace boost::python;

namespace {}

void export_PropertyManager() {
register_ptr_to_python<boost::shared_ptr<PropertyManager>>();
class_<PropertyManager, bases<IPropertyManager>, boost::noncopyable>(
"PropertyManager");
typedef boost::shared_ptr<PropertyManager> PropertyManager_sptr;

// The second argument defines the actual type held within the Python object.
// This means that when a PropertyManager is constructed in Python it actually used
// a shared_ptr to the object rather than a raw pointer. This knowledge is used by
// DataServiceExporter::extractCppValue to assume that it can always extract a shared_ptr
// type
class_<PropertyManager, PropertyManager_sptr, bases<IPropertyManager>,
boost::noncopyable>("PropertyManager");
}

#ifdef _MSC_VER
Expand Down

0 comments on commit 9beab64

Please sign in to comment.