diff --git a/AUTHORS.rst b/AUTHORS.rst index 42a456c..81fcfc2 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -32,3 +32,4 @@ Patches and Suggestions - Jonathan Herriott - Job Evers - Cyrus Durgin +- Luca Castoro diff --git a/retrying.py b/retrying.py index bcb7a9d..6723520 100644 --- a/retrying.py +++ b/retrying.py @@ -77,7 +77,8 @@ def __init__(self, wait_func=None, wait_jitter_max=None, before_attempts=None, - after_attempts=None): + after_attempts=None, + custom_message=None): self._stop_max_attempt_number = 5 if stop_max_attempt_number is None else stop_max_attempt_number self._stop_max_delay = 100 if stop_max_delay is None else stop_max_delay @@ -92,6 +93,7 @@ def __init__(self, self._wait_jitter_max = 0 if wait_jitter_max is None else wait_jitter_max self._before_attempts = before_attempts self._after_attempts = after_attempts + self._custom_message = custom_message # TODO add chaining of stop behaviors # stop behavior @@ -217,15 +219,16 @@ def should_reject(self, attempt): def call(self, fn, *args, **kwargs): start_time = int(round(time.time() * 1000)) attempt_number = 1 + message = self._custom_message if self._custom_message else fn.__name__ while True: if self._before_attempts: self._before_attempts(attempt_number) try: - attempt = Attempt(fn(*args, **kwargs), attempt_number, False) + attempt = Attempt(fn(*args, **kwargs), attempt_number, False, message) except: tb = sys.exc_info() - attempt = Attempt(tb, attempt_number, True) + attempt = Attempt(tb, attempt_number, True, message) if not self.should_reject(attempt): return attempt.get(self._wrap_exception) @@ -257,10 +260,11 @@ class Attempt(object): occurred during the execution. """ - def __init__(self, value, attempt_number, has_exception): + def __init__(self, value, attempt_number, has_exception, message): self.value = value self.attempt_number = attempt_number self.has_exception = has_exception + self.message = message def get(self, wrap_exception=False): """ @@ -278,9 +282,9 @@ def get(self, wrap_exception=False): def __repr__(self): if self.has_exception: - return "Attempts: {0}, Error:\n{1}".format(self.attempt_number, "".join(traceback.format_tb(self.value[2]))) + return "Attempts: {0}, {1}, Error:\n{2}".format(self.attempt_number, self.message, "".join(traceback.format_tb(self.value[2]))) else: - return "Attempts: {0}, Value: {1}".format(self.attempt_number, self.value) + return "Attempts: {0}, {1}, Value: {2}".format(self.attempt_number, self.message, self.value) class RetryError(Exception): diff --git a/test_retrying.py b/test_retrying.py index 8ce4ac3..722d398 100644 --- a/test_retrying.py +++ b/test_retrying.py @@ -12,6 +12,7 @@ ## See the License for the specific language governing permissions and ## limitations under the License. +import sys import time import unittest @@ -468,5 +469,31 @@ def _test_after(): self.assertTrue(TestBeforeAfterAttempts._attempt_number is 2) +class TestMeaningfulMessage(unittest.TestCase): + + def test_function_name(self): + + @retry(retry_on_result = lambda x: not x, stop_max_attempt_number = 5) + def just_a_function(): + return 0 + + try: + just_a_function() + self.assertFalse(True) + except RetryError as ex: + self.assertTrue('just_a_function' in str(ex)) + + def test_custom_message(self): + + @retry(retry_on_result = lambda x: not x, stop_max_attempt_number = 5, custom_message = 'hello world') + def just_a_function(): + return 0 + + try: + just_a_function() + self.assertFalse(True) + except RetryError as ex: + self.assertTrue('hello world' in str(ex)) + if __name__ == '__main__': unittest.main()