Skip to content

Commit

Permalink
Empty out the DataService objects before python exits.
Browse files Browse the repository at this point in the history
The instance methods are tracked using a reference count. When the
count reaches zero then it is assumed that the final object is being
deleted and the service is cleared.
Refs #8216
  • Loading branch information
martyngigg committed Mar 17, 2014
1 parent 69e528a commit 9ed8f06
Show file tree
Hide file tree
Showing 7 changed files with 126 additions and 26 deletions.
Expand Up @@ -44,6 +44,9 @@ namespace Mantid
class SingletonHolder
{
public:
/// Allow users to access to the type returned by Instance()
typedef T HeldType;

static T& Instance();

private:
Expand Down
@@ -0,0 +1,93 @@
#ifndef MANTID_PYTHONINTERFACE_TRACKINGINSTANCEMETHOD_H_
#define MANTID_PYTHONINTERFACE_TRACKINGINSTANCEMETHOD_H_

/*
Copyright © 2014 ISIS Rutherford Appleton Laboratory & NScD Oak Ridge National Laboratory
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/class.hpp>

namespace Mantid
{
namespace PythonInterface
{
/**
* Add an Instance() & __del__ method to the already exported python type.
* The methods track how many times instance() & __del__ are called and clear the
* SingletonType object when the count reaches zero.
* @tparam SingletonType The main SingletonHolder type. It is expected to have a nested type
* HeldType that defines the implementation
* @tparam PythonType The boost.python C++ exported type
*/
template<typename SingletonType, typename PythonType>
class TrackingInstanceMethod
{
/// Type returned by instance()
typedef typename SingletonType::HeldType InstanceType;

public:
/**
* Add the instance tracking methods
* @param classType The python type already exported using class_
*/
static void define(PythonType & classType)
{
classType.def("__del__", &TrackingInstanceMethod::decref);
classType.def("Instance", &TrackingInstanceMethod::instance,
return_value_policy<reference_existing_object>(),
"Return a reference to the singleton instance");
classType.staticmethod("Instance");
}

/**
* Increment reference count & return the singleton instance
* @return A reference to the InstanceType
*/
static InstanceType &instance()
{
++g_py_instance_count;
return SingletonType::Instance();
}

/**
* @param self The calling object
*/
static void decref(InstanceType & self)
{
--g_py_instance_count;
if (g_py_instance_count == 0)
{
self.clear();
}
}

private:
/// Track the number of calls to instance/decref
static size_t g_py_instance_count;
};

/// Initialize static counter
template <typename T, typename S>
size_t TrackingInstanceMethod<T,S>::g_py_instance_count = 0;

}
}

#endif /* MANTID_PYTHONINTERFACE_TRACKINGINSTANCEMETHOD */
@@ -1,5 +1,6 @@
#include "MantidAPI/AlgorithmManager.h"
#include "MantidPythonInterface/api/AlgorithmIDProxy.h"
#include "MantidPythonInterface/kernel/TrackingInstanceMethod.h"

#include <boost/python/class.hpp>
#include <boost/python/def.hpp>
Expand All @@ -10,6 +11,7 @@

using namespace Mantid::API;
using Mantid::PythonInterface::AlgorithmIDProxy;
using Mantid::PythonInterface::TrackingInstanceMethod;
using namespace boost::python;

namespace
Expand Down Expand Up @@ -66,7 +68,9 @@ namespace

void export_AlgorithmManager()
{
class_<AlgorithmManagerImpl,boost::noncopyable>("AlgorithmManagerImpl", no_init)
typedef class_<AlgorithmManagerImpl,boost::noncopyable> PythonType;

auto pythonClass = class_<AlgorithmManagerImpl,boost::noncopyable>("AlgorithmManagerImpl", no_init)
.def("create", &AlgorithmManagerImpl::create, create_overloads((arg("name"), arg("version")), "Creates a managed algorithm."))
.def("createUnmanaged", &AlgorithmManagerImpl::createUnmanaged,
createUnmanaged_overloads((arg("name"), arg("version")), "Creates an unmanaged algorithm."))
Expand All @@ -83,9 +87,9 @@ void export_AlgorithmManager()
.def("clear", &AlgorithmManagerImpl::clear, "Clears the current list of managed algorithms")
.def("cancelAll", &AlgorithmManagerImpl::cancelAll,
"Requests that all currently running algorithms be cancelled")

.def("Instance", &AlgorithmManager::Instance, return_value_policy<reference_existing_object>(),
"Returns a reference to the AlgorithmManager singleton")
.staticmethod("Instance")
;

// Instance method
TrackingInstanceMethod<AlgorithmManager, PythonType>::define(pythonClass);

}
@@ -1,5 +1,6 @@
#include "MantidPythonInterface/kernel/DataServiceExporter.h"
#include "MantidPythonInterface/kernel/Registry/DowncastRegistry.h"
#include "MantidPythonInterface/kernel/TrackingInstanceMethod.h"

#include "MantidAPI/AnalysisDataService.h"
#include "MantidAPI/Workspace.h"
Expand All @@ -11,6 +12,7 @@

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

Expand Down Expand Up @@ -68,22 +70,18 @@ namespace

void export_AnalysisDataService()
{

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

// -- special ADS behaviour --
// replace the add/addOrReplace,__setitem__ methods as we need to exact the exact stored type
adsType.def("add", &addItem,
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.");
adsType.def("addOrReplace", &addOrReplaceItem,
pythonClass.def("addOrReplace", &addOrReplaceItem,
"Adds the given object to the service with the given name. The the name exists the object is replaced.");
adsType.def("__setitem__", &addOrReplaceItem);
pythonClass.def("__setitem__", &addOrReplaceItem);

// Add instance method for the ADS singleton
adsType.def("Instance", &AnalysisDataService::Instance,
return_value_policy<reference_existing_object>(),
"Return a reference to the ADS singleton");
adsType.staticmethod("Instance");
// Instance method
TrackingInstanceMethod<AnalysisDataService, typename ADSExporter::PythonType>::define(pythonClass);
}

@@ -1,4 +1,5 @@
#include "MantidPythonInterface/kernel/DataServiceExporter.h"
#include "MantidPythonInterface/kernel/TrackingInstanceMethod.h"

#include "MantidAPI/PropertyManagerDataService.h"
#include "MantidKernel/PropertyManager.h"
Expand All @@ -7,22 +8,23 @@

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

/// Weak pointer to DataItem typedef
typedef boost::weak_ptr<PropertyManager> PropertyManager_wptr;

void export_PropertyManagerDataService()
{
using Mantid::PythonInterface::DataServiceExporter;

register_ptr_to_python<PropertyManager_wptr>();
auto pmdType = DataServiceExporter<PropertyManagerDataServiceImpl,
PropertyManager_sptr>::define("PropertyManagerDataServiceImpl");

pmdType.def("Instance", &PropertyManagerDataService::Instance,
return_value_policy<reference_existing_object>(),
"Return a reference to the ADS singleton");
pmdType.staticmethod("Instance");
typedef DataServiceExporter<PropertyManagerDataServiceImpl, PropertyManager_sptr> PMDExporter;
auto pmdType = PMDExporter::define("PropertyManagerDataServiceImpl");

// Instance method
TrackingInstanceMethod<PropertyManagerDataService, typename PMDExporter::PythonType>::define(pmdType);

}

Expand Up @@ -95,6 +95,7 @@ set ( INC_FILES
${HEADER_DIR}/kernel/PropertyWithValueExporter.h
${HEADER_DIR}/kernel/PythonObjectInstantiator.h
${HEADER_DIR}/kernel/StlExportDefinitions.h
${HEADER_DIR}/kernel/TrackingInstanceMethod.h
${HEADER_DIR}/kernel/TypedValidatorExporter.h
)

Expand Down
5 changes: 2 additions & 3 deletions Code/Mantid/MantidQt/CustomInterfaces/test/CMakeLists.txt
Expand Up @@ -6,11 +6,10 @@ if ( CXXTEST_FOUND )
set ( TESTHELPER_SRCS ../../../Framework/TestHelpers/src/ComponentCreationHelper.cpp
../../../Framework/TestHelpers/src/WorkspaceCreationHelper.cpp
../../../Framework/TestHelpers/src/ScopedFileHelper.cpp
)
../../../Framework/TestHelpers/src/TearDownWorld.cpp
)

if ( GMOCK_FOUND AND GTEST_FOUND )
set ( TESTHELPER_SRCS ../../../Framework/TestHelpers/src/TearDownWorld.cpp )

cxxtest_add_test ( CustomInterfacesTest ${TEST_FILES} ${GMOCK_TEST_FILES} )
target_link_libraries( CustomInterfacesTest CustomInterfaces DataObjects ${GMOCK_LIBRARIES} ${GTEST_LIBRARIES} )
add_dependencies( CustomInterfacesTest MDAlgorithms )
Expand Down

0 comments on commit 9ed8f06

Please sign in to comment.