Skip to content

Commit

Permalink
Checkpoint removing downcasting policies
Browse files Browse the repository at this point in the history
The tests still don't work yet.
Refs #9807
  • Loading branch information
martyngigg committed May 25, 2015
1 parent e6d750d commit 2167ec8
Show file tree
Hide file tree
Showing 13 changed files with 172 additions and 146 deletions.
Expand Up @@ -23,8 +23,8 @@
File change history is stored at: <https://github.com/mantidproject/mantid>
Code Documentation is available at: <http://doxygen.mantidproject.org>
*/
#include "MantidPythonInterface/kernel/Policies/DowncastingPolicies.h"
#include "MantidKernel/Exception.h"
#include "MantidPythonInterface/kernel/WeakPtr.h"

#include <boost/python/class.hpp>
#include <boost/python/list.hpp>
Expand All @@ -38,9 +38,11 @@ namespace PythonInterface {
* @tparam SvcType Type of DataService to export
* @tparam SvcHeldType The type held within the DataService map
*/
template <typename SvcType, typename SvcHeldType> struct DataServiceExporter {
/// typedef the type created by boost.python
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;

/**
* Define the necessary boost.python framework to expor the templated
Expand All @@ -60,7 +62,6 @@ template <typename SvcType, typename SvcHeldType> struct DataServiceExporter {
static PythonType define(const char *pythonClassName) {
using namespace boost::python;
using namespace Mantid::Kernel;
namespace Policies = Mantid::PythonInterface::Policies;

auto classType =
PythonType(pythonClassName, no_init)
Expand All @@ -73,7 +74,6 @@ template <typename SvcType, typename SvcHeldType> struct DataServiceExporter {
.def("doesExist", &SvcType::doesExist,
"Returns True if the object is found in the service.")
.def("retrieve", &DataServiceExporter::retrieveOrKeyError,
return_value_policy<Policies::ToWeakPtrWithDowncast>(),
"Retrieve the named object. Raises an exception if the name "
"does not exist")
.def("remove", &SvcType::remove, "Remove a named object")
Expand All @@ -86,8 +86,7 @@ template <typename SvcType, typename SvcHeldType> struct DataServiceExporter {

// Make it act like a dictionary
.def("__len__", &SvcType::size)
.def("__getitem__", &DataServiceExporter::retrieveOrKeyError,
return_value_policy<Policies::ToWeakPtrWithDowncast>())
.def("__getitem__", &DataServiceExporter::retrieveOrKeyError)
.def("__setitem__", &SvcType::addOrReplace)
.def("__contains__", &SvcType::doesExist)
.def("__delitem__", &SvcType::remove);
Expand All @@ -105,10 +104,10 @@ template <typename SvcType, typename SvcHeldType> struct DataServiceExporter {
* @return A shared_ptr to the named object. If the name does not exist it
* sets a KeyError error indicator.
*/
static SvcHeldType retrieveOrKeyError(SvcType &self,
const std::string &name) {
static WeakPtr retrieveOrKeyError(SvcType &self,
const std::string &name) {
using namespace Mantid::Kernel;
SvcHeldType item;
SvcPtrType item;
try {
item = self.retrieve(name);
} catch (Exception::NotFoundError &) {
Expand All @@ -117,7 +116,7 @@ template <typename SvcType, typename SvcHeldType> struct DataServiceExporter {
PyErr_SetString(PyExc_KeyError, err.c_str());
throw boost::python::error_already_set();
}
return item;
return WeakPtr(item);
}

/**
Expand Down
@@ -1,7 +1,7 @@
#ifndef MANITD_PYTHONINTERFACE_TOWEAKPTRWITHDOWNCASTIMPL_H_
#define MANITD_PYTHONINTERFACE_TOWEAKPTRWITHDOWNCASTIMPL_H_
/**
Copyright &copy; 2012 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge
Copyright &copy; 2012 ISIS Rutherford Appleton Laboratory, NScD Oak Ridg
National Laboratory & European Spallation Source
This file is part of Mantid.
Expand Down
Expand Up @@ -24,7 +24,6 @@
*/
#include "MantidPythonInterface/kernel/Registry/TypedPropertyValueHandler.h"
#include "MantidPythonInterface/kernel/Registry/TypeRegistry.h"
#include "MantidPythonInterface/kernel/Registry/DowncastRegistry.h"
#include <boost/python/register_ptr_to_python.hpp>

namespace Mantid {
Expand All @@ -37,9 +36,6 @@ namespace Registry {
* - Calls register_ptr_to_python<boost::shared_ptr<T>>
* - Calls register_ptr_to_python<boost::weak_ptr<T>>
* - Registers a new PropertyValueHandler for a boost::shared_ptr<T>
*
* ID strings can then be mapped to the template type by calling the
* insert method.
*/
template <typename IType> struct DLLExport DataItemInterface {
typedef boost::shared_ptr<IType> IType_sptr;
Expand All @@ -57,7 +53,6 @@ template <typename IType> struct DLLExport DataItemInterface {
/// Register a downcast for this ID
DataItemInterface &castFromID(const std::string &id) {
using namespace Registry;
DowncastRegistry::subscribe<IType>(id);
return *this;
}
};
Expand Down
Expand Up @@ -29,6 +29,7 @@
namespace Mantid {
namespace Kernel {
// Forward declarations
class DataItem;
class IPropertyManager;
class Property;
}
Expand All @@ -43,7 +44,7 @@ namespace Registry {
*/
struct DLLExport PropertyValueHandler {
/// Virtual Destructor
virtual ~PropertyValueHandler(){};
virtual ~PropertyValueHandler() {};
/// Overload to set the named property's value on the property manager
virtual void set(Kernel::IPropertyManager *alg, const std::string &name,
const boost::python::object &value) const = 0;
Expand Down
Expand Up @@ -26,6 +26,7 @@
#include "MantidPythonInterface/kernel/Registry/DowncastRegistry.h"

#include "MantidPythonInterface/kernel/IsNone.h" // includes object.hpp
#include "MantidAPI/Workspace.h"
#include "MantidKernel/PropertyWithValue.h"
#include "MantidKernel/IPropertyManager.h"

Expand Down Expand Up @@ -109,12 +110,20 @@ struct DLLExport TypedPropertyValueHandler<boost::shared_ptr<T>>
void set(Kernel::IPropertyManager *alg, const std::string &name,
const boost::python::object &value) const {
using namespace boost::python;
using Registry::DowncastRegistry;
using Mantid::API::Workspace_sptr;
typedef boost::weak_ptr<Mantid::API::Workspace> Workspace_wptr;

const auto &entry =
DowncastRegistry::retrieve(call_method<std::string>(value.ptr(), "id"));
alg->setProperty<HeldType>(name, boost::dynamic_pointer_cast<T>(
entry.fromPythonAsSharedPtr(value)));
Workspace_sptr p;
extract<Workspace_wptr> weakExtract(value);
extract<Workspace_sptr> sharedExtract(value);
if(weakExtract.check()) {
p = weakExtract().lock();
} else if(sharedExtract.check()) {
p = sharedExtract();
} else {
throw std::runtime_error("Unable to add unknown object type to ADS");
}
alg->setProperty<HeldType>(name, boost::dynamic_pointer_cast<T>(p));
}

/**
Expand Down Expand Up @@ -147,6 +156,7 @@ struct DLLExport TypedPropertyValueHandler<boost::shared_ptr<T>>
}
return valueProp;
}

};
}
}
Expand Down
@@ -1,70 +1,68 @@
#include "MantidPythonInterface/kernel/DataServiceExporter.h"
#include "MantidPythonInterface/kernel/Registry/DowncastRegistry.h"
#include "MantidPythonInterface/kernel/TrackingInstanceMethod.h"

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

#include <boost/python/call_method.hpp>
#include <boost/weak_ptr.hpp>

using namespace Mantid::API;
using namespace Mantid::Kernel;
using Mantid::PythonInterface::DataServiceExporter;
using Mantid::PythonInterface::TrackingInstanceMethod;
using namespace Mantid::PythonInterface::Registry;
using namespace boost::python;

namespace {

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)
{
const auto & entry = DowncastRegistry::retrieve(call_method<std::string>(item.ptr(), "id"));
typedef boost::weak_ptr<Workspace> Workspace_wptr;

/**
* 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) {
extract<Workspace_wptr> weakExtract(item);
if(weakExtract.check()) {
self.add(name, weakExtract().lock());
return;
}

try
{
// It is VERY important that the extract type be a reference to SvcHeldType so that
// boost.python doesn't create a new shared_ptr and instead simply extracts the embedded one.
self.add(name, boost::dynamic_pointer_cast<Workspace>(entry.fromPythonAsSharedPtr(item)));
}
catch(std::exception& exc)
{
PyErr_SetString(PyExc_RuntimeError, exc.what()); // traditionally throws RuntimeError so don't break scripts
throw boost::python::error_already_set();
}
extract<Workspace_sptr> sharedExtract(item);
if(sharedExtract.check()) {
self.add(name, sharedExtract());
} 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)
{
const auto & entry = DowncastRegistry::retrieve(call_method<std::string>(item.ptr(), "id"));
}

try
{
// It is VERY important that the extract type be a reference to SvcHeldType so that
// boost.python doesn't create a new shared_ptr and instead simply extracts the embedded one.
self.addOrReplace(name, boost::dynamic_pointer_cast<Workspace>(entry.fromPythonAsSharedPtr(item)));
}
catch(std::exception& exc)
{
PyErr_SetString(PyExc_RuntimeError, exc.what()); // traditionally throws RuntimeError so don't break scripts
throw boost::python::error_already_set();
}
/**
* 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) {
extract<Workspace_wptr> weakExtract(item);
if(weakExtract.check()) {
self.add(name, weakExtract().lock());
return;
}

extract<Workspace_sptr> sharedExtract(item);
if(sharedExtract.check()) {
self.add(name, sharedExtract());
} else {
throw std::runtime_error("Unable to add unknown object type to ADS");
}
}

}
// clang-format off
void export_AnalysisDataService()
// clang-format on
Expand All @@ -73,14 +71,16 @@ void export_AnalysisDataService()
auto pythonClass = ADSExporter::define("AnalysisDataServiceImpl");

// -- special ADS behaviour --
// replace the add/addOrReplace,__setitem__ methods as we need to exact 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.");
// 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.");
"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);
}

0 comments on commit 2167ec8

Please sign in to comment.