class AsyncRetrying(BaseRetrying): def __init__(self, sleep=sleep, **kwargs): super(AsyncRetrying, self).__init__(**kwargs) self.sleep = sleep async def __call__(self, fn, *args, **kwargs): self.begin(fn) retry_state = RetryCallState(retry_object=self, fn=fn, args=args, kwargs=kwargs) while True: do = self.iter(retry_state=retry_state) if isinstance(do, DoAttempt): try: result = await fn(*args, **kwargs) except BaseException: retry_state.set_exception(sys.exc_info()) else: retry_state.set_result(result) elif isinstance(do, DoSleep): retry_state.prepare_for_next_attempt() await self.sleep(do) else: return do def __aiter__(self): self.begin(None) self._retry_state = RetryCallState(self, fn=None, args=(), kwargs={}) return self async def __anext__(self): while True: do = self.iter(retry_state=self._retry_state) if do is None: raise StopAsyncIteration elif isinstance(do, DoAttempt): return AttemptManager(retry_state=self._retry_state) elif isinstance(do, DoSleep): self._retry_state.prepare_for_next_attempt() await self.sleep(do) else: return do def wraps(self, fn): fn = super().wraps(fn) # Ensure wrapper is recognized as a coroutine function. async def async_wrapped(*args, **kwargs): return await fn(*args, **kwargs) # Preserve attributes async_wrapped.retry = fn.retry async_wrapped.retry_with = fn.retry_with return async_wrapped
async def __call__( # type: ignore # Change signature from supertype self, fn: typing.Callable[..., typing.Awaitable[_RetValT]], *args: typing.Any, **kwargs: typing.Any, ) -> _RetValT: self.begin() retry_state = RetryCallState(retry_object=self, fn=fn, args=args, kwargs=kwargs) while True: do = self.iter(retry_state=retry_state) if isinstance(do, DoAttempt): try: result = await fn(*args, **kwargs) except BaseException: # noqa: B902 retry_state.set_exception(sys.exc_info()) else: retry_state.set_result(result) elif isinstance(do, DoSleep): retry_state.prepare_for_next_attempt() await self.sleep(do) else: return do
def __call__( # type: ignore # Change signature from supertype self, fn: "typing.Callable[..., typing.Union[typing.Generator[typing.Any, typing.Any, _RetValT], Future[_RetValT]]]", *args: typing.Any, **kwargs: typing.Any, ) -> "typing.Generator[typing.Any, typing.Any, _RetValT]": self.begin() retry_state = RetryCallState(retry_object=self, fn=fn, args=args, kwargs=kwargs) while True: do = self.iter(retry_state=retry_state) if isinstance(do, DoAttempt): try: result = yield fn(*args, **kwargs) except BaseException: # noqa: B902 retry_state.set_exception(sys.exc_info()) else: retry_state.set_result(result) elif isinstance(do, DoSleep): retry_state.prepare_for_next_attempt() yield self.sleep(do) else: raise gen.Return(do)
def _make_wait_call_state(previous_attempt_number, delay_since_first_attempt, last_result=None): required_parameter_unset = (previous_attempt_number is _unset or delay_since_first_attempt is _unset) if required_parameter_unset: missing = [] if previous_attempt_number is _unset: missing.append('previous_attempt_number') if delay_since_first_attempt is _unset: missing.append('delay_since_first_attempt') missing_str = ', '.join(repr(s) for s in missing) raise TypeError('wait func missing parameters: ' + missing_str) from tenacity import RetryCallState retry_state = RetryCallState(None, None, (), {}) retry_state.attempt_number = previous_attempt_number if last_result is not None: retry_state.outcome = last_result else: retry_state.set_result(None) # Ensure outcome_timestamp - start_time is *exactly* equal to the delay to # avoid complexity in test code. retry_state.start_time = Fraction(retry_state.start_time) retry_state.outcome_timestamp = (retry_state.start_time + Fraction(delay_since_first_attempt)) assert retry_state.seconds_since_start == delay_since_first_attempt return retry_state
def new_fn(self, attempt=_unset, retry_state=None): if retry_state is None: from tenacity import RetryCallState if attempt is _unset: raise _make_unset_exception('retry', attempt=attempt) retry_state_passed_as_non_kwarg = ( attempt is not _unset and isinstance(attempt, RetryCallState)) if retry_state_passed_as_non_kwarg: retry_state = attempt else: warn_about_dunder_non_retry_state_deprecation(fn, stacklevel=2) retry_state = RetryCallState(None, None, (), {}) retry_state.outcome = attempt return fn(self, retry_state=retry_state)
class AsyncRetrying(BaseRetrying): def __init__(self, sleep=sleep, **kwargs): super(AsyncRetrying, self).__init__(**kwargs) self.sleep = sleep async def call(self, fn, *args, **kwargs): self.begin(fn) retry_state = RetryCallState(retry_object=self, fn=fn, args=args, kwargs=kwargs) while True: do = self.iter(retry_state=retry_state) if isinstance(do, DoAttempt): try: result = await fn(*args, **kwargs) except BaseException: retry_state.set_exception(sys.exc_info()) else: retry_state.set_result(result) elif isinstance(do, DoSleep): retry_state.prepare_for_next_attempt() await self.sleep(do) else: return do def __aiter__(self): self.begin(None) self._retry_state = RetryCallState(self, fn=None, args=(), kwargs={}) return self async def __anext__(self): while True: do = self.iter(retry_state=self._retry_state) if do is None: raise StopAsyncIteration elif isinstance(do, DoAttempt): return AttemptManager(retry_state=self._retry_state) elif isinstance(do, DoSleep): self._retry_state.prepare_for_next_attempt() await self.sleep(do) else: return do
def _make_wait_call_state(previous_attempt_number, delay_since_first_attempt, last_result=None): required_parameter_unset = (previous_attempt_number is _unset or delay_since_first_attempt is _unset) if required_parameter_unset: missing = [] if previous_attempt_number is _unset: missing.append('previous_attempt_number') if delay_since_first_attempt is _unset: missing.append('delay_since_first_attempt') missing_str = ', '.join(repr(s) for s in missing) raise TypeError('wait func missing parameters: ' + missing_str) from tenacity import RetryCallState call_state = RetryCallState(None, (), {}) call_state.attempt_number = previous_attempt_number call_state.outcome_timestamp = (call_state.start_time + delay_since_first_attempt) call_state.outcome = last_result return call_state
def make_retry_state(previous_attempt_number, delay_since_first_attempt, last_result=None): """Construct RetryCallState for given attempt number & delay. Only used in testing and thus is extra careful about timestamp arithmetics. """ required_parameter_unset = previous_attempt_number is _unset or delay_since_first_attempt is _unset if required_parameter_unset: raise _make_unset_exception( "wait/stop", previous_attempt_number=previous_attempt_number, delay_since_first_attempt=delay_since_first_attempt, ) from tenacity import RetryCallState retry_state = RetryCallState(None, None, (), {}) retry_state.attempt_number = previous_attempt_number if last_result is not None: retry_state.outcome = last_result else: retry_state.set_result(None) _set_delay_since_start(retry_state, delay_since_first_attempt) return retry_state
def make_retry_state(previous_attempt_number, delay_since_first_attempt, last_result=None): """Construct RetryCallState for given attempt number & delay. Only used in testing and thus is extra careful about timestamp arithmetics. """ required_parameter_unset = (previous_attempt_number is _unset or delay_since_first_attempt is _unset) if required_parameter_unset: raise _make_unset_exception( 'wait/stop', previous_attempt_number=previous_attempt_number, delay_since_first_attempt=delay_since_first_attempt) from tenacity import RetryCallState retry_state = RetryCallState(None, None, (), {}) retry_state.attempt_number = previous_attempt_number if last_result is not None: retry_state.outcome = last_result else: retry_state.set_result(None) _set_delay_since_start(retry_state, delay_since_first_attempt) return retry_state
async def __call__(self, fn, *args, **kwargs): self.begin(fn) retry_state = RetryCallState(retry_object=self, fn=fn, args=args, kwargs=kwargs) while True: do = self.iter(retry_state=retry_state) if isinstance(do, DoAttempt): try: result = await fn(*args, **kwargs) except BaseException: # noqa: B902 retry_state.set_exception(sys.exc_info()) else: retry_state.set_result(result) elif isinstance(do, DoSleep): retry_state.prepare_for_next_attempt() await self.sleep(do) else: return do
def call(self, fn, *args, **kwargs): self.begin(fn) call_state = RetryCallState(fn=fn, args=args, kwargs=kwargs) while True: do = self.iter(call_state=call_state) if isinstance(do, DoAttempt): call_state.attempt_number += 1 try: result = yield from fn(*args, **kwargs) except BaseException: call_state.set_exception(sys.exc_info()) else: call_state.set_result(result) elif isinstance(do, DoSleep): call_state.prepare_for_next_attempt() yield from self.sleep(do) else: return do
def call(self, fn, *args, **kwargs): self.begin(fn) retry_state = RetryCallState( retry_object=self, fn=fn, args=args, kwargs=kwargs) while True: do = self.iter(retry_state=retry_state) if isinstance(do, DoAttempt): try: result = yield fn(*args, **kwargs) except BaseException: retry_state.set_exception(sys.exc_info()) else: retry_state.set_result(result) elif isinstance(do, DoSleep): retry_state.prepare_for_next_attempt() yield self.sleep(do) else: raise gen.Return(do)
def __aiter__(self): self.begin(None) self._retry_state = RetryCallState(self, fn=None, args=(), kwargs={}) return self
class AsyncRetrying(BaseRetrying): """This is a modified version of the tenacity.AsyncRetrying class that handles asynchronously defined retry or retry_error_callback parameters. There is an open PR for this change on the tenacity repository: https://github.com/jd/tenacity/pull/289 """ def __init__(self, sleep=asyncio.sleep, **kwargs): super().__init__(**kwargs) self.sleep = sleep async def iter(self, retry_state): fut = retry_state.outcome if fut is None: if self.before is not None: self.before(retry_state) return DoAttempt() is_explicit_retry = retry_state.outcome.failed and isinstance( retry_state.outcome.exception(), TryAgain) if iscoroutinefunction(self.retry): should_retry = await self.retry(retry_state=retry_state) else: should_retry = self.retry(retry_state=retry_state) if not (is_explicit_retry or should_retry): return fut.result() if self.after is not None: self.after(retry_state=retry_state) self.statistics[ "delay_since_first_attempt"] = retry_state.seconds_since_start if self.stop(retry_state=retry_state): if self.retry_error_callback: if iscoroutinefunction(self.retry_error_callback): return await self.retry_error_callback( retry_state=retry_state) return self.retry_error_callback(retry_state=retry_state) retry_exc = self.retry_error_cls(fut) if self.reraise: raise retry_exc.reraise() six.raise_from(retry_exc, fut.exception()) if self.wait: iteration_sleep = self.wait(retry_state=retry_state) else: iteration_sleep = 0.0 retry_state.next_action = RetryAction(iteration_sleep) retry_state.idle_for += iteration_sleep self.statistics["idle_for"] += iteration_sleep self.statistics["attempt_number"] += 1 if self.before_sleep is not None: self.before_sleep(retry_state=retry_state) return DoSleep(iteration_sleep) async def __call__(self, fn, *args, **kwargs): self.begin() retry_state = RetryCallState(retry_object=self, fn=fn, args=args, kwargs=kwargs) while True: do = await self.iter(retry_state=retry_state) if isinstance(do, DoAttempt): try: result = await fn(*args, **kwargs) except BaseException: retry_state.set_exception(sys.exc_info()) else: retry_state.set_result(result) elif isinstance(do, DoSleep): retry_state.prepare_for_next_attempt() await self.sleep(do) else: return do def __aiter__(self): self.begin(None) self._retry_state = RetryCallState(self, fn=None, args=(), kwargs={}) return self async def __anext__(self): while True: do = await self.iter(retry_state=self._retry_state) if do is None: raise StopAsyncIteration if isinstance(do, DoAttempt): return AttemptManager(retry_state=self._retry_state) if isinstance(do, DoSleep): self._retry_state.prepare_for_next_attempt() await self.sleep(do) else: return do def wraps(self, fn): fn = super().wraps(fn) # Ensure wrapper is recognized as a coroutine function. async def async_wrapped(*args, **kwargs): return await fn(*args, **kwargs) # Preserve attributes async_wrapped.retry = fn.retry async_wrapped.retry_with = fn.retry_with return async_wrapped
def retry_state(self): retry_state = RetryCallState(object(), lambda x: x, (), {}) retry_state.outcome = Future(attempt_number=1) return retry_state
class AsyncRetrying(BaseRetrying): def __init__(self, sleep: typing.Callable[[float], typing.Awaitable] = sleep, **kwargs: typing.Any) -> None: super().__init__(**kwargs) self.sleep = sleep async def __call__( # type: ignore # Change signature from supertype self, fn: typing.Callable[..., typing.Awaitable[_RetValT]], *args: typing.Any, **kwargs: typing.Any, ) -> _RetValT: self.begin() retry_state = RetryCallState(retry_object=self, fn=fn, args=args, kwargs=kwargs) while True: do = self.iter(retry_state=retry_state) if isinstance(do, DoAttempt): try: result = await fn(*args, **kwargs) except BaseException: # noqa: B902 retry_state.set_exception(sys.exc_info()) else: retry_state.set_result(result) elif isinstance(do, DoSleep): retry_state.prepare_for_next_attempt() await self.sleep(do) else: return do def __aiter__(self) -> "AsyncRetrying": self.begin() self._retry_state = RetryCallState(self, fn=None, args=(), kwargs={}) return self async def __anext__(self) -> typing.Union[AttemptManager, typing.Any]: while True: do = self.iter(retry_state=self._retry_state) if do is None: raise StopAsyncIteration elif isinstance(do, DoAttempt): return AttemptManager(retry_state=self._retry_state) elif isinstance(do, DoSleep): self._retry_state.prepare_for_next_attempt() await self.sleep(do) else: return do def wraps(self, fn: WrappedFn) -> WrappedFn: fn = super().wraps(fn) # Ensure wrapper is recognized as a coroutine function. @functools.wraps(fn) async def async_wrapped(*args: typing.Any, **kwargs: typing.Any) -> typing.Any: return await fn(*args, **kwargs) # Preserve attributes async_wrapped.retry = fn.retry async_wrapped.retry_with = fn.retry_with return async_wrapped
def __aiter__(self) -> "AsyncRetrying": self.begin() self._retry_state = RetryCallState(self, fn=None, args=(), kwargs={}) return self