diff --git a/Code/Mantid/Framework/PythonInterface/inc/MantidPythonInterface/api/ExtractWorkspace.h b/Code/Mantid/Framework/PythonInterface/inc/MantidPythonInterface/api/ExtractWorkspace.h new file mode 100644 index 000000000000..aea2f398e4e7 --- /dev/null +++ b/Code/Mantid/Framework/PythonInterface/inc/MantidPythonInterface/api/ExtractWorkspace.h @@ -0,0 +1,43 @@ +#ifndef MANTID_PYTHONINTERFACE_EXTRACTWORKSPACE_H_ +#define MANTID_PYTHONINTERFACE_EXTRACTWORKSPACE_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 . + + File change history is stored at: + Code Documentation is available at: +*/ +#include + +#include + +namespace Mantid { +namespace PythonInterface { + +struct ExtractWorkspace { + ExtractWorkspace(const boost::python::object &pyvalue); + bool check() const; + const API::Workspace_sptr operator()() const; + +private: + API::Workspace_sptr m_value; +}; +} +} + +#endif // MANTID_PYTHONINTERFACE_EXTRACTWORKSPACE_H_ diff --git a/Code/Mantid/Framework/PythonInterface/inc/MantidPythonInterface/kernel/Policies/DowncastingPolicies.h b/Code/Mantid/Framework/PythonInterface/inc/MantidPythonInterface/kernel/Policies/DowncastingPolicies.h deleted file mode 100644 index d13f07a7e0ab..000000000000 --- a/Code/Mantid/Framework/PythonInterface/inc/MantidPythonInterface/kernel/Policies/DowncastingPolicies.h +++ /dev/null @@ -1,130 +0,0 @@ -#ifndef MANITD_PYTHONINTERFACE_TOWEAKPTRWITHDOWNCASTIMPL_H_ -#define MANITD_PYTHONINTERFACE_TOWEAKPTRWITHDOWNCASTIMPL_H_ -/** - Copyright © 2012 ISIS Rutherford Appleton Laboratory, NScD Oak Ridg - 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 . - - File change history is stored at: - Code Documentation is available at: - */ -#include "MantidPythonInterface/kernel/Registry/DowncastRegistry.h" -#include - -#include // for PyObject - -#include -#include - -namespace Mantid { - -namespace PythonInterface { - -//-------------------------------------------------------------------------------- -// Implementations -//-------------------------------------------------------------------------------- -///@cond -namespace // anonymous namespace with the implementation - { -template struct AsWeakPtr { - static PyObject *apply(const Registry::DowncastDataItem &caster, - const ArgType &p) { - return caster.toPythonAsWeakPtr(p); - } -}; -template struct AsSharedPtr { - static PyObject *apply(const Registry::DowncastDataItem &caster, - const ArgType &p) { - return caster.toPythonAsSharedPtr(p); - } -}; - -/** - * Converts a ArgType object to a Python object and performs an downcast if it - * can. - * Only used for DataItem's at the moment so ArgType will always equal - * DataItem_sptr - * but the template is kept for possible extension in the future - */ -template struct DowncastImpl { - inline PyObject *operator()(const ArgType &p) const { - if (!p) - Py_RETURN_NONE; - return CasterType::apply(Registry::DowncastRegistry::retrieve(p->id()), p); - } - - inline PyTypeObject const *get_pytype() const { - return boost::python::converter::registered::converters - .to_python_target_type(); - } -}; - -} // end -///@endcond - -namespace Policies { -/** - * NOTE: These only workspace for functions/methods returning a shared_ptr - * where T is convertible to a Kernel::DataItem as it requires - * the presence of an id() method - */ - -//-------------------------------------------------------------------------------- -// ToWeakPtrWithDowncast -//-------------------------------------------------------------------------------- -/** - * This defines the structure as required by boost::python. - * If T is convertible to a shared_ptr then it calls - * ToWeakPtrWithDownastImpl or else just return the value as is - */ -struct ToWeakPtrWithDowncast { - template struct apply { - // if convertible to shared_ptr then call - // ToWeakPtrWithDownCastImpl or else - // just return the value as is - typedef typename boost::mpl::if_c< - boost::is_convertible>::value, - DowncastImpl>, - boost::python::to_python_value>::type type; - }; -}; - -//-------------------------------------------------------------------------------- -// ToSharedPtrWithDowncast -//-------------------------------------------------------------------------------- -/** - * This defines the structure as required by boost::python. - * If T is convertible to a shared_ptr then it calls - * ToSharedPtrWithDowncastImpl or else just return the value as is - */ -struct ToSharedPtrWithDowncast { - template struct apply { - // if convertible to shared_ptr then call - // ToWeakPtrWithDownCastImpl or else - // just return the value as is - typedef typename boost::mpl::if_c< - boost::is_convertible>::value, - DowncastImpl>, - boost::python::to_python_value>::type type; - }; -}; - -} // Policies -} -} // namespace Mantid::PythonInterface - -#endif /* MANITD_PYTHONINTERFACE_TOWEAKPTRWITHDOWNCASTIMPL_H_ */ diff --git a/Code/Mantid/Framework/PythonInterface/inc/MantidPythonInterface/kernel/PropertyWithValueExporter.h b/Code/Mantid/Framework/PythonInterface/inc/MantidPythonInterface/kernel/PropertyWithValueExporter.h index 558c583ee3ce..168d4d80df41 100644 --- a/Code/Mantid/Framework/PythonInterface/inc/MantidPythonInterface/kernel/PropertyWithValueExporter.h +++ b/Code/Mantid/Framework/PythonInterface/inc/MantidPythonInterface/kernel/PropertyWithValueExporter.h @@ -25,12 +25,12 @@ */ #include "MantidKernel/PropertyWithValue.h" -#include "MantidPythonInterface/kernel/Policies/DowncastingPolicies.h" #ifndef Q_MOC_RUN #include #include #include +#include #endif namespace Mantid { @@ -38,18 +38,17 @@ namespace PythonInterface { /** * A helper struct to export PropertyWithValue<> types to Python. */ -template struct PropertyWithValueExporter { +template +struct PropertyWithValueExporter { static void define(const char *pythonClassName) { using namespace boost::python; using namespace Mantid::Kernel; class_, bases, boost::noncopyable>( pythonClassName, no_init) - .add_property( - "value", - make_function( - &PropertyWithValue::operator(), - return_value_policy())); + .add_property("value", + make_function(&PropertyWithValue::operator(), + return_value_policy())); } }; } diff --git a/Code/Mantid/Framework/PythonInterface/inc/MantidPythonInterface/kernel/Registry/DowncastDataItem.h b/Code/Mantid/Framework/PythonInterface/inc/MantidPythonInterface/kernel/Registry/DowncastDataItem.h deleted file mode 100644 index 455c759ecbda..000000000000 --- a/Code/Mantid/Framework/PythonInterface/inc/MantidPythonInterface/kernel/Registry/DowncastDataItem.h +++ /dev/null @@ -1,119 +0,0 @@ -#ifndef MANTID_PYTHONINTERFACE_DOWNCASTDATAITEM_H_ -#define MANTID_PYTHONINTERFACE_DOWNCASTDATAITEM_H_ -/** - Copyright © 2014 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 . - - File change history is stored at: - Code Documentation is available at: -*/ -#include "MantidKernel/DataItem.h" -#include "MantidPythonInterface/kernel/WeakPtr.h" - -#include -#include // for PyObject -#include - -namespace Mantid { -namespace PythonInterface { -namespace Registry { -/** - * Interface class so that we can store derived objects in a map - * It defines functions for converting shared_ptr into - * Python objects of the required type - */ -struct DLLExport DowncastDataItem { - virtual ~DowncastDataItem() {} - /// Convert a shared_ptr to a python object that holds a shared_ptr - virtual PyObject * - toPythonAsSharedPtr(const Kernel::DataItem_sptr &data) const = 0; - /// Convert a shared_ptr to a python object that holds a weak_ptr - virtual PyObject * - toPythonAsWeakPtr(const Kernel::DataItem_sptr &data) const = 0; - /// Convert a Python object to a DataItem_sptr - virtual Kernel::DataItem_sptr - fromPythonAsSharedPtr(const boost::python::object &data) const = 0; -}; - -/** - * Implementation of DowncastDataItem interface - * @tparam CastedType The final type that the input item should be cast to when - * going to Python - */ -template -struct DLLExport DowncastToType : public DowncastDataItem { - typedef boost::shared_ptr PythonType_sptr; - typedef boost::weak_ptr PythonType_wptr; - - /** - * Convert a shared_ptr to a python object that holds a - * shared_ptr - * @param data The original C++ DataItem pointer - * @returns A new PyObject holding the requested data - */ - PyObject *toPythonAsSharedPtr(const Kernel::DataItem_sptr &data) const { - using namespace boost::python; - typedef to_python_value ToSharedValue; - // boost python handles NULL pointers by converting them to None objects - return ToSharedValue()(boost::dynamic_pointer_cast(data)); - } - /** - * Convert a shared_ptr to a python object that holds a - * weak_ptr - * @param data The original C++ DataItem pointer - * @returns A new PyObject holding the requested data - */ - PyObject *toPythonAsWeakPtr(const Kernel::DataItem_sptr &data) const { - using namespace boost::python; - typedef to_python_value ToWeakValue; - return ToWeakValue()( - PythonType_wptr(boost::dynamic_pointer_cast(data))); - } - /** - * Convert a Python object to a boost::shared_ptr - * @param data A Python object that should be holding either a - * boost::shared_ptr - * or a boost::weak_ptr - */ - Kernel::DataItem_sptr - fromPythonAsSharedPtr(const boost::python::object &data) const { - using namespace boost::python; - // If we can extract a weak pointer then we must construct the shared - // pointer - // from the weak pointer itself to ensure the new shared_ptr has the correct - // use count. - // The order is important as if we try the shared_ptr first then - // boost::python will - // just construct a brand new shared pointer for the object rather than - // converting from the - // stored weak one. - extract weakPtr(data); - if (weakPtr.check()) { - return boost::dynamic_pointer_cast(weakPtr().lock()); - } else { - return boost::dynamic_pointer_cast( - extract(data)()); - } - } -}; - -} // namespace Registry -} // namespace PythonInterface -} // namespace Mantid - -#endif /* MANTID_PYTHONINTERFACE_DOWNCASTDATAITEM_H_ */ diff --git a/Code/Mantid/Framework/PythonInterface/inc/MantidPythonInterface/kernel/Registry/DowncastRegistry.h b/Code/Mantid/Framework/PythonInterface/inc/MantidPythonInterface/kernel/Registry/DowncastRegistry.h deleted file mode 100644 index c3c0befd01d0..000000000000 --- a/Code/Mantid/Framework/PythonInterface/inc/MantidPythonInterface/kernel/Registry/DowncastRegistry.h +++ /dev/null @@ -1,72 +0,0 @@ -#ifndef MANTID_PYTHONINTERFACE_DOWNCASTREGISTRY_H_ -#define MANTID_PYTHONINTERFACE_DOWNCASTREGISTRY_H_ -/** - Copyright © 2012 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 . - - File change history is stored at: - Code Documentation is available at: -*/ -#include "MantidPythonInterface/kernel/Registry/DowncastDataItem.h" -#include - -namespace Mantid { -namespace PythonInterface { -namespace Registry { -// We currently only expose up to the API level in Python. Due to the -// inner workings of boost::python this means that if a DataItem_sptr or -// Workspace_sptr is returned from a particular method then it is not -// automatically converted to the most derived pointer that boost::python -// knows about. -// -// In order for returned objects to be of any use in Python then they must be -// cast to the highest-type that has been exposed, i.e a Workspace2D should be -// return as a MatrixWorkspace or a MaskWorkspace should be returned as an -// IMaskWorkspace. Here we define a registry that allows the required mappings -// to be defined and used. -// -// The mappings are between the string returned by the id() method and a simple -// templated DowncastDataItem converter class. - -/** - * A simple static class with methods to subscribe and retrieve the relevant - * DowncastDataItem object - */ -class DLLExport DowncastRegistry { -public: - /** - * Create an entry in the registry for a type given by the template type - * that will be identified by the id string given - * @param id string that will be returned by the concrete types id() method - */ - template static void subscribe(const std::string &id) { - subscribe(id, new DowncastToType()); - } - /// Retrieve a registered casting object - static const DowncastDataItem &retrieve(const std::string &id); - -private: - /// Implementation for the templated subscribe for a given id. Keeps impl out - /// of header - static void subscribe(const std::string &id, const DowncastDataItem *caster); -}; -} -} -} - -#endif /* MANTID_PYTHONINTERFACE_DOWNCASTREGISTRY_H_ */ diff --git a/Code/Mantid/Framework/PythonInterface/inc/MantidPythonInterface/kernel/Registry/DataItemInterface.h b/Code/Mantid/Framework/PythonInterface/inc/MantidPythonInterface/kernel/Registry/RegisterWorkspacePtrToPython.h similarity index 90% rename from Code/Mantid/Framework/PythonInterface/inc/MantidPythonInterface/kernel/Registry/DataItemInterface.h rename to Code/Mantid/Framework/PythonInterface/inc/MantidPythonInterface/kernel/Registry/RegisterWorkspacePtrToPython.h index 8250d812b784..3c69a5b0a711 100644 --- a/Code/Mantid/Framework/PythonInterface/inc/MantidPythonInterface/kernel/Registry/DataItemInterface.h +++ b/Code/Mantid/Framework/PythonInterface/inc/MantidPythonInterface/kernel/Registry/RegisterWorkspacePtrToPython.h @@ -24,6 +24,8 @@ */ #include "MantidPythonInterface/kernel/Registry/TypedPropertyValueHandler.h" #include "MantidPythonInterface/kernel/Registry/TypeRegistry.h" +#include "MantidPythonInterface/kernel/WeakPtr.h" + #include namespace Mantid { @@ -37,11 +39,11 @@ namespace Registry { * - Calls register_ptr_to_python> * - Registers a new PropertyValueHandler for a boost::shared_ptr */ -template struct DLLExport DataItemInterface { +template struct DLLExport RegisterWorkspacePtrToPython { typedef boost::shared_ptr IType_sptr; typedef boost::weak_ptr IType_wptr; /// Constructor - DataItemInterface() { + RegisterWorkspacePtrToPython() { using namespace boost::python; using namespace Registry; @@ -50,11 +52,6 @@ template struct DLLExport DataItemInterface { // properties can only ever store pointers to these TypeRegistry::subscribe>(); } - /// Register a downcast for this ID - DataItemInterface &castFromID(const std::string &id) { - using namespace Registry; - return *this; - } }; } } diff --git a/Code/Mantid/Framework/PythonInterface/inc/MantidPythonInterface/kernel/Registry/TypedPropertyValueHandler.h b/Code/Mantid/Framework/PythonInterface/inc/MantidPythonInterface/kernel/Registry/TypedPropertyValueHandler.h index fbb6a7bfbb5f..b784421835f7 100644 --- a/Code/Mantid/Framework/PythonInterface/inc/MantidPythonInterface/kernel/Registry/TypedPropertyValueHandler.h +++ b/Code/Mantid/Framework/PythonInterface/inc/MantidPythonInterface/kernel/Registry/TypedPropertyValueHandler.h @@ -22,16 +22,19 @@ File change history is stored at: Code Documentation is available at: */ +#include "MantidPythonInterface/api/ExtractWorkspace.h" #include "MantidPythonInterface/kernel/Registry/PropertyValueHandler.h" -#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" #include #include +#include +#include + #include namespace Mantid { @@ -88,7 +91,7 @@ struct DLLExport TypedPropertyValueHandler : public PropertyValueHandler { }; // -// Specialization for shared_ptr types that can be set via weak pointers +// Specialization for shared_ptr types. They need special handling for workspaces // template struct DLLExport TypedPropertyValueHandler> @@ -109,21 +112,7 @@ struct DLLExport TypedPropertyValueHandler> */ void set(Kernel::IPropertyManager *alg, const std::string &name, const boost::python::object &value) const { - using namespace boost::python; - using Mantid::API::Workspace_sptr; - typedef boost::weak_ptr Workspace_wptr; - - Workspace_sptr p; - extract weakExtract(value); - extract 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(name, boost::dynamic_pointer_cast(p)); + alg->setProperty(name, boost::dynamic_pointer_cast(ExtractWorkspace(value)())); } /** diff --git a/Code/Mantid/Framework/PythonInterface/mantid/api/CMakeLists.txt b/Code/Mantid/Framework/PythonInterface/mantid/api/CMakeLists.txt index cc3435e40577..5627f30ebfdb 100644 --- a/Code/Mantid/Framework/PythonInterface/mantid/api/CMakeLists.txt +++ b/Code/Mantid/Framework/PythonInterface/mantid/api/CMakeLists.txt @@ -80,6 +80,7 @@ set ( SRC_FILES src/PythonAlgorithm/AlgorithmAdapter.cpp src/PythonAlgorithm/DataProcessorAdapter.cpp src/CloneMatrixWorkspace.cpp + src/ExtractWorkspace.cpp ) set ( INC_FILES @@ -91,6 +92,7 @@ set ( INC_FILES ${HEADER_DIR}/api/PythonAlgorithm/DataProcessorAdapter.h ${HEADER_DIR}/api/BinaryOperations.h ${HEADER_DIR}/api/CloneMatrixWorkspace.h + ${HEADER_DIR}/api/ExtractWorkspace.h ${HEADER_DIR}/api/WorkspacePropertyExporter.h ) diff --git a/Code/Mantid/Framework/PythonInterface/mantid/api/src/Algorithms/RunPythonScript.cpp b/Code/Mantid/Framework/PythonInterface/mantid/api/src/Algorithms/RunPythonScript.cpp index c15bd4e9b70e..773955d9bd63 100644 --- a/Code/Mantid/Framework/PythonInterface/mantid/api/src/Algorithms/RunPythonScript.cpp +++ b/Code/Mantid/Framework/PythonInterface/mantid/api/src/Algorithms/RunPythonScript.cpp @@ -1,223 +1,220 @@ #include "MantidPythonInterface/api/Algorithms/RunPythonScript.h" +#include "MantidPythonInterface/api/ExtractWorkspace.h" #include "MantidPythonInterface/kernel/Environment/ErrorHandling.h" #include "MantidPythonInterface/kernel/Environment/Threading.h" -#include "MantidPythonInterface/kernel/Policies/DowncastingPolicies.h" -#include "MantidPythonInterface/kernel/Registry/DowncastDataItem.h" +#include "MantidPythonInterface/kernel/IsNone.h" #include "MantidKernel/MandatoryValidator.h" #include #include #include #include +#include #include -namespace Mantid -{ - namespace PythonInterface - { - - /// Algorithm's name for identification. @see Algorithm::name - const std::string RunPythonScript::name() const { return "RunPythonScript";} - - /// Algorithm's version for identification. @see Algorithm::version - int RunPythonScript::version() const { return 1;} - - /// Algorithm's category for identification. @see Algorithm::category - const std::string RunPythonScript::category() const { return "DataHandling\\LiveData\\Support"; } - - /// @copydoc Algorithm::summary - const std::string RunPythonScript::summary() const { return "Executes a snippet of Python code"; } - - /** - * Override standard group behaviour so that the algorithm is only - * called once for the whole group - */ - bool RunPythonScript::checkGroups() - { - return false; - } - - /** - * Initialize the algorithm's properties. - */ - void RunPythonScript::init() - { - using namespace API; - using namespace Kernel; - - declareProperty(new WorkspaceProperty("InputWorkspace","",Direction::Input, PropertyMode::Optional), - "An input workspace that the python code will modify." - "The workspace will be in the python variable named 'input'."); - declareProperty("Code", "", "Python code (can be on multiple lines).", - boost::make_shared >()); - declareProperty(new WorkspaceProperty("OutputWorkspace","",Direction::Output, PropertyMode::Optional), - "An output workspace to be produced by the python code." - "The workspace will be in the python variable named 'output'."); - } - - //---------------------------------------------------------------------------------------------- - /** Execute the algorithm. - */ - void RunPythonScript::exec() - { - using namespace API; - - Workspace_sptr outputWS = executeScript(scriptCode()); - setProperty("OutputWorkspace", outputWS); - } - - /** - * Builds the code string from the user input. The user script is wrapped - * in a tiny PythonAlgorithm to 'fool' the Python framework into - * creating a child algorithm for each algorithm that is run. See - * PythonInterface/mantid/simpleapi.py:_create_algorithm_object - * This has to be the case to get the workspace locking correct. - * - * The code assumes that the scope in which it is executed has defined - * the variables input & output. - * - * @return A string containing the code ready to execute - */ - std::string RunPythonScript::scriptCode() const - { - std::string userCode = getPropertyValue("Code"); - // Unify line endings - boost::regex eol("\\R"); // \R is Perl syntax for matching any EOL sequence - userCode = boost::regex_replace(userCode, eol, "\n"); // converts all to LF - - // Wrap and indent the user code (see method documentation) - std::istringstream is(userCode); - std::ostringstream os; - const char * indent = " "; - os << "import mantid\n" - << "from mantid.simpleapi import *\n" - << "class _DUMMY_ALG(mantid.api.PythonAlgorithm):\n" - << indent << "def PyExec(self, input=None,output=None):\n"; - std::string line; - while(getline(is, line)) - { - os << indent << indent << line << "\n"; - } - os << indent << indent << "return input,output\n"; // When executed the global scope needs to know about input,output so we return them - os << "input,output = _DUMMY_ALG().PyExec(input,output)"; - - if(g_log.is(Kernel::Logger::Priority::PRIO_DEBUG)) g_log.debug() << "Full code to be executed:\n" << os.str() << "\n"; - return os.str(); - } - - /** - * Sets up the code context & executes it. - * A python dictionary of local attributes is setup to contain a reference to the input workspace - * & the output workspace. This together with the __main__ global dictionary defines the execution - * context - * @param script A string containing a read-to-execute script - * @return A pointer to the output workspace if one was generated. If one was not then this is an empty pointer - */ - boost::shared_ptr RunPythonScript::executeScript(const std::string & script) const - { - using namespace API; - using namespace boost::python; - - // Execution - Environment::GlobalInterpreterLock gil; - auto locals = doExecuteScript(script); - return extractOutputWorkspace(locals); - } - - /** - * Uses the __main__ object to define the globals context and together with the given locals - * dictionary executes the script. The GIL is acquired and released during this call - * @param script The script code - * @returns A dictionary defining the input & output variables - */ - boost::python::dict RunPythonScript::doExecuteScript(const std::string & script) const - { - // Retrieve the main module. - auto main = boost::python::import("__main__"); - // Retrieve the main module's namespace - boost::python::object globals(main.attr("__dict__")); - boost::python::dict locals = buildLocals(); - try - { - boost::python::exec(script.c_str(), globals, locals); - } - catch(boost::python::error_already_set &) - { - Environment::throwRuntimeError(); - } - return locals; - } - - /** - * Creates a Python dictionary containing definitions of the 'input' & 'output' variable - * references that the script may use - * @return A Python dictionary that can be used as the locals argument for the script execution - */ - boost::python::dict RunPythonScript::buildLocals() const - { - // Define the local variable names required by the script, in this case - // - input: Points to input workspace if one has been given - // - output: Will point to the output workspace if one has been given - using namespace boost::python; - - dict locals; - locals["input"] = object(); // default to None - locals["output"] = object(); - - API::Workspace_sptr inputWS = getProperty("InputWorkspace"); - if(inputWS) - { - // We have a generic workspace ptr but the Python needs to see the derived type so - // that it can access the appropriate methods for that instance - // The ToSharedPtrWithDowncast policy is already in place for this and is used in many - // method exports as part of a return_value_policy struct. - // It is called manually here. - typedef Policies::ToSharedPtrWithDowncast::apply::type WorkspaceDowncaster; - locals["input"] = object(handle<>(WorkspaceDowncaster()(inputWS))); - } - std::string outputWSName = getPropertyValue("OutputWorkspace"); - if(!outputWSName.empty()) - { - locals["output"] = object(handle<>(to_python_value()(outputWSName))); - } - return locals; - } - - - /** - * If an output workspace was created then extract it from the given dictionary - * @param locals A dictionary possibly containing an 'output' reference - * @return A pointer to the output workspace if created, otherwise an empty pointer - */ - boost::shared_ptr RunPythonScript::extractOutputWorkspace(const boost::python::dict & locals) const - { - using namespace API; - using namespace boost::python; - - // Might be None, string or a workspace object - object pyoutput = locals["output"]; - if(pyoutput.ptr() == Py_None) return Workspace_sptr(); - - if(PyObject_HasAttrString(pyoutput.ptr(), "id")) - { - const auto & entry = Registry::DowncastRegistry::retrieve(call_method(pyoutput.ptr(), "id")); - return boost::dynamic_pointer_cast(entry.fromPythonAsSharedPtr(pyoutput)); - } - else - { - extract stringExtractor(pyoutput); - if(stringExtractor.check()) - { - // Will raise an error if the workspace does not exist as the user requested an output workspace - // but didn't create one. - return AnalysisDataService::Instance().retrieve(stringExtractor()); - } - else - { - throw std::runtime_error("Invalid type assigned to 'output' variable. Must be a string or a Workspace object"); - } - } +namespace Mantid { +namespace PythonInterface { + +using namespace API; +using namespace Kernel; + +/// Algorithm's name for identification. @see Algorithm::name +const std::string RunPythonScript::name() const { return "RunPythonScript"; } + +/// Algorithm's version for identification. @see Algorithm::version +int RunPythonScript::version() const { return 1; } + +/// Algorithm's category for identification. @see Algorithm::category +const std::string RunPythonScript::category() const { + return "DataHandling\\LiveData\\Support"; +} + +/// @copydoc Algorithm::summary +const std::string RunPythonScript::summary() const { + return "Executes a snippet of Python code"; +} + +/** + * Override standard group behaviour so that the algorithm is only + * called once for the whole group + */ +bool RunPythonScript::checkGroups() { return false; } + +/** + * Initialize the algorithm's properties. + */ +void RunPythonScript::init() { + declareProperty( + new WorkspaceProperty("InputWorkspace", "", Direction::Input, + PropertyMode::Optional), + "An input workspace that the python code will modify." + "The workspace will be in the python variable named 'input'."); + declareProperty("Code", "", "Python code (can be on multiple lines).", + boost::make_shared>()); + declareProperty( + new WorkspaceProperty("OutputWorkspace", "", Direction::Output, + PropertyMode::Optional), + "An output workspace to be produced by the python code." + "The workspace will be in the python variable named 'output'."); +} + +//---------------------------------------------------------------------------------------------- +/** Execute the algorithm. + */ +void RunPythonScript::exec() { + Workspace_sptr outputWS = executeScript(scriptCode()); + setProperty("OutputWorkspace", outputWS); +} + +/** + * Builds the code string from the user input. The user script is wrapped + * in a tiny PythonAlgorithm to 'fool' the Python framework into + * creating a child algorithm for each algorithm that is run. See + * PythonInterface/mantid/simpleapi.py:_create_algorithm_object + * This has to be the case to get the workspace locking correct. + * + * The code assumes that the scope in which it is executed has defined + * the variables input & output. + * + * @return A string containing the code ready to execute + */ +std::string RunPythonScript::scriptCode() const { + std::string userCode = getPropertyValue("Code"); + // Unify line endings + boost::regex eol("\\R"); // \R is Perl syntax for matching any EOL sequence + userCode = boost::regex_replace(userCode, eol, "\n"); // converts all to LF + + // Wrap and indent the user code (see method documentation) + std::istringstream is(userCode); + std::ostringstream os; + const char *indent = " "; + os << "import mantid\n" + << "from mantid.simpleapi import *\n" + << "class _DUMMY_ALG(mantid.api.PythonAlgorithm):\n" << indent + << "def PyExec(self, input=None,output=None):\n"; + std::string line; + while (getline(is, line)) { + os << indent << indent << line << "\n"; + } + os << indent << indent + << "return input,output\n"; // When executed the global scope needs to know + // about input,output so we return them + os << "input,output = _DUMMY_ALG().PyExec(input,output)"; + + if (g_log.is(Kernel::Logger::Priority::PRIO_DEBUG)) + g_log.debug() << "Full code to be executed:\n" << os.str() << "\n"; + return os.str(); +} + +/** + * Sets up the code context & executes it. + * A python dictionary of local attributes is setup to contain a reference to + * the input workspace + * & the output workspace. This together with the __main__ global dictionary + * defines the execution + * context + * @param script A string containing a read-to-execute script + * @return A pointer to the output workspace if one was generated. If one was + * not then this is an empty pointer + */ +boost::shared_ptr +RunPythonScript::executeScript(const std::string &script) const { + using namespace API; + using namespace boost::python; + + // Execution + Environment::GlobalInterpreterLock gil; + auto locals = doExecuteScript(script); + return extractOutputWorkspace(locals); +} + +/** + * Uses the __main__ object to define the globals context and together with the + * given locals + * dictionary executes the script. The GIL is acquired and released during this + * call + * @param script The script code + * @returns A dictionary defining the input & output variables + */ +boost::python::dict +RunPythonScript::doExecuteScript(const std::string &script) const { + // Retrieve the main module. + auto main = boost::python::import("__main__"); + // Retrieve the main module's namespace + boost::python::object globals(main.attr("__dict__")); + boost::python::dict locals = buildLocals(); + try { + boost::python::exec(script.c_str(), globals, locals); + } catch (boost::python::error_already_set &) { + Environment::throwRuntimeError(); + } + return locals; +} + +/** + * Creates a Python dictionary containing definitions of the 'input' & 'output' + * variable + * references that the script may use + * @return A Python dictionary that can be used as the locals argument for the + * script execution + */ +boost::python::dict RunPythonScript::buildLocals() const { + // Define the local variable names required by the script, in this case + // - input: Points to input workspace if one has been given + // - output: Will point to the output workspace if one has been given + using namespace boost::python; + + dict locals; + locals["input"] = object(); // default to None + locals["output"] = object(); + + API::Workspace_sptr inputWS = getProperty("InputWorkspace"); + if (inputWS) { + locals["input"] = + object(handle<>(to_python_value()(inputWS))); + } + std::string outputWSName = getPropertyValue("OutputWorkspace"); + if (!outputWSName.empty()) { + locals["output"] = + object(handle<>(to_python_value()(outputWSName))); + } + return locals; +} + +/** + * If an output workspace was created then extract it from the given dictionary + * @param locals A dictionary possibly containing an 'output' reference + * @return A pointer to the output workspace if created, otherwise an empty + * pointer + */ +boost::shared_ptr RunPythonScript::extractOutputWorkspace( + const boost::python::dict &locals) const { + using namespace API; + using namespace boost::python; + + // Might be None, string or a workspace object + auto pyoutput = locals.get("output"); + if (isNone(pyoutput)) + return Workspace_sptr(); + + auto ptrExtract = ExtractWorkspace(pyoutput); + if (ptrExtract.check()) { + return ptrExtract(); + } else { + extract extractString(pyoutput); + if (extractString.check()) { + // Will raise an error if the workspace does not exist as the user + // requested + // an output workspace + // but didn't create one. + return AnalysisDataService::Instance().retrieve(extractString()); + } else { + throw std::runtime_error( + "Invalid type assigned to 'output' variable. Must " + "be a string or a Workspace object"); } + } +} - } // namespace PythonInterface +} // namespace PythonInterface } // namespace Mantid diff --git a/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/AnalysisDataService.cpp b/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/AnalysisDataService.cpp index 90af321c1614..4a3773de97c0 100644 --- a/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/AnalysisDataService.cpp +++ b/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/AnalysisDataService.cpp @@ -1,21 +1,17 @@ +#include "MantidPythonInterface/api/ExtractWorkspace.h" #include "MantidPythonInterface/kernel/DataServiceExporter.h" #include "MantidPythonInterface/kernel/TrackingInstanceMethod.h" #include "MantidAPI/AnalysisDataService.h" #include "MantidAPI/Workspace.h" -#include -#include - using namespace Mantid::API; using namespace Mantid::Kernel; -using Mantid::PythonInterface::DataServiceExporter; -using Mantid::PythonInterface::TrackingInstanceMethod; +using namespace Mantid::PythonInterface; using namespace boost::python; namespace { -typedef boost::weak_ptr Workspace_wptr; /** * Add an item into the ADS, if it exists then an error is raised @@ -25,19 +21,12 @@ typedef boost::weak_ptr Workspace_wptr; */ void addItem(AnalysisDataServiceImpl &self, const std::string &name, const boost::python::object &item) { - extract weakExtract(item); - if(weakExtract.check()) { - self.add(name, weakExtract().lock()); - return; - } - - extract sharedExtract(item); - if(sharedExtract.check()) { - self.add(name, sharedExtract()); + ExtractWorkspace extractWS(item); + if(extractWS.check()) { + self.add(name, extractWS()); } else { throw std::runtime_error("Unable to add unknown object type to ADS"); } - } /** @@ -48,17 +37,11 @@ void addItem(AnalysisDataServiceImpl &self, const std::string &name, */ void addOrReplaceItem(AnalysisDataServiceImpl &self, const std::string &name, const boost::python::object &item) { - extract weakExtract(item); - if(weakExtract.check()) { - self.add(name, weakExtract().lock()); - return; - } - - extract sharedExtract(item); - if(sharedExtract.check()) { - self.add(name, sharedExtract()); + ExtractWorkspace extractWS(item); + if(extractWS.check()) { + self.addOrReplace(name, extractWS()); } else { - throw std::runtime_error("Unable to add unknown object type to ADS"); + throw std::runtime_error("Unable to add/replace unknown object type to ADS"); } } diff --git a/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/BinaryOperations.cpp b/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/BinaryOperations.cpp index ca1f13e79308..d804b454a980 100644 --- a/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/BinaryOperations.cpp +++ b/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/BinaryOperations.cpp @@ -1,25 +1,20 @@ #include "MantidPythonInterface/api/BinaryOperations.h" -#include "MantidPythonInterface/kernel/Policies/DowncastingPolicies.h" -#include "MantidAPI/WorkspaceOpOverloads.h" #include "MantidAPI/AlgorithmManager.h" #include "MantidAPI/AnalysisDataService.h" -#include "MantidAPI/WorkspaceGroup.h" +#include "MantidAPI/IMDHistoWorkspace.h" #include "MantidAPI/IMDWorkspace.h" #include "MantidAPI/MatrixWorkspace.h" -#include "MantidAPI/IMDHistoWorkspace.h" +#include "MantidAPI/WorkspaceGroup.h" +#include "MantidAPI/WorkspaceOpOverloads.h" #include -#include - -namespace Policies = Mantid::PythonInterface::Policies; // clang-format off void export_BinaryOperations() // clang-format on { using namespace Mantid::API; - using boost::python::return_value_policy; //Operator overloads dispatch through the above structure. The typedefs save some typing typedef IMDWorkspace_sptr(*binary_fn_md_md)(const IMDWorkspace_sptr, const IMDWorkspace_sptr, const std::string &,const std::string &,bool, bool); @@ -38,16 +33,15 @@ void export_BinaryOperations() using Mantid::PythonInterface::performBinaryOp; using Mantid::PythonInterface::performBinaryOpWithDouble; - def("performBinaryOp", (binary_fn_md_md)&performBinaryOp, return_value_policy()); - def("performBinaryOp", (binary_fn_md_gp)&performBinaryOp, return_value_policy()); - def("performBinaryOp", (binary_fn_gp_md)&performBinaryOp, return_value_policy()); - def("performBinaryOp", (binary_fn_gp_gp)&performBinaryOp, return_value_policy()); - def("performBinaryOp", (binary_fn_mh_mh)&performBinaryOp, return_value_policy()); - - def("performBinaryOp", (binary_fn_md_db)&performBinaryOpWithDouble, return_value_policy()); - def("performBinaryOp", (binary_fn_mh_db)&performBinaryOpWithDouble, return_value_policy()); - def("performBinaryOp", (binary_fn_gp_db)&performBinaryOpWithDouble, return_value_policy()); + def("performBinaryOp", (binary_fn_md_md)&performBinaryOp); + def("performBinaryOp", (binary_fn_md_gp)&performBinaryOp); + def("performBinaryOp", (binary_fn_gp_md)&performBinaryOp); + def("performBinaryOp", (binary_fn_gp_gp)&performBinaryOp); + def("performBinaryOp", (binary_fn_mh_mh)&performBinaryOp); + def("performBinaryOp", (binary_fn_md_db)&performBinaryOpWithDouble); + def("performBinaryOp", (binary_fn_mh_db)&performBinaryOpWithDouble); + def("performBinaryOp", (binary_fn_gp_db)&performBinaryOpWithDouble); } diff --git a/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/IEventWorkspace.cpp b/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/IEventWorkspace.cpp index af2bfc0bea8f..1eafc7d43408 100644 --- a/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/IEventWorkspace.cpp +++ b/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/IEventWorkspace.cpp @@ -1,12 +1,12 @@ #include "MantidAPI/IEventWorkspace.h" #include "MantidAPI/IEventList.h" -#include "MantidPythonInterface/kernel/Registry/DataItemInterface.h" +#include "MantidPythonInterface/kernel/Registry/RegisterWorkspacePtrToPython.h" #include #include using namespace Mantid::API; -using Mantid::PythonInterface::Registry::DataItemInterface; +using Mantid::PythonInterface::Registry::RegisterWorkspacePtrToPython; using namespace boost::python; /** @@ -28,9 +28,6 @@ void export_IEventWorkspace() .def("clearMRU", &IEventWorkspace::clearMRU, args("self"), "Clear the most-recently-used lists") ; - DataItemInterface() - // map IDs to this interface - .castFromID("EventWorkspace") - ; + RegisterWorkspacePtrToPython(); } diff --git a/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/IMDEventWorkspace.cpp b/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/IMDEventWorkspace.cpp index 8bc619371670..e960e1110e11 100644 --- a/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/IMDEventWorkspace.cpp +++ b/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/IMDEventWorkspace.cpp @@ -1,20 +1,13 @@ #include "MantidAPI/IMDEventWorkspace.h" -#include "MantidPythonInterface/kernel/Registry/DataItemInterface.h" +#include "MantidPythonInterface/kernel/Registry/RegisterWorkspacePtrToPython.h" #include #include using namespace Mantid::API; -using Mantid::PythonInterface::Registry::DataItemInterface; +using Mantid::PythonInterface::Registry::RegisterWorkspacePtrToPython; using namespace boost::python; -namespace -{ - // THIS NUMBER SHOULD MATCH MAX_MD_DIMENSIONS_NUM IN MDEvents/inc/MantidMDEvents/MDEventFactory - static const unsigned int MAX_MD_DIMS = 9; - static const unsigned int NUM_EVENT_TYPES = 2; -} - // clang-format off void export_IMDEventWorkspace() // clang-format on @@ -33,20 +26,6 @@ void export_IMDEventWorkspace() ; //----------------------------------------------------------------------------------------------- - DataItemInterface entry; - // The IDs for the MDEventWorkpaces are constructed from the event types and number of dimensions - const char *eventTypes[NUM_EVENT_TYPES]= { "MDEvent", "MDLeanEvent" }; - - std::ostringstream out; - for(unsigned int i = 1; i <= MAX_MD_DIMS; ++i) - { - for(unsigned int j = 0; j < NUM_EVENT_TYPES; ++j) - { - out.str(""); - out << "MDEventWorkspace<" << eventTypes[j] << "," << i << ">"; - entry.castFromID(out.str()); - } - } - + RegisterWorkspacePtrToPython(); } diff --git a/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/IMDHistoWorkspace.cpp b/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/IMDHistoWorkspace.cpp index 24ab708188fe..0c9595268fd2 100644 --- a/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/IMDHistoWorkspace.cpp +++ b/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/IMDHistoWorkspace.cpp @@ -1,6 +1,6 @@ #include "MantidAPI/IMDHistoWorkspace.h" #include "MantidPythonInterface/kernel/Converters/CArrayToNDArray.h" -#include "MantidPythonInterface/kernel/Registry/DataItemInterface.h" +#include "MantidPythonInterface/kernel/Registry/RegisterWorkspacePtrToPython.h" #include #include @@ -8,7 +8,7 @@ using namespace Mantid::API; -using Mantid::PythonInterface::Registry::DataItemInterface; +using Mantid::PythonInterface::Registry::RegisterWorkspacePtrToPython; namespace Converters = Mantid::PythonInterface::Converters; using namespace boost::python; @@ -191,8 +191,6 @@ void export_IMDHistoWorkspace() //------------------------------------------------------------------------------------------------- - DataItemInterface() - .castFromID("MDHistoWorkspace") - ; + RegisterWorkspacePtrToPython(); } diff --git a/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/IMDWorkspace.cpp b/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/IMDWorkspace.cpp index 8b0931b83894..884e5cda994c 100644 --- a/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/IMDWorkspace.cpp +++ b/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/IMDWorkspace.cpp @@ -1,12 +1,12 @@ #include "MantidAPI/IMDWorkspace.h" -#include "MantidPythonInterface/kernel/Registry/DataItemInterface.h" +#include "MantidPythonInterface/kernel/Registry/RegisterWorkspacePtrToPython.h" #include #include #include using namespace Mantid::API; -using Mantid::PythonInterface::Registry::DataItemInterface; +using Mantid::PythonInterface::Registry::RegisterWorkspacePtrToPython; using namespace boost::python; // clang-format off @@ -30,6 +30,6 @@ void export_IMDWorkspace() .def("getNEvents", &IMDWorkspace::getNEvents, args("self"), "Returns the total number of events, contributed to the workspace") .def("getSpecialCoordinateSystem", &IMDWorkspace::getSpecialCoordinateSystem, args("self"), "Returns the special coordinate system of the workspace"); - DataItemInterface(); + RegisterWorkspacePtrToPython(); } diff --git a/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/IPeaksWorkspace.cpp b/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/IPeaksWorkspace.cpp index 9ea3e721fbc8..51c434c57511 100644 --- a/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/IPeaksWorkspace.cpp +++ b/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/IPeaksWorkspace.cpp @@ -1,6 +1,6 @@ #include "MantidAPI/IPeaksWorkspace.h" #include "MantidAPI/IPeak.h" -#include "MantidPythonInterface/kernel/Registry/DataItemInterface.h" +#include "MantidPythonInterface/kernel/Registry/RegisterWorkspacePtrToPython.h" #include "MantidPythonInterface/kernel/Converters/PyObjectToV3D.h" #include #include @@ -8,7 +8,7 @@ #include using namespace Mantid::API; -using Mantid::PythonInterface::Registry::DataItemInterface; +using Mantid::PythonInterface::Registry::RegisterWorkspacePtrToPython; using namespace boost::python; namespace { @@ -54,8 +54,6 @@ void export_IPeaksWorkspace() //------------------------------------------------------------------------------------------------- - DataItemInterface() - .castFromID("PeaksWorkspace") - ; + RegisterWorkspacePtrToPython(); } diff --git a/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/ITableWorkspace.cpp b/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/ITableWorkspace.cpp index a614c7c8ae00..fe5b68600ee4 100644 --- a/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/ITableWorkspace.cpp +++ b/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/ITableWorkspace.cpp @@ -5,7 +5,7 @@ #include "MantidPythonInterface/kernel/Converters/NDArrayToVector.h" #include "MantidPythonInterface/kernel/Converters/PySequenceToVector.h" #include "MantidPythonInterface/kernel/Converters/CloneToNumpy.h" -#include "MantidPythonInterface/kernel/Registry/DataItemInterface.h" +#include "MantidPythonInterface/kernel/Registry/RegisterWorkspacePtrToPython.h" #include "MantidPythonInterface/kernel/Policies/VectorToNumpy.h" #include @@ -23,7 +23,7 @@ #include using namespace Mantid::API; -using Mantid::PythonInterface::Registry::DataItemInterface; +using Mantid::PythonInterface::Registry::RegisterWorkspacePtrToPython; using namespace boost::python; namespace @@ -393,8 +393,6 @@ void export_ITableWorkspace() //------------------------------------------------------------------------------------------------- - DataItemInterface() - .castFromID("TableWorkspace") - ; + RegisterWorkspacePtrToPython(); } diff --git a/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/MDGeometry.cpp b/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/MDGeometry.cpp index 815cf0cb2392..e27352ecbba7 100644 --- a/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/MDGeometry.cpp +++ b/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/MDGeometry.cpp @@ -1,5 +1,4 @@ #include "MantidAPI/MDGeometry.h" -#include "MantidPythonInterface/kernel/Policies/DowncastingPolicies.h" #include "MantidPythonInterface/kernel/Policies/RemoveConst.h" #include "MantidPythonInterface/kernel/Policies/VectorToNumpy.h" #include @@ -9,7 +8,6 @@ using Mantid::API::MDGeometry; using Mantid::Geometry::IMDDimension_const_sptr; -using Mantid::PythonInterface::Policies::ToSharedPtrWithDowncast; using Mantid::PythonInterface::Policies::RemoveConstSharedPtr; using Mantid::PythonInterface::Policies::VectorToNumpy; using namespace boost::python; @@ -86,8 +84,7 @@ void export_MDGeometry() .def("numOriginalWorkspaces", &MDGeometry::numOriginalWorkspaces, "Returns the number of source workspaces attached" ) - .def("getOriginalWorkspace", &MDGeometry::getOriginalWorkspace, (args("index")), - return_value_policy(), + .def("getOriginalWorkspace", &MDGeometry::getOriginalWorkspace, (args("index")), "Returns the source workspace attached at the given index") .def("getOrigin", (const Mantid::Kernel::VMD & (MDGeometry::*)() const)&MDGeometry::getOrigin, diff --git a/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/MatrixWorkspace.cpp b/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/MatrixWorkspace.cpp index 726a9e7db745..460e2424b947 100644 --- a/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/MatrixWorkspace.cpp +++ b/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/MatrixWorkspace.cpp @@ -5,13 +5,13 @@ #include "MantidPythonInterface/kernel/Converters/WrapWithNumpy.h" #include "MantidPythonInterface/kernel/Policies/RemoveConst.h" #include "MantidPythonInterface/kernel/Policies/VectorToNumpy.h" -#include "MantidPythonInterface/kernel/Registry/DataItemInterface.h" +#include "MantidPythonInterface/kernel/Registry/RegisterWorkspacePtrToPython.h" #include -#include #include #include #include +#include #include using namespace Mantid::API; @@ -241,5 +241,5 @@ void export_MatrixWorkspace() "CheckWorkspacesMatch algorithm") ; - DataItemInterface(); + RegisterWorkspacePtrToPython(); } diff --git a/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/Workspace.cpp b/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/Workspace.cpp index 83a024efd0a9..7050d9b0c187 100644 --- a/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/Workspace.cpp +++ b/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/Workspace.cpp @@ -1,6 +1,6 @@ #include "MantidAPI/Workspace.h" -#include "MantidPythonInterface/kernel/Registry/DataItemInterface.h" +#include "MantidPythonInterface/kernel/Registry/RegisterWorkspacePtrToPython.h" #include #include @@ -46,5 +46,5 @@ void export_Workspace() "Return read-only access to the workspace history"); // register pointers - DataItemInterface(); + RegisterWorkspacePtrToPython(); } diff --git a/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/WorkspaceGroup.cpp b/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/WorkspaceGroup.cpp index 67de0e52e7fc..e3931e62e87d 100644 --- a/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/WorkspaceGroup.cpp +++ b/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/WorkspaceGroup.cpp @@ -1,14 +1,12 @@ #include "MantidAPI/WorkspaceGroup.h" -#include "MantidPythonInterface/kernel/Policies/DowncastingPolicies.h" -#include "MantidPythonInterface/kernel/Registry/DataItemInterface.h" +#include "MantidPythonInterface/kernel/Registry/RegisterWorkspacePtrToPython.h" #include #include using namespace Mantid::API; -using Mantid::PythonInterface::Registry::DataItemInterface; +using Mantid::PythonInterface::Registry::RegisterWorkspacePtrToPython; using namespace boost::python; -namespace Policies = Mantid::PythonInterface::Policies; // clang-format off void export_WorkspaceGroup() @@ -21,20 +19,17 @@ void export_WorkspaceGroup() .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(), "Returns the item at the given index") + .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, - return_value_policy()) + .def("__getitem__", (Workspace_sptr (WorkspaceGroup::*)(const size_t) const)&WorkspaceGroup::getItem) ; //----------------------------------------------------------------------------------------------- - DataItemInterface() - .castFromID("WorkspaceGroup") - ; + RegisterWorkspacePtrToPython(); } diff --git a/Code/Mantid/Framework/PythonInterface/mantid/api/src/ExtractWorkspace.cpp b/Code/Mantid/Framework/PythonInterface/mantid/api/src/ExtractWorkspace.cpp new file mode 100644 index 000000000000..f43c2c825ed5 --- /dev/null +++ b/Code/Mantid/Framework/PythonInterface/mantid/api/src/ExtractWorkspace.cpp @@ -0,0 +1,54 @@ +//----------------------------------------------------------------------------- +// Includes +//----------------------------------------------------------------------------- +#include "MantidPythonInterface/api/ExtractWorkspace.h" + +#include +#include + +namespace Mantid { +namespace PythonInterface { + +using namespace API; + +using boost::python::extract; + +//----------------------------------------------------------------------------- +// Public methods +//----------------------------------------------------------------------------- +/** + * @param pyvalue Python object from which to extract + */ +ExtractWorkspace::ExtractWorkspace(const boost::python::api::object &pyvalue) + : m_value() { + // Test for a weak pointer first + typedef boost::weak_ptr Workspace_wptr; + extract extractWeak(pyvalue); + if (extractWeak.check()) { + m_value = extractWeak().lock(); + } + extract extractShared(pyvalue); + if (extractShared.check()) { + m_value = extractShared(); + } +} + +/** + * Check whether the extract can pull out the workspace type + * @return True if it can be converted, false otherwise + */ +bool ExtractWorkspace::check() const { return !m_value; } + +/** + * @return The extracted shared_ptr or throws std::invalid_argument + */ +const API::Workspace_sptr ExtractWorkspace::operator()() const { + if (check()) { + return m_value; + } else { + throw std::invalid_argument( + "Unable to extract boost::shared_ptr from Python object"); + } +} +} +} diff --git a/Code/Mantid/Framework/PythonInterface/mantid/dataobjects/src/Exports/TableWorkspace.cpp b/Code/Mantid/Framework/PythonInterface/mantid/dataobjects/src/Exports/TableWorkspace.cpp index bfda43f40655..a113a7cefcec 100644 --- a/Code/Mantid/Framework/PythonInterface/mantid/dataobjects/src/Exports/TableWorkspace.cpp +++ b/Code/Mantid/Framework/PythonInterface/mantid/dataobjects/src/Exports/TableWorkspace.cpp @@ -15,5 +15,5 @@ class_, ; // register pointers - DataItemInterface(); + RegisterWorkspacePtrToPython(); } diff --git a/Code/Mantid/Framework/PythonInterface/mantid/dataobjects/src/Exports/Workspace2D.cpp b/Code/Mantid/Framework/PythonInterface/mantid/dataobjects/src/Exports/Workspace2D.cpp index ad2410f06c87..1172626af320 100644 --- a/Code/Mantid/Framework/PythonInterface/mantid/dataobjects/src/Exports/Workspace2D.cpp +++ b/Code/Mantid/Framework/PythonInterface/mantid/dataobjects/src/Exports/Workspace2D.cpp @@ -1,5 +1,5 @@ #include "MantidDataObjects/Workspace2D.h" -#include "MantidPythonInterface/kernel/Registry/DataItemInterface.h" +#include "MantidPythonInterface/kernel/Registry/RegisterWorkspacePtrToPython.h" #include #include @@ -16,5 +16,5 @@ void export_Workspace2D() ; // register pointers - DataItemInterface(); + RegisterWorkspacePtrToPython(); } diff --git a/Code/Mantid/Framework/PythonInterface/mantid/kernel/CMakeLists.txt b/Code/Mantid/Framework/PythonInterface/mantid/kernel/CMakeLists.txt index 853745062795..6a19edb68323 100644 --- a/Code/Mantid/Framework/PythonInterface/mantid/kernel/CMakeLists.txt +++ b/Code/Mantid/Framework/PythonInterface/mantid/kernel/CMakeLists.txt @@ -63,7 +63,6 @@ set ( SRC_FILES src/Registry/PropertyWithValueFactory.cpp src/Registry/SequenceTypeHandler.cpp src/Registry/TypeRegistry.cpp - src/Registry/DowncastRegistry.cpp src/Environment/ErrorHandling.cpp src/Environment/Threading.cpp src/Environment/WrapperHelpers.cpp @@ -93,7 +92,7 @@ set ( INC_FILES ${HEADER_DIR}/kernel/Registry/SequenceTypeHandler.h ${HEADER_DIR}/kernel/Registry/TypedPropertyValueHandler.h ${HEADER_DIR}/kernel/Registry/TypeRegistry.h - ${HEADER_DIR}/kernel/Registry/DowncastRegistry.h + ${HEADER_DIR}/kernel/Registry/RegisterWorkspacePtrToPython.h ${HEADER_DIR}/kernel/DataServiceExporter.h ${HEADER_DIR}/kernel/IsNone.h ${HEADER_DIR}/kernel/PropertyWithValueExporter.h diff --git a/Code/Mantid/Framework/PythonInterface/mantid/kernel/src/Exports/PropertyWithValue.cpp b/Code/Mantid/Framework/PythonInterface/mantid/kernel/src/Exports/PropertyWithValue.cpp index a7eb9bd5f20f..2bb53ccf8a15 100644 --- a/Code/Mantid/Framework/PythonInterface/mantid/kernel/src/Exports/PropertyWithValue.cpp +++ b/Code/Mantid/Framework/PythonInterface/mantid/kernel/src/Exports/PropertyWithValue.cpp @@ -1,40 +1,50 @@ #include "MantidPythonInterface/kernel/PropertyWithValueExporter.h" +#include + using Mantid::PythonInterface::PropertyWithValueExporter; // clang-format off void export_BasicPropertyWithValueTypes() // clang-format on { - // cut down copy-and-paste code -#define EXPORT_PROP(CType, ExportName) \ - PropertyWithValueExporter::define(ExportName); - - //ints & vectors - EXPORT_PROP(int, "IntPropertyWithValue"); - EXPORT_PROP(std::vector, "VectorIntPropertyWithValue"); - EXPORT_PROP(unsigned int, "UIntPropertyWithValue"); - EXPORT_PROP(std::vector, "VectorUIntPropertyWithValue"); + // ints & vectors + PropertyWithValueExporter::define("IntPropertyWithValue"); + PropertyWithValueExporter>::define( + "VectorIntPropertyWithValue"); + PropertyWithValueExporter::define("UIntPropertyWithValue"); + PropertyWithValueExporter>::define( + "VectorUIntPropertyWithValue"); + // longs & vectors - EXPORT_PROP(long, "LongPropertyWithValue"); - EXPORT_PROP(std::vector, "VectorLongPropertyWithValue"); - EXPORT_PROP(unsigned long, "ULongPropertyWithValue"); - EXPORT_PROP(std::vector, "VectorULongPropertyWithValue"); + PropertyWithValueExporter::define("LongPropertyWithValue"); + PropertyWithValueExporter>::define( + "VectorLongPropertyWithValue"); + PropertyWithValueExporter::define("ULongPropertyWithValue"); + PropertyWithValueExporter>::define( + "VectorULongPropertyWithValue"); + // long long long longs & vectors - EXPORT_PROP(long long, "LongLongPropertyWithValue"); - EXPORT_PROP(std::vector, "VectorLongLongPropertyWithValue"); - EXPORT_PROP(unsigned long long, "ULongLongPropertyWithValue"); - EXPORT_PROP(std::vector, "VectorULongLongPropertyWithValue"); + PropertyWithValueExporter::define("LongLongPropertyWithValue"); + PropertyWithValueExporter>::define( + "VectorLongLongPropertyWithValue"); + PropertyWithValueExporter::define( + "ULongLongPropertyWithValue"); + PropertyWithValueExporter>::define( + "VectorULongLongPropertyWithValue"); + // double - EXPORT_PROP(double, "FloatPropertyWithValue"); - EXPORT_PROP(std::vector, "VectorFloatPropertyWithValue"); + PropertyWithValueExporter::define("FloatPropertyWithValue"); + PropertyWithValueExporter>::define( + "VectorFloatPropertyWithValue"); + // boolean - EXPORT_PROP(bool, "BoolPropertyWithValue"); - EXPORT_PROP(std::vector, "VectorBoolPropertyWithValue"); + PropertyWithValueExporter::define("BoolPropertyWithValue"); + PropertyWithValueExporter>::define( + "VectorBoolPropertyWithValue"); + // std::string - EXPORT_PROP(std::string, "StringPropertyWithValue"); - EXPORT_PROP(std::vector, "VectorStringPropertyWithValue"); - - -#undef EXPORT_PROP + PropertyWithValueExporter::define("StringPropertyWithValue"); + PropertyWithValueExporter>::define( + "VectorStringPropertyWithValue"); } diff --git a/Code/Mantid/Framework/PythonInterface/mantid/kernel/src/Registry/DowncastRegistry.cpp b/Code/Mantid/Framework/PythonInterface/mantid/kernel/src/Registry/DowncastRegistry.cpp deleted file mode 100644 index 07b01ebe6a00..000000000000 --- a/Code/Mantid/Framework/PythonInterface/mantid/kernel/src/Registry/DowncastRegistry.cpp +++ /dev/null @@ -1,85 +0,0 @@ -//----------------------------------------------------------------------------- -// Includes -//----------------------------------------------------------------------------- -#include "MantidPythonInterface/kernel/Registry/DowncastRegistry.h" - -#include -#include -#include -#include - -namespace Mantid -{ - namespace PythonInterface - { - namespace Registry - { - namespace // - { - /// Typedef the map of type_info -> Downcaster objects - typedef boost::unordered_map> RegistryType; - //typedef std::map> RegistryType; - - /** - * Returns a reference to the static type map. Creates on first call to the function - * @return A reference to the type map - */ - RegistryType & downcastRegistry() - { - static RegistryType registry; - return registry; - } - } // end - - //----------------------------------------------------------------------- - // Public methods - //----------------------------------------------------------------------- - /** - * Throws std::invalid_argument if the item does not exist - * @param id A string ID from a concrete DataItem type - * @return The object responsible for casting and creating a Python object - * from it - */ - const DowncastDataItem & DowncastRegistry::retrieve(const std::string & id) - { - auto & registry = downcastRegistry(); - auto entry = registry.find(id); - if(entry != registry.cend()) - { - return *(entry->second); - } - else - { - throw std::invalid_argument("DowncastRegistry::retrieve - Unable to find registered " - "object with id=" + id); - } - } - - - //----------------------------------------------------------------------- - // Private methods - //----------------------------------------------------------------------- - /** - * Subscribe a caster object with a given ID - * @param id A string ID that will map to the object - * @param caster A pointer to a DowncastDataItem object. Ownership of the - * object is transferred here - */ - void DowncastRegistry::subscribe(const std::string & id, const DowncastDataItem * caster) - { - auto & registry = downcastRegistry(); - if(registry.find(id) == registry.cend()) - { - typedef boost::shared_ptr DowncastDataItemPtr; - registry.insert(std::make_pair(id, DowncastDataItemPtr(caster))); - } - else - { - throw std::invalid_argument("DowncastRegistry::subscribe - object with ID=" + id + \ - " has already been registered"); - } - } - - } - } -}