Skip to content

Commit

Permalink
Tidy up singleton access from Python. Refs #4399
Browse files Browse the repository at this point in the history
Added aliases so that they can be called as if they were classes
with only static methods.
  • Loading branch information
martyngigg committed Mar 15, 2012
1 parent 75078ab commit c1394eb
Show file tree
Hide file tree
Showing 27 changed files with 194 additions and 144 deletions.
4 changes: 0 additions & 4 deletions Code/Mantid/Framework/PythonInterface/mantid/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,3 @@ def apiVersion():
###############################################################################
__version__ = version_str()

###############################################################################
# Aliases
###############################################################################
mtd = AnalysisDataService.Instance()
18 changes: 12 additions & 6 deletions Code/Mantid/Framework/PythonInterface/mantid/api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,18 @@
from _api import *
_dlopen.restore_flags(flags)

###############################################################################
# Alias singleton objects so they just look like classes with only
# static methods, which is really what they are
###############################################################################
FrameworkManager = FrameworkManagerImpl.Instance()
AnalysisDataService = AnalysisDataServiceImpl.Instance()
mtd = AnalysisDataService #tradition
AlgorithmFactory = AlgorithmFactoryImpl.Instance()
AlgorithmManager = AlgorithmManagerImpl.Instance()
FileFinder = FileFinderImpl.Instance()


###############################################################################
# Add importAll member to ADS
###############################################################################
Expand All @@ -28,11 +40,6 @@
###############################################################################
import _workspaceops

###############################################################################
# Make the singleton objects available as named variables
###############################################################################
FrameworkManager.Instance() # This starts the framework

###############################################################################
# Starting the FrameworkManager loads the C++ plugin libraries
# we need to load in the Python plugins as well
Expand All @@ -43,7 +50,6 @@
# Disabled for the time being as all algorithms are of the old kind
#_plugins.load(_cfg['pythonalgorithm.directories'])


###############################################################################
# When in GUI mode we want to be picky about algorithm execution as we
# currently can't run the scripts in a separate thread:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
The function is also attached to the AnalysisDataService and named importAll.
"""
from mantid.api import AnalysisDataService
from mantid.api import AnalysisDataServiceImpl
import inspect as _inspect
import keyword as _keyword
import re as _re
Expand Down Expand Up @@ -78,4 +78,4 @@ def clean(name):
locals_.update(vars)

# Attach to ADS as importAll
setattr(AnalysisDataService, "importAll", _importAll)
setattr(AnalysisDataServiceImpl, "importAll", _importAll)
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
from mantid.api import Workspace, AnalysisDataService, FrameworkManager, ITableWorkspace
from mantid.api import performBinaryOp as _performBinaryOp
from mantid.kernel.funcreturns import lhs_info
_ads = AnalysisDataService.Instance()

#------------------------------------------------------------------------------
# Binary Ops
Expand Down Expand Up @@ -83,8 +82,8 @@ def _do_binary_operation(op, self, rhs, lhs_vars, inplace, reverse):

if clear_tmps:
for name in _workspace_op_tmps:
if name in _ads and output_name != name:
del _ads[name]
if name in AnalysisDataService and output_name != name:
del AnalysisDataService[name]
_workspace_op_tmps = []

if inplace:
Expand Down Expand Up @@ -143,16 +142,16 @@ def _do_unary_operation(op, self, lhs_vars):
_workspace_op_tmps.append(output_name)

# Do the operation
alg = FrameworkManager.Instance().createAlgorithm(op)
alg = FrameworkManager.createAlgorithm(op)
alg.setPropertyValue("InputWorkspace", self.name())
alg.setPropertyValue("OutputWorkspace", output_name)
alg.execute()
resultws = _ads[output_name]
resultws = AnalysisDataService[output_name]

if clear_tmps:
for name in _workspace_op_tmps:
if name in _ads and output_name != name:
_ads.remove(name)
if name in AnalysisDataService and output_name != name:
AnalysisDataService.remove(name)
_workspace_op_tmps = []

return resultws
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,11 @@ namespace
void export_AlgorithmFactory()
{

class_<AlgorithmFactoryImpl,boost::noncopyable>("AlgorithmFactory", no_init)
.def("Instance", &AlgorithmFactory::Instance, return_value_policy<reference_existing_object>(), //This policy is really only safe for singletons
class_<AlgorithmFactoryImpl,boost::noncopyable>("AlgorithmFactoryImpl", no_init)
.def("getRegisteredAlgorithms", &getRegisteredAlgorithms, "Returns a Python dictionary of currently registered algorithms")
.def("Instance", &AlgorithmFactory::Instance, return_value_policy<reference_existing_object>(),
"Returns a reference to the AlgorithmFactory singleton")
.staticmethod("Instance")
.def("getRegisteredAlgorithms", &getRegisteredAlgorithms, "Returns a Python dictionary of ")
;

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,12 @@ namespace

void export_AlgorithmManager()
{
class_<AlgorithmManagerImpl,boost::noncopyable>("AlgorithmManager", no_init)
.def("Instance", &AlgorithmManager::Instance, return_value_policy<reference_existing_object>(), //This policy is really only safe for singletons
"Returns a reference to the AlgorithmManager singleton")
.staticmethod("Instance")
class_<AlgorithmManagerImpl,boost::noncopyable>("AlgorithmManagerImpl", no_init)
.def("create", &AlgorithmManagerImpl::create, create_overloads(args("name", "version"), "Creates a managed algorithm."))
.def("createUnmanaged", &AlgorithmManagerImpl::createUnmanaged,
createUnmanaged_overloads(args("name", "version"), "Creates an unmanaged algorithm."))
;
.def("Instance", &AlgorithmManager::Instance, return_value_policy<reference_existing_object>(),
"Returns a reference to the AlgorithmManager singleton")
.staticmethod("Instance")
;
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,16 +74,16 @@ void export_AnalysisDataService()
{
register_ptr_to_python<DataItem_wptr>();

class_<AnalysisDataServiceImpl,boost::noncopyable>("AnalysisDataService", no_init)
.def("Instance", &AnalysisDataService::Instance, return_value_policy<reference_existing_object>(),
"Return a reference to the ADS singleton")
.staticmethod("Instance")
class_<AnalysisDataServiceImpl,boost::noncopyable>("AnalysisDataServiceImpl", no_init)
.def("retrieve", &retrieveAsWeakPtr, return_value_policy<Policies::upcast_returned_value>(),
"Retrieve the named object. Raises an exception if the name does not exist")
.def("remove", &AnalysisDataServiceImpl::remove, "Remove a named object")
.def("clear", &AnalysisDataServiceImpl::clear, "Removes all objects managed by the service.")
.def("size", &AnalysisDataServiceImpl::size, "Returns the number of objects within the service")
.def("getObjectNames", &getObjectNamesAsList, "Return the list of names currently known to the ADS")
.def("Instance", &AnalysisDataService::Instance, return_value_policy<reference_existing_object>(),
"Return a reference to the ADS singleton")
.staticmethod("Instance")
// Make it act like a dictionary
.def("__len__", &AnalysisDataServiceImpl::size)
.def("__getitem__", &retrieveAsWeakPtr, return_value_policy<Policies::upcast_returned_value>())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,16 @@ using namespace boost::python;

void export_FileFinder()
{
class_<FileFinderImpl, boost::noncopyable>("FileFinder", no_init)
.def("Instance", &FileFinder::Instance, return_value_policy<reference_existing_object>(),
"Returns a reference to the FileFinder singleton instance")
.staticmethod("Instance")
class_<FileFinderImpl, boost::noncopyable>("FileFinderImpl", no_init)
.def("getFullPath", &FileFinderImpl::getFullPath,
"Return a full path to the given file if it can be found within datasearch.directories paths. "
"An empty string is returned otherwise.")
.def("findRuns", &FileFinderImpl::findRuns, "Find a list of files file given a hint. "
"The hint can be a comma separated list of run numbers and can also include ranges of runs, e.g. 123-135 or equivalently 123-35"
"If no instrument prefix is given then the current default is used.")
;
.def("Instance", &FileFinder::Instance, return_value_policy<reference_existing_object>(),
"Returns a reference to the FileFinder singleton instance")
.staticmethod("Instance")
;
}

Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <boost/python/overloads.hpp>
#include <boost/python/args.hpp>
#include <boost/python/converter/shared_ptr_to_python.hpp>
#include <boost/bind.hpp>

using Mantid::API::FrameworkManagerImpl;
using Mantid::API::FrameworkManager;
Expand Down Expand Up @@ -61,10 +62,7 @@ namespace

void export_FrameworkManager()
{
class_<FrameworkManagerImpl,boost::noncopyable>("FrameworkManager", no_init)
.def("Instance", &FrameworkManager::Instance, return_value_policy<reference_existing_object>(),
"Returns a reference to the FrameworkManager singleton")
.staticmethod("Instance")
class_<FrameworkManagerImpl,boost::noncopyable>("FrameworkManagerImpl", no_init)
.def("clear", &FrameworkManagerImpl::clear, "Clear all memory held by Mantid")
.def("clearAlgorithms", &FrameworkManagerImpl::clearAlgorithms, "Clear memory held by algorithms (does not include workspaces)")
.def("clearData", &FrameworkManagerImpl::clearData, "Clear memory held by the data service (essentially all workspaces, including hidden)")
Expand All @@ -74,6 +72,10 @@ void export_FrameworkManager()
create_overloads(args("name", "version"), "Creates and initializes an algorithm of the "
"given name and version. If this called from within a Python algorithm "
"an unmanaged algorithm is created otherwise it will be a managed algorithm"))
.def("Instance", &FrameworkManager::Instance, return_value_policy<reference_existing_object>(),
"Returns a reference to the FrameworkManager singleton")
.staticmethod("Instance")

;

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
###############################################################################
# Make the singleton objects available as named variables
###############################################################################
config = ConfigService.Instance()
ConfigService = ConfigServiceImpl.Instance()
config = ConfigService #shorter alias

###############################################################################
# Set up a general Python logger. Others can be created as they are required
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
"""
import os as _os
import imp as _imp
from mantid.kernel import Logger
from mantid.kernel import Logger, ConfigService


class PluginLoader(object):

Expand Down Expand Up @@ -96,8 +97,7 @@ def load_modules(self, refresh=False):
"""
Import Python modules containing Python algorithms
"""
from mantid.kernel import ConfigService
dir_list = ConfigService.Instance()["pythonalgorithms.directories"].split(';')
dir_list = ConfigService["pythonalgorithms.directories"].split(';')

# Check defined Python algorithm directories and load any modules
changes = False
Expand Down
Original file line number Diff line number Diff line change
@@ -1,27 +1,53 @@
#include "MantidKernel/ConfigService.h"
#include "MantidPythonInterface/kernel/Converters/PySequenceToVector.h"
#include <boost/python/class.hpp>
#include <boost/python/def.hpp>
#include <boost/python/reference_existing_object.hpp>
#include <boost/python/copy_const_reference.hpp>
#include <boost/python/list.hpp>

using Mantid::Kernel::ConfigService;
using Mantid::Kernel::ConfigServiceImpl;
using namespace boost::python;

namespace
{
/// Set directories from a python list
void setDataSearchDirs(ConfigServiceImpl &self, const boost::python::list & paths)
{
using namespace Mantid::PythonInterface;
self.setDataSearchDirs(Converters::PySequenceToVectorConverter<std::string>(paths)());
}
}

void export_ConfigService()
{
class_<ConfigServiceImpl, boost::noncopyable>("ConfigService", no_init)
.def("Instance", &ConfigService::Instance, return_value_policy<reference_existing_object>(),
"Returns a reference to the ConfigService")
.staticmethod("Instance")
class_<ConfigServiceImpl, boost::noncopyable>("ConfigServiceImpl", no_init)
.def("getLocalFilename", &ConfigServiceImpl::getLocalFilename, "Returns the path to the system wide properties file.")
.def("getUserFilename", &ConfigServiceImpl::getUserFilename, "Returns the path to the user properties file")
.def("getInstrumentDirectory", &ConfigServiceImpl::getInstrumentDirectory,
"Returns the directory used for the instrument definitions")
.def("getString", (std::string (ConfigServiceImpl::*)(const std::string &))&ConfigServiceImpl::getString,
"Return the given property")
.def("setString", &ConfigServiceImpl::setString, "Set the given property name. "
"If it does not exist it is added to the current configuration")
.def("hasProperty", &ConfigServiceImpl::hasProperty)
.def("getDataSearchDirs",&ConfigServiceImpl::getDataSearchDirs, return_value_policy<copy_const_reference>(),
"Return the current list of data search paths")
.def("appendDataSearchDir", &ConfigServiceImpl::appendDataSearchDir,
"Append a directory to the current list of data search paths")
"Append a directory to the current list of data search paths")
.def("setDataSearchDirs", (void (ConfigServiceImpl::*)(const std::string &))&ConfigServiceImpl::setDataSearchDirs,
"Set the whole datasearch.directories property from a single string. Entries should be separated by a ; character")
.def("setDataSearchDirs", &setDataSearchDirs,
"Set the datasearch.directories property from a list of strings.")
// Treat this as a dictionary
.def("__getitem__", (std::string (ConfigServiceImpl::*)(const std::string &))&ConfigServiceImpl::getString)
.def("__setitem__", &ConfigServiceImpl::setString)
.def("__contains__", &ConfigServiceImpl::hasProperty)
.def("Instance", &ConfigService::Instance, return_value_policy<reference_existing_object>(),
"Returns a reference to the ConfigService")
.staticmethod("Instance")

;
}

30 changes: 13 additions & 17 deletions Code/Mantid/Framework/PythonInterface/mantid/simpleapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,15 @@
and assign it to the rebinned variable
"""
import mantid
import api
import kernel
import api as _api
import kernel as _kernel
from kernel import funcreturns as _funcreturns
from kernel import logger as _logger
from api import AnalysisDataService as _ads
from api import FrameworkManager as _framework

# Make "mtd" and "logger" available if a user just types from mantid.simpleapi import *
from mantid import mtd, logger, apiVersion

_ads = api.AnalysisDataService.Instance()
_framework = api.FrameworkManager.Instance()

def version():
return "simpleapi - memory-based version"
# Give a user access to this
from mantid import apiVersion, __gui__

def _is_workspace_property(prop):
"""
Expand All @@ -43,7 +39,7 @@ def _is_workspace_property(prop):
@param prop - A property object
@returns True if the property is considered to be of type workspace
"""
if isinstance(prop, api.IWorkspaceProperty):
if isinstance(prop, _api.IWorkspaceProperty):
return True
if 'Workspace' in prop.name: return True
# Doesn't look like a workspace property
Expand Down Expand Up @@ -158,7 +154,7 @@ def _set_properties(alg_object, *args, **kwargs):
value = kwargs[key]
# Anything stored in the ADS must be set by string value
# if it is not a child algorithm.
if (not alg_object.isChild()) and isinstance(value, kernel.DataItem):
if (not alg_object.isChild()) and isinstance(value, _kernel.DataItem):
alg_object.setPropertyValue(key, value.name())
else:
alg_object.setProperty(key, value)
Expand Down Expand Up @@ -242,7 +238,7 @@ def _set_properties_dialog(algm_object, *args, **kwargs):
dialog box call. If the dialog is cancelled raise a runtime error, otherwise
return the algorithm ready to execute.
"""
if not mantid.__gui__:
if not __gui__:
raise RuntimeError("Can only display properties dialog in gui mode")

# generic setup
Expand Down Expand Up @@ -408,7 +404,7 @@ def get_argument_value(key, kwargs):
# Check for any properties that aren't known and warn they will not be used
for key in kwargs.keys():
if key not in algm:
mantid.logger.warning("You've passed a property (%s) to Load() that doesn't apply to this file type." % key)
_logger.warning("You've passed a property (%s) to Load() that doesn't apply to this file type." % key)
del kwargs[key]
_set_properties(algm, **kwargs)
algm.execute()
Expand Down Expand Up @@ -470,8 +466,8 @@ def translate():
"""
from api import AlgorithmFactory, AlgorithmManager

algs = AlgorithmFactory.Instance().getRegisteredAlgorithms(True)
algorithm_mgr = AlgorithmManager.Instance()
algs = AlgorithmFactory.getRegisteredAlgorithms(True)
algorithm_mgr = AlgorithmManager
for name, versions in algs.iteritems():
if name == "Load":
continue
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
class AlgorithmFactoryTest(unittest.TestCase):

def test_get_algorithm_factory_does_not_return_None(self):
self.assertTrue(AlgorithmFactory.Instance() is not None )
self.assertTrue(AlgorithmFactory is not None )

def test_get_registered_algs_returns_dictionary_of_known_algorithms(self):
all_algs = AlgorithmFactory.Instance().getRegisteredAlgorithms(True)
all_algs = AlgorithmFactory.getRegisteredAlgorithms(True)
self.assertTrue( len(all_algs) > 0 )
self.assertTrue( 'ConvertUnits' in all_algs )
# 3 versions of LoadRaw
Expand Down

0 comments on commit c1394eb

Please sign in to comment.