The tenacity library comes with an intriguing mix of iterators and context managers to allow the users to retry blocks with this syntax:
from tenacity import Retrying, stop_after_attempt
for attempt in Retrying(stop=stop_after_attempt(3)):
with attempt:
1 / 0
You can use the same mechanism yourself, by creating and linking a custom context manager and iterator:
class YouAndIhaveUnfinishedBusiness:
def __init__(self, notify_success, attempt_number):
self.notify_success = notify_success
self.attempt = attempt_number
def __enter__(self):
pass
def __exit__(self, exc_type, exc_value, traceback):
if exc_value:
print(f"You have disappointed me {self.attempt} time(s).")
else:
self.notify_success()
return True
class DoOrDoNotThereIsNoTry:
def __init__(self, max_attempts):
self.max_attempts = max_attempts
self.success = False
def __iter__(self):
for i in range(self.max_attempts):
yield YouAndIhaveUnfinishedBusiness(self.succeed, i+1)
if self.success:
print("You are ready for the Kumite.")
break
else:
print("We trained him wrong on purpose, as a joke.")
def succeed(self):
self.success = True
The issue with this pattern is that you create a hard API requirement that isn’t enforceable through the Python API. Aka nothing would stop me from mistakenly doing, and as a reviewer that is unaware of the retrying API, I would never spot this bug:
for attempt in Retrying(stop=stop_after_attempt(3)):
0/0
For a reader that didn’t went through the documentation, it isn’t obvious at all what the with attempt is meant for. This pattern try to be too much clever for little to no gain over the existing decorator pattern.
Decorator are also easy to use as scope with inlined function. Nothing stop you from doing:
Summary:
The tenacity library comes with an intriguing mix of iterators and context managers to allow the users to retry blocks with this syntax:
You can use the same mechanism yourself, by creating and linking a custom context manager and iterator:
The issue with this pattern is that you create a hard API requirement that isn’t enforceable through the Python API. Aka nothing would stop me from mistakenly doing, and as a reviewer that is unaware of the retrying API, I would never spot this bug:
For a reader that didn’t went through the documentation, it isn’t obvious at all what the
with attempt
is meant for. This pattern try to be too much clever for little to no gain over the existing decorator pattern.Decorator are also easy to use as scope with inlined function. Nothing stop you from doing: