Skip to content

Instantly share code, notes, and snippets.

@JesterEE
Last active July 19, 2017 22:51
Show Gist options
  • Save JesterEE/05d218c0ecc040162853251ac0a9703e to your computer and use it in GitHub Desktop.
Save JesterEE/05d218c0ecc040162853251ac0a9703e to your computer and use it in GitHub Desktop.
Example using the retrying module with a generator.See docstrings for details.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from retrying import retry
import datetime
import time
class RetryingTimeWrappedGeneratorClass:
"""Class to illustrate how to use `retrying` with a generator.
The `@retry` decorator must be placed on the function execution "inside"
the iteration of the generator. If an error is caught, the iterator will
not progress, and the retried function will operate on the same value of
the generator as determined by the `@retry` decorator.
Note that a class was needed here to carry state information for
`self.time_target` between iterations. If state is not necessary for a
specific generator/iterator use case, 3 separate functions
(generator, iterator, and "main") can be used outside of a class."""
def __init__(self, rng, wait, delta_sec):
self.rng = rng
self.wait = wait
self.delta_sec = delta_sec
self.time_target = datetime.datetime.now() + datetime.timedelta(seconds=delta_sec)
@staticmethod
def calc_square_generator(rng):
"""Generator for squared numbers."""
mylist = range(rng)
for n in mylist:
yield n * n
def calc_square_generator_loop(self):
"""Iterator for the square number generator."""
print("TARGET: {}".format(self.time_target))
for v in self.calc_square_generator(self.rng):
self.calc_square_generator_loop_wrapped(v)
@retry(retry_on_exception=lambda e: isinstance(e, ValueError), wait_random_min=1000, wait_random_max=2000,
stop_max_attempt_number=2, wrap_exception=True)
def calc_square_generator_loop_wrapped(self, v):
""""Main" function to do something over the iteration of the generator.
Here, the value of the generator is not used ... we just check the time
to determine if we ran for too long.
Note: Each iteration of this function is a separate call ... so setting
a maximum delay time is not helpful (for this simple function).
However, to illustrate how the decorator arguments might be
helpful, a random min/max wait time is set in conjunction with a
maximum number of attempts. If
`wait_random_max` ~>= `self.delta_sec`, there is a possibility
that this function can fail multiple times consecutively, causing
the failure condition
(`stop_max_attempt_number` consecutive `ValueError`s).
"""
print('NOW: {} {}'.format(v, datetime.datetime.now()))
if datetime.datetime.now() > self.time_target:
self.time_target = self.time_target + datetime.timedelta(seconds=self.delta_sec)
print('Took too long ... time_target: Added {} seconds to execution.'.format(self.delta_sec))
raise ValueError('Poof ... time flew by!')
time.sleep(self.wait)
if __name__ == '__main__':
wrapped_generator = RetryingTimeWrappedGeneratorClass(rng=10, wait=1, delta_sec=2)
wrapped_generator.calc_square_generator_loop()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment