diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c20fca640e9b65a34b23323403cab4530e0da3c..1b451f3d9bd76e516d369ee9851dd868ddd90ea8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1 +1,3 @@ # v2.14.38 + +* added `call_between_retries` to `retry` diff --git a/satella/__init__.py b/satella/__init__.py index 4967019676def17933f2b5529990cc887b528ca5..a18a644c4d6e085a41fc1221a2afef2485795417 100644 --- a/satella/__init__.py +++ b/satella/__init__.py @@ -1 +1 @@ -__version__ = '2.14.38a1' +__version__ = '2.14.38' diff --git a/satella/coding/decorators/retry_dec.py b/satella/coding/decorators/retry_dec.py index 7cccdd7485dfdca5794c391f6437f69c8da1e185..098626d1036df2bda6321bc06e3ba502643e0ec7 100644 --- a/satella/coding/decorators/retry_dec.py +++ b/satella/coding/decorators/retry_dec.py @@ -10,7 +10,8 @@ def retry(times: tp.Optional[int] = None, on_failure: tp.Callable[[Exception], None] = lambda e: None, swallow_exception: bool = True, call_on_failure: tp.Optional[tp.Callable[[Exception], None]] = None, - call_on_success: tp.Optional[tp.Callable[[int], None]] = None): + call_on_success: tp.Optional[tp.Callable[[int], None]] = None, + call_between_retries: tp.Optional[tp.Callable[[Exception], None]] = None): """ A decorator retrying given operation, failing it when an exception shows up. @@ -40,6 +41,8 @@ def retry(times: tp.Optional[int] = None, exception as it's sole argument. It's result will be discarded. :param call_on_success: a callable that will be called with a single argument: the number of retries that it took to finish the job. It's result will be discarded. + :param call_between_retries: called between retries with a single argument, the Exception + instance that forced the retry. :return: function result """ def outer(fun): @@ -57,6 +60,8 @@ def retry(times: tp.Optional[int] = None, return y except exc_classes as e: f = e + if call_between_retries is not None: + call_between_retries(e) continue else: on_failure(f) diff --git a/tests/test_coding/test_decorators.py b/tests/test_coding/test_decorators.py index e6200f63bbf436dbde63cf48c9faace37038db04..bb1a323a3e4457f1e65ca50ddb93242589243ea1 100644 --- a/tests/test_coding/test_decorators.py +++ b/tests/test_coding/test_decorators.py @@ -77,7 +77,8 @@ class TestDecorators(unittest.TestCase): self.assertEqual(test(), [2, 3, None, 4]) def test_retry(self): - a = {'test': 0, 'limit': 2, 'true': False, 'false': False} + a = {'test': 3, 'limit': 2, 'true': False, 'false': False, + 'retried': False} def on_failure(e): nonlocal a @@ -87,8 +88,13 @@ class TestDecorators(unittest.TestCase): nonlocal a a['false'] = True + def on_retry(e): + nonlocal a + a['retried'] = True + @retry(3, ValueError, swallow_exception=False, call_on_failure=on_failure, - call_on_success=on_success) + call_on_success=on_success, + call_between_retries=on_retry) def do_op(): a['test'] += 1 if a['test'] < a['limit']: @@ -96,11 +102,21 @@ class TestDecorators(unittest.TestCase): do_op() self.assertTrue(a['false']) + self.assertFalse(a['retried']) + a = {'test': 0, 'limit': 2, 'true': False, 'false': False, + 'retried': False} + + do_op() + self.assertTrue(a['retried']) + self.assertTrue(a['false']) a['limit'] = 10 a['false'] = False + a['retried'] = False self.assertRaises(ValueError, do_op) self.assertTrue(a['true']) self.assertFalse(a['false']) + self.assertTrue(a['retried']) + self.assertTrue(a['retried']) def test_replace_argument_if(self): @replace_argument_if('y', x.int(), str)