Commit a2feb339 authored by Jose Borreguero's avatar Jose Borreguero
Browse files

deprecator_alias and alias deprecated method


Signed-off-by: default avatarJose Borreguero <borreguero@gmail.com>
parent e328e392
...@@ -168,12 +168,14 @@ public: ...@@ -168,12 +168,14 @@ public:
/// Function to return all of the seeAlso (these are not validated) algorithms /// Function to return all of the seeAlso (these are not validated) algorithms
/// related to this algorithm.A default implementation is provided. /// related to this algorithm.A default implementation is provided.
const std::vector<std::string> seeAlso() const override { return {}; }; const std::vector<std::string> seeAlso() const override { return {}; };
/// Function to return any aliases to the algorithm; A default implementation /// function to return any aliases to the algorithm; A default implementation is provided
/// is provided
const std::string alias() const override { return ""; } const std::string alias() const override { return ""; }
/// Flag to indicate if the algorithm is called by its alias. /// Flag to indicate if the algorithm is called by its alias.
bool calledByAlias = false; bool calledByAlias = false;
/// Expiration date (in ISO8601 format) for the algorithm aliases; default implementation for no expiration date
const std::string aliasDeprecated() const override { return ""; }
/// function to return URL for algorithm documentation; A default /// function to return URL for algorithm documentation; A default
/// implementation is provided. /// implementation is provided.
/// Override if the algorithm is not part of the Mantid distribution. /// Override if the algorithm is not part of the Mantid distribution.
......
...@@ -68,6 +68,9 @@ public: ...@@ -68,6 +68,9 @@ public:
/// Function to return all of the seeAlso algorithms related to this algorithm /// Function to return all of the seeAlso algorithms related to this algorithm
virtual const std::vector<std::string> seeAlso() const = 0; virtual const std::vector<std::string> seeAlso() const = 0;
/// Expiration date (in ISO8601 format) for the algorithm aliases. Empty if no expiration date
virtual const std::string aliasDeprecated() const = 0;
/// function to return any aliases of the algorithm. /// function to return any aliases of the algorithm.
virtual const std::string alias() const = 0; virtual const std::string alias() const = 0;
......
...@@ -183,6 +183,12 @@ loading.multifilelimit = ...@@ -183,6 +183,12 @@ loading.multifilelimit =
# Hide algorithms that use a Property Manager by default. # Hide algorithms that use a Property Manager by default.
algorithms.categories.hidden=Workflow\\Inelastic\\UsesPropertyManager;Workflow\\SANS\\UsesPropertyManager;DataHandling\\LiveData\\Support;Deprecated;Utility\\Development;Remote algorithms.categories.hidden=Workflow\\Inelastic\\UsesPropertyManager;Workflow\\SANS\\UsesPropertyManager;DataHandling\\LiveData\\Support;Deprecated;Utility\\Development;Remote
# Response upon invoking an algorithm with its alias, when the alias is deprecated.
# Allowed values are:
# "Warn": log a warning indicating the alias is deprecated, along with the name to be used
# "Raise": raise a RuntimeError if the deprecated deadline has been met
algorithms.alias.deprecated = Warn
# All interface categories are shown by default. # All interface categories are shown by default.
interfaces.categories.hidden = interfaces.categories.hidden =
......
...@@ -54,8 +54,13 @@ public: ...@@ -54,8 +54,13 @@ public:
/// Returns seeAlso related algorithms. /// Returns seeAlso related algorithms.
const std::vector<std::string> seeAlso() const override; const std::vector<std::string> seeAlso() const override;
/// Allow the method returning the algorithm aliases to be overridden /// Allow the method returning the algorithm aliases to be overridden
const std::string alias() const override; const std::string alias() const override;
/// Returns optional documentation URL of the algorithm /// Returns optional documentation URL of the algorithm
/// Allow the method returning the expiration date (in ISO8601 format) for the algorithm aliases to be overridden
const std::string aliasDeprecated() const override;
const std::string helpURL() const override; const std::string helpURL() const override;
/// Allow the isRunning method to be overridden /// Allow the isRunning method to be overridden
bool isRunning() const override; bool isRunning() const override;
......
...@@ -365,6 +365,9 @@ void export_ialgorithm() { ...@@ -365,6 +365,9 @@ void export_ialgorithm() {
class_<IAlgorithm, bases<IPropertyManager>, boost::noncopyable>("IAlgorithm", "Interface for all algorithms", no_init) class_<IAlgorithm, bases<IPropertyManager>, boost::noncopyable>("IAlgorithm", "Interface for all algorithms", no_init)
.def("name", &IAlgorithm::name, arg("self"), "Returns the name of the algorithm") .def("name", &IAlgorithm::name, arg("self"), "Returns the name of the algorithm")
.def("alias", &IAlgorithm::alias, arg("self"), "Return the aliases for the algorithm") .def("alias", &IAlgorithm::alias, arg("self"), "Return the aliases for the algorithm")
.def("aliasDeprecated", &IAlgorithm::aliasDeprecated, arg("self"),
"Deprecation date (in ISO8601 format) for the algorithm aliases. "
"Returns empty string if no deprecation date")
.def("version", &IAlgorithm::version, arg("self"), "Returns the version number of the algorithm") .def("version", &IAlgorithm::version, arg("self"), "Returns the version number of the algorithm")
.def("cancel", &IAlgorithm::cancel, arg("self"), "Request that the algorithm stop running") .def("cancel", &IAlgorithm::cancel, arg("self"), "Request that the algorithm stop running")
.def("category", &IAlgorithm::category, arg("self"), "Returns the category containing the algorithm") .def("category", &IAlgorithm::category, arg("self"), "Returns the category containing the algorithm")
......
...@@ -118,6 +118,18 @@ template <typename BaseAlgorithm> const std::string AlgorithmAdapter<BaseAlgorit ...@@ -118,6 +118,18 @@ template <typename BaseAlgorithm> const std::string AlgorithmAdapter<BaseAlgorit
} }
} }
/**
* Returns the expiration date (in ISO8601 format) of algorithm aliases. If not overridden, returns the
* base algorithm implementation
*/
template <typename BaseAlgorithm> const std::string AlgorithmAdapter<BaseAlgorithm>::aliasDeprecated() const {
try {
return callMethod<std::string>(getSelf(), "aliasDeprecated");
} catch (UndefinedAttributeError &) {
return BaseAlgorithm::aliasDeprecated();
}
}
/** /**
* Returns the summary of the algorithm. If not overridden * Returns the summary of the algorithm. If not overridden
* it returns defaultSummary * it returns defaultSummary
......
...@@ -29,7 +29,8 @@ Importing this module starts the FrameworkManager instance. ...@@ -29,7 +29,8 @@ Importing this module starts the FrameworkManager instance.
# std libs # std libs
from collections import OrderedDict, namedtuple from collections import OrderedDict, namedtuple
from contextlib import contextmanager from contextlib import contextmanager
import inspect import datetime
from dateutil.parser import parse as parse_date
import os import os
import sys import sys
...@@ -37,6 +38,7 @@ import mantid ...@@ -37,6 +38,7 @@ import mantid
# This is a simple API so give access to the aliases by default as well # This is a simple API so give access to the aliases by default as well
from mantid import __gui__, api as _api, kernel as _kernel, apiVersion from mantid import __gui__, api as _api, kernel as _kernel, apiVersion
from mantid.kernel import plugins as _plugin_helper from mantid.kernel import plugins as _plugin_helper
from mantid.kernel import ConfigService, logger
from mantid.kernel.funcinspect import customise_func as _customise_func, lhs_info as _lhs_info, \ from mantid.kernel.funcinspect import customise_func as _customise_func, lhs_info as _lhs_info, \
replace_signature as _replace_signature, LazyFunctionSignature replace_signature as _replace_signature, LazyFunctionSignature
...@@ -963,7 +965,7 @@ def set_properties(alg_object, *args, **kwargs): ...@@ -963,7 +965,7 @@ def set_properties(alg_object, *args, **kwargs):
do_set_property(key, value) do_set_property(key, value)
def _create_algorithm_function(name, version, algm_object): def _create_algorithm_function(name, version, algm_object): # noqa: C901
""" """
Create a function that will set up and execute an algorithm. Create a function that will set up and execute an algorithm.
The help that will be displayed is that of the most recent version. The help that will be displayed is that of the most recent version.
...@@ -972,12 +974,34 @@ def _create_algorithm_function(name, version, algm_object): ...@@ -972,12 +974,34 @@ def _create_algorithm_function(name, version, algm_object):
:param algm_object: the created algorithm object. :param algm_object: the created algorithm object.
""" """
def algorithm_wrapper(): def algorithm_wrapper(alias=None):
""" r"""
Creates a wrapper object around the algorithm functions. @brief Creates a wrapper object around the algorithm functions.
@param str alias: Non-empty when the algorithm is to be invoked with this alias instead of its name.
Default `None` indicates an alias is not being used.
""" """
class Wrapper: class Wrapper:
__slots__ = ["__name__", "__signature__"]
__slots__ = ["__name__", "__signature__", "_alias"]
@staticmethod
def _init_alias(algm_alias):
r"""
@brief Encapsulate alias features on a namedtuple
@param str algm_alias
"""
deprecated = algm_object.aliasDeprecated() # non-empty string when alias set to be deprecated
if deprecated:
try:
parse_date(deprecated)
except ValueError:
deprecated = ''
logger.error(f'Alias deprecation date {deprecated} must be in ISO8601 format')
AlgorithmAlias = namedtuple('AlgorithmAlias', 'name, deprecated')
return AlgorithmAlias(algm_alias, deprecated)
def __init__(self, algm_alias=None):
self._alias = self._init_alias(algm_alias) if algm_alias else None
def __getattribute__(self, item): def __getattribute__(self, item):
obj = object.__getattribute__(self, item) obj = object.__getattribute__(self, item)
...@@ -999,6 +1023,14 @@ def _create_algorithm_function(name, version, algm_object): ...@@ -999,6 +1023,14 @@ def _create_algorithm_function(name, version, algm_object):
If both startProgress and endProgress are supplied they will If both startProgress and endProgress are supplied they will
be used. be used.
""" """
# Check at runtime whether to throw upon alias deprecation.
if self._alias and self._alias.deprecated:
deprecated = parse_date(self._alias.deprecated) < datetime.datetime.today()
deprecated_action = ConfigService.Instance().get('algorithms.alias.deprecated', 'Warn').lower()
if deprecated and deprecated_action == 'raise':
raise RuntimeError(f'Use of algorithm alias {self._alias.name} not allowed. Use {name} instead')
_version = version _version = version
if "Version" in kwargs: if "Version" in kwargs:
_version = kwargs["Version"] _version = kwargs["Version"]
...@@ -1047,21 +1079,23 @@ def _create_algorithm_function(name, version, algm_object): ...@@ -1047,21 +1079,23 @@ def _create_algorithm_function(name, version, algm_object):
msg = '{}-v{}: {}'.format(algm.name(), algm.version(), str(e)) msg = '{}-v{}: {}'.format(algm.name(), algm.version(), str(e))
raise RuntimeError(msg) from e raise RuntimeError(msg) from e
if self._alias and self._alias.deprecated:
logger.error(f'Algorithm alias {self._alias.name} is deprecated. Use {name} instead')
return _gather_returns(name, lhs, algm) return _gather_returns(name, lhs, algm)
# Set the signature of the callable to be one that is only generated on request. # Set the signature of the callable to be one that is only generated on request.
Wrapper.__call__.__signature__ = LazyFunctionSignature(alg_name=name) Wrapper.__call__.__signature__ = LazyFunctionSignature(alg_name=name)
return Wrapper()
# enddef wrapper = Wrapper(algm_alias=alias)
# Insert definition in to global dict wrapper.__name__ = name
algm_wrapper = algorithm_wrapper() return wrapper
algm_wrapper.__name__ = name
globals()[name] = algm_wrapper
# Register aliases - split on whitespace # Register aliases - split on whitespace
for alias in algm_object.alias().strip().split(): for alias in algm_object.alias().strip().split():
globals()[alias] = algm_wrapper globals()[alias] = algorithm_wrapper(alias=alias)
# endfor
algm_wrapper = algorithm_wrapper()
globals()[name] = algorithm_wrapper() # Insert definition in to global dict
return algm_wrapper return algm_wrapper
......
# Mantid Repository : https://github.com/mantidproject/mantid
#
# Copyright &copy; 2020 ISIS Rutherford Appleton Laboratory UKRI,
# NScD Oak Ridge National Laboratory, European Spallation Source,
# Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
# SPDX - License - Identifier: GPL - 3.0 +
# package imports
from mantid.kernel import ConfigService, logger
# third-party imports
from dateutil.parser import parse as parse_date
# standard imports
import functools
def deprecated_alias(deprecation_date): # decorator factory
r"""
:brief: Class decorator marking the algorithm's alias as deprecated
:details: It's assumed that the algorithm implements the alias method
:param str deprecation_date: date of deprecation for the alias, in ISO8601 format
"""
try:
parse_date(deprecation_date)
except ValueError:
logger.error(f'Alias deprecation date {deprecation_date} must be in ISO8601 format')
def decorator_instance(cls):
cls_aliasDeprecated = cls.aliasDeprecated
@functools.wraps(cls_aliasDeprecated)
def new_aliasDeprecated(self):
return deprecation_date
cls.aliasDeprecated = new_aliasDeprecated
return cls
return decorator_instance
def deprecated_algorithm(new_name, deprecation_date): # decorator factory
r"""
:brief: Class decorator marking the algorithm as deprecated
:param str new_name: Algorithm's name that should be used in place of this algorithm
:param str deprecation_date: date of deprecation for this algorithm, in ISO8601 format
"""
try:
parse_date(deprecation_date)
except ValueError:
logger.error(f'Algorithm deprecation date {deprecation_date} must be in ISO8601 format')
def decorator_instance(cls):
depr_msg = f'Algorithm "{cls.__name__}" is deprecated since {deprecation_date}. Use "{new_name}" instead'
raise_msg = f'Configuration "algorithms.deprecated" set to raise upon use of deprecated algorithms'
cls_init = cls.__init__
@functools.wraps(cls_init)
def new_init(self, *args, **kwargs):
r"""decorate __init__ to possibly raise"""
if ConfigService.Instance()['algorithms.deprecated'] == 'Raise':
logger.error(depr_msg)
raise RuntimeError(raise_msg)
cls_init(self, *args, **kwargs)
cls.__init__ = new_init
cls_PyExec = cls.PyExec
@functools.wraps(cls_PyExec)
def new_PyExec(self):
r"""decorate PyExec to throw an error message"""
cls_PyExec(self)
logger.error(depr_msg) # show error after execution
cls.PyExec = new_PyExec
return cls
return decorator_instance
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
# Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS # Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
# SPDX - License - Identifier: GPL - 3.0 + # SPDX - License - Identifier: GPL - 3.0 +
# 3rd party # package imports
from mantid import config, FileFinder from mantid import config, FileFinder
# standard # standard
......
...@@ -36,6 +36,11 @@ General properties ...@@ -36,6 +36,11 @@ General properties
| ``algorithms.categories.hidden`` | A comma separated list of any categories of | ``Muons,Testing`` | | ``algorithms.categories.hidden`` | A comma separated list of any categories of | ``Muons,Testing`` |
| | algorithms that should be hidden in Mantid. | | | | algorithms that should be hidden in Mantid. | |
+----------------------------------+--------------------------------------------------+------------------------+ +----------------------------------+--------------------------------------------------+------------------------+
| ``algorithms.alias.expired`` | Action upon invoking the algorithm via one of | ``Warn`` or ``Raise`` |
| | its alias when the grace period for use of the | |
| | aliases has already expired. | |
| | ``Raise`` will cause a ``RuntimError``. | |
+----------------------------------+--------------------------------------------------+------------------------+
| ``curvefitting.guiExclude`` | A semicolon separated list of function names | ``ExpDecay;Gaussian;`` | | ``curvefitting.guiExclude`` | A semicolon separated list of function names | ``ExpDecay;Gaussian;`` |
| | that should be hidden in Mantid. | | | | that should be hidden in Mantid. | |
+----------------------------------+--------------------------------------------------+------------------------+ +----------------------------------+--------------------------------------------------+------------------------+
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment