From 56066ec185e6343e1186c2afc88fc0bdaa5cf41b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Ma=C5=9Blanka?= <pmaslanka@smok.co> Date: Fri, 15 Oct 2021 16:34:10 +0200 Subject: [PATCH] 2.18.4 --- CHANGELOG.md | 2 ++ docs/coding/decorators.rst | 4 +++ satella/__init__.py | 2 +- satella/coding/decorators/__init__.py | 5 ++-- satella/coding/decorators/arguments.py | 37 ++++++++++++++++++++++++ tests/test_coding/test_decorators.py | 39 +++++++++++++++++++++++++- 6 files changed, 85 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index edc031fa..e0740ef9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,5 @@ # v2.18.4 * added `map_through` to `unpack_dict` +* added `execute_if_attribute_none` +* added `execute_if_attribute_not_none` diff --git a/docs/coding/decorators.rst b/docs/coding/decorators.rst index e743c138..52020b49 100644 --- a/docs/coding/decorators.rst +++ b/docs/coding/decorators.rst @@ -1,6 +1,10 @@ Decorators ========== +.. autofunction:: satella.coding.decorators.execute_if_attribute_none + +.. autofunction:: satella.coding.decorators.execute_if_attribute_not_none + .. autofunction:: satella.coding.decorators.transform_result .. autofunction:: satella.coding.decorators.transform_arguments diff --git a/satella/__init__.py b/satella/__init__.py index f9ba0d3c..2d29c1ea 100644 --- a/satella/__init__.py +++ b/satella/__init__.py @@ -1 +1 @@ -__version__ = '2.18.4a2' +__version__ = '2.18.4' diff --git a/satella/coding/decorators/__init__.py b/satella/coding/decorators/__init__.py index 5c5784e1..3fc063c0 100644 --- a/satella/coding/decorators/__init__.py +++ b/satella/coding/decorators/__init__.py @@ -1,6 +1,6 @@ from .arguments import auto_adapt_to_methods, attach_arguments, for_argument, \ execute_before, copy_arguments, replace_argument_if, transform_result, \ - transform_arguments + transform_arguments, execute_if_attribute_none, execute_if_attribute_not_none from .decorators import wraps, chain_functions, has_keys, short_none, memoize, return_as_list, \ default_return, cache_memoize, call_method_on_exception from .flow_control import loop_while, queue_get @@ -12,4 +12,5 @@ __all__ = ['retry', 'transform_result', 'transform_arguments', 'chain_functions', 'has_keys', 'short_none', 'auto_adapt_to_methods', 'attach_arguments', 'for_argument', 'loop_while', 'memoize', 'copy_arguments', 'replace_argument_if', 'return_as_list', - 'default_return', 'cache_memoize', 'call_method_on_exception'] + 'default_return', 'cache_memoize', 'call_method_on_exception', + 'execute_if_attribute_none', 'execute_if_attribute_not_none'] diff --git a/satella/coding/decorators/arguments.py b/satella/coding/decorators/arguments.py index e415ed5b..e7fa1308 100644 --- a/satella/coding/decorators/arguments.py +++ b/satella/coding/decorators/arguments.py @@ -373,3 +373,40 @@ def for_argument(*t_ops: ForArgumentArg, **t_kwops: ForArgumentArg): return inner return outer + + +def execute_if_attribute_none(attribute: str): + """ + Decorator for instancemethods. + + This will execute the function only if provided attribute is None. + Otherwise it will return a None + + :param attribute: name of the attribute to check + """ + def outer(fun): + @wraps(fun) + def inner(self, *args, **kwargs): + if getattr(self, attribute) is None: + return fun(self, *args, **kwargs) + return inner + return outer + + +def execute_if_attribute_not_none(attribute: str): + """ + Decorator for instancemethods. + + This will execute the function only if provided attribute is not None. + Otherwise it will return a None + + :param attribute: name of the attribute to check + """ + def outer(fun): + @wraps(fun) + def inner(self, *args, **kwargs): + if getattr(self, attribute) is not None: + return fun(self, *args, **kwargs) + return inner + return outer + diff --git a/tests/test_coding/test_decorators.py b/tests/test_coding/test_decorators.py index 0826265a..425f384f 100644 --- a/tests/test_coding/test_decorators.py +++ b/tests/test_coding/test_decorators.py @@ -9,7 +9,8 @@ from satella.coding import wraps, chain_functions, postcondition, \ from satella.coding.decorators import auto_adapt_to_methods, attach_arguments, \ execute_before, loop_while, memoize, copy_arguments, replace_argument_if, \ retry, return_as_list, default_return, transform_result, transform_arguments, \ - cache_memoize, call_method_on_exception + cache_memoize, call_method_on_exception, execute_if_attribute_none, \ + execute_if_attribute_not_none from satella.coding.predicates import x from satella.exceptions import PreconditionError @@ -18,6 +19,42 @@ logger = logging.getLogger(__name__) class TestDecorators(unittest.TestCase): + def test_execute_if_attribute_not_none(self): + class ExecIfAttrNone: + def __init__(self): + self.attr = None + self.called = 0 + + @execute_if_attribute_not_none('attr') + def run_me(self): + self.called += 1 + + e = ExecIfAttrNone() + self.assertEqual(e.called, 0) + e.run_me() + self.assertEqual(e.called, 0) + e.attr = 2 + e.run_me() + self.assertEqual(e.called, 1) + + def test_execute_if_attribute_none(self): + class ExecIfAttrNone: + def __init__(self): + self.attr = None + self.called = 0 + + @execute_if_attribute_none('attr') + def run_me(self): + self.called += 1 + + e = ExecIfAttrNone() + self.assertEqual(e.called, 0) + e.run_me() + self.assertEqual(e.called, 1) + e.attr = 2 + e.run_me() + self.assertEqual(e.called, 1) + def test_call_method_on_exception(self): a = {'called': False} slf = self -- GitLab