diff --git a/parcels/tools/_helpers.py b/parcels/tools/_helpers.py new file mode 100644 index 000000000..ffe583157 --- /dev/null +++ b/parcels/tools/_helpers.py @@ -0,0 +1,53 @@ +"""Internal helpers for Parcels.""" + +import functools +import warnings +from typing import Callable + +PACKAGE = "Parcels" + + +def deprecated(msg: str = "") -> Callable: + """Decorator marking a function as being deprecated + + Parameters + ---------- + msg : str, optional + Custom message to append to the deprecation warning. + + Examples + -------- + ``` + @deprecated("Please use `another_function` instead") + def some_old_function(x, y): + return x + y + + @deprecated() + def some_other_old_function(x, y): + return x + y + ``` + """ + if msg: + msg = " " + msg + + def decorator(func): + @functools.wraps(func) + def wrapper(*args, **kwargs): + msg_formatted = ( + f"`{func.__qualname__}` is deprecated and will be removed in a future release of {PACKAGE}.{msg}" + ) + + warnings.warn(msg_formatted, category=DeprecationWarning, stacklevel=2) + return func(*args, **kwargs) + + return wrapper + + return decorator + + +def deprecated_made_private(func: Callable) -> Callable: + return deprecated( + "It has moved to the internal API as it is not expected to be directly used by " + "the end-user. If you feel that you use this code directly in your scripts, please " + "comment on our tracking issue at <>." # TODO: Add tracking issue + )(func) diff --git a/tests/tools/test_helpers.py b/tests/tools/test_helpers.py new file mode 100644 index 000000000..0089fed36 --- /dev/null +++ b/tests/tools/test_helpers.py @@ -0,0 +1,53 @@ +import pytest + +from parcels.tools._helpers import deprecated, deprecated_made_private + + +def test_deprecated(): + class SomeClass: + @deprecated() + def some_method(self, x, y): + return x + y + + @staticmethod + @deprecated() + def some_static_method(x, y): + return x + y + + @property + @deprecated() + def some_property(self): + return 2 + + @deprecated() + def some_function(x, y): + return x + y + + with pytest.warns(DeprecationWarning) as record: + SomeClass().some_method(1, 2) + assert "SomeClass.some_method" in record[0].message.args[0] + + with pytest.warns(DeprecationWarning) as record: + SomeClass.some_static_method(1, 2) + assert "SomeClass.some_static_method" in record[0].message.args[0] + + with pytest.warns(DeprecationWarning) as record: + _ = SomeClass().some_property + assert "SomeClass.some_property" in record[0].message.args[0] + + with pytest.warns(DeprecationWarning) as record: + some_function(1, 2) + assert "some_function" in record[0].message.args[0] + + with pytest.warns(DeprecationWarning) as record: + some_function(1, 2) + assert "some_function" in record[0].message.args[0] + + +def test_deprecated_made_private(): + @deprecated_made_private + def some_function(x, y): + return x + y + + with pytest.warns(DeprecationWarning): + some_function(1, 2)