Skip to content

Commit

Permalink
Add a simple ToWeakPtr return value policy
Browse files Browse the repository at this point in the history
Improve WorkspaceGroup test to cover the use case.
Refs #9807
  • Loading branch information
martyngigg committed Jun 1, 2015
1 parent 12df5ed commit 0a6b102
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 19 deletions.
@@ -0,0 +1,93 @@
#ifndef MANTID_PYTHONINTERFACE_TOWEAKPTR_H_
#define MANTID_PYTHONINTERFACE_TOWEAKPTR_H_
/**
Copyright © 2015 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge
National Laboratory & European Spallation Source
This file is part of Mantid.
Mantid is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
Mantid is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
File change history is stored at: <https://github.com/mantidproject/mantid>
Code Documentation is available at: <http://doxygen.mantidproject.org>
*/
#include <boost/python/detail/prefix.hpp>
#include <boost/python/to_python_value.hpp>

#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>

namespace Mantid {
namespace PythonInterface {
namespace Policies {

namespace {
//-----------------------------------------------------------------------
// MPL helper structs
//-----------------------------------------------------------------------
/// MPL struct to figure out if a type is a boost::shared_ptr<T>
/// The general one inherits from boost::false_type
template <typename T> struct IsSharedPtr : boost::false_type {};

/// Specialization for boost::shared_ptr<const T> types to inherit from
/// boost::true_type
template <typename T>
struct IsSharedPtr<boost::shared_ptr<T>> : boost::true_type {};

//-----------------------------------------------------------------------
// Policy implementation
//-----------------------------------------------------------------------
/**
* Constructs a boost::weak_ptr around the incoming boost::shared_ptr
*/
template <typename ArgType> struct ToWeakPtrImpl {
// Useful types
typedef typename ArgType::element_type PointeeType;
typedef boost::weak_ptr<PointeeType> WeakPtr;

inline PyObject *operator()(const ArgType &p) const {
if (!p)
Py_RETURN_NONE;
return boost::python::to_python_value<WeakPtr>()(WeakPtr(p));
}

inline PyTypeObject const *get_pytype() const {
return boost::python::converter::registered<WeakPtr>::converters
.to_python_target_type();
}
};

//-----------------------------------------------------------------------
// Error handler
//-----------------------------------------------------------------------
template <typename T> struct ToWeakPtr_Requires_Shared_Ptr_Return_Value {};
} // ends anonymous namespace

/**
* Implements the ToWeakPtr policy as required by boost.python
*/
struct ToWeakPtr {
template <class T> struct apply {
// Deduce if type is correct for policy
typedef typename boost::mpl::if_c<
IsSharedPtr<T>::value, ToWeakPtrImpl<T>,
ToWeakPtr_Requires_Shared_Ptr_Return_Value<T>>::type type;
};
};

} // ends Policies namespace
}
} // ends Mantid::PythonInterface namespaces

#endif /* MANTID_PYTHONINTERFACE_REMOVECONST_H_REMOVECONST_H_ */
@@ -1,35 +1,49 @@
#include "MantidAPI/WorkspaceGroup.h"
#include "MantidPythonInterface/kernel/Policies/ToWeakPtr.h"
#include "MantidPythonInterface/kernel/Registry/RegisterWorkspacePtrToPython.h"

#include <boost/python/class.hpp>
#include <boost/python/return_value_policy.hpp>

using namespace Mantid::API;
using Mantid::PythonInterface::Registry::RegisterWorkspacePtrToPython;
using namespace Mantid::PythonInterface;
using namespace boost::python;

// clang-format off
void export_WorkspaceGroup()
void export_WorkspaceGroup()
// clang-format on
{
class_< WorkspaceGroup, bases<Workspace>, boost::noncopyable >("WorkspaceGroup", no_init)
.def("getNumberOfEntries", &WorkspaceGroup::getNumberOfEntries, "Returns the number of entries in the group")
.def("getNames", &WorkspaceGroup::getNames, "Returns the names of the entries in the group")
.def("contains", (bool (WorkspaceGroup::*)(const std::string & wsName) const)&WorkspaceGroup::contains, "Returns true if the given name is in the group")
.def("add", &WorkspaceGroup::add, "Add a name to the group")
.def("size", &WorkspaceGroup::size, "Returns the number of workspaces contained in the group")
.def("remove", &WorkspaceGroup::remove, "Remove a name from the group")
.def("getItem", (Workspace_sptr (WorkspaceGroup::*)(const size_t) const)&WorkspaceGroup::getItem,
"Returns the item at the given index")
.def("isMultiPeriod", &WorkspaceGroup::isMultiperiod, "Retuns true if the workspace group is multi-period")
// ------------ Operators --------------------------------
.def("__len__", &WorkspaceGroup::getNumberOfEntries)
.def("__contains__", (bool (WorkspaceGroup::*)(const std::string & wsName) const)&WorkspaceGroup::contains)
.def("__getitem__", (Workspace_sptr (WorkspaceGroup::*)(const size_t) const)&WorkspaceGroup::getItem)
;
class_<WorkspaceGroup, bases<Workspace>, boost::noncopyable>("WorkspaceGroup",
no_init)
.def("getNumberOfEntries", &WorkspaceGroup::getNumberOfEntries,
"Returns the number of entries in the group")
.def("getNames", &WorkspaceGroup::getNames,
"Returns the names of the entries in the group")
.def("contains",
(bool (WorkspaceGroup::*)(const std::string &wsName) const) &
WorkspaceGroup::contains,
"Returns true if the given name is in the group")
.def("add", &WorkspaceGroup::add, "Add a name to the group")
.def("size", &WorkspaceGroup::size,
"Returns the number of workspaces contained in the group")
.def("remove", &WorkspaceGroup::remove, "Remove a name from the group")
.def("getItem", (Workspace_sptr (WorkspaceGroup::*)(const size_t) const) &
WorkspaceGroup::getItem,
return_value_policy<Policies::ToWeakPtr>(),
"Returns the item at the given index")
.def("isMultiPeriod", &WorkspaceGroup::isMultiperiod,
"Retuns true if the workspace group is multi-period")
// ------------ Operators --------------------------------
.def("__len__", &WorkspaceGroup::getNumberOfEntries)
.def("__contains__",
(bool (WorkspaceGroup::*)(const std::string &wsName) const) &
WorkspaceGroup::contains)
.def("__getitem__",
(Workspace_sptr (WorkspaceGroup::*)(const size_t) const) &
WorkspaceGroup::getItem,
return_value_policy<Policies::ToWeakPtr>());

//-----------------------------------------------------------------------------------------------

RegisterWorkspacePtrToPython<WorkspaceGroup>();
Registry::RegisterWorkspacePtrToPython<WorkspaceGroup>();
}

Expand Up @@ -86,6 +86,8 @@ set ( INC_FILES
${HEADER_DIR}/kernel/Environment/Threading.h
${HEADER_DIR}/kernel/Environment/WrapperHelpers.h
${HEADER_DIR}/kernel/Policies/MatrixToNumpy.h
${HEADER_DIR}/kernel/Policies/RemoveConst.h
${HEADER_DIR}/kernel/Policies/ToWeakPtr.h
${HEADER_DIR}/kernel/Policies/VectorToNumpy.h
${HEADER_DIR}/kernel/Registry/PropertyValueHandler.h
${HEADER_DIR}/kernel/Registry/PropertyWithValueFactory.h
Expand Down
Expand Up @@ -42,6 +42,15 @@ def test_group_index_access_returns_correct_workspace(self):
member = group[i]
self.assertTrue(isinstance(member, MatrixWorkspace))

# Clearing the data should leave the handle unusable
member = group[0]
mtd.remove("First")
try:
member.name()
self.fail("Handle for item extracted from WorkspaceGroup is still usable after ADS has been cleared, it should be a weak reference and raise an error.")
except RuntimeError, exc:
self.assertEquals(str(exc), 'Variable invalidated, data has been deleted.')

def test_SimpleAlgorithm_Accepts_Group_Handle(self):
from mantid.simpleapi import Scale

Expand Down

0 comments on commit 0a6b102

Please sign in to comment.