Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 12 additions & 11 deletions tenacity/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@
import warnings
from abc import ABC, abstractmethod
from concurrent import futures
from inspect import iscoroutinefunction

from . import asyncio as tasyncio

# Import all built-in retry strategies for easier usage.
from .retry import retry_base # noqa
Expand Down Expand Up @@ -556,16 +557,16 @@ def retry(func: WrappedFn) -> WrappedFn:

@t.overload
def retry(
sleep: t.Callable[[t.Union[int, float]], t.Optional[t.Awaitable[None]]] = sleep,
stop: "StopBaseT" = stop_never,
wait: "WaitBaseT" = wait_none(),
retry: "RetryBaseT" = retry_if_exception_type(),
before: t.Callable[["RetryCallState"], None] = before_nothing,
after: t.Callable[["RetryCallState"], None] = after_nothing,
before_sleep: t.Optional[t.Callable[["RetryCallState"], None]] = None,
sleep: t.Callable[[t.Union[int, float]], t.Union[None, t.Awaitable[None]]] = sleep,
stop: "t.Union[StopBaseT, tasyncio.stop.StopBaseT]" = stop_never,
wait: "t.Union[WaitBaseT, tasyncio.wait.WaitBaseT]" = wait_none(),
retry: "t.Union[RetryBaseT, tasyncio.retry.RetryBaseT]" = retry_if_exception_type(),
before: t.Callable[["RetryCallState"], t.Union[None, t.Awaitable[None]]] = before_nothing,
after: t.Callable[["RetryCallState"], t.Union[None, t.Awaitable[None]]] = after_nothing,
before_sleep: t.Optional[t.Callable[["RetryCallState"], t.Union[None, t.Awaitable[None]]]] = None,
reraise: bool = False,
retry_error_cls: t.Type["RetryError"] = RetryError,
retry_error_callback: t.Optional[t.Callable[["RetryCallState"], t.Any]] = None,
retry_error_callback: t.Optional[t.Callable[["RetryCallState"], t.Union[t.Any, t.Awaitable[t.Any]]]] = None,
) -> t.Callable[[WrappedFn], WrappedFn]:
...

Expand All @@ -588,7 +589,7 @@ def wrap(f: WrappedFn) -> WrappedFn:
f"this will probably hang indefinitely (did you mean retry={f.__class__.__name__}(...)?)"
)
r: "BaseRetrying"
if iscoroutinefunction(f):
if tasyncio.is_coroutine_callable(f):
r = AsyncRetrying(*dargs, **dkw)
elif tornado and hasattr(tornado.gen, "is_coroutine_function") and tornado.gen.is_coroutine_function(f):
r = TornadoRetrying(*dargs, **dkw)
Expand All @@ -600,7 +601,7 @@ def wrap(f: WrappedFn) -> WrappedFn:
return wrap


from tenacity._asyncio import AsyncRetrying # noqa:E402,I100
from tenacity.asyncio import AsyncRetrying # noqa:E402,I100

if tornado:
from tenacity.tornadoweb import TornadoRetrying
Expand Down
112 changes: 104 additions & 8 deletions tenacity/_asyncio.py → tenacity/asyncio/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,57 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import asyncio
import functools
import inspect
import sys
import typing as t
from asyncio import sleep

from tenacity import AttemptManager
from tenacity import BaseRetrying
from tenacity import DoAttempt
from tenacity import DoSleep
from tenacity import RetryCallState
from tenacity import RetryError
from tenacity import after_nothing
from tenacity import before_nothing

# Import all built-in retry strategies for easier usage.
from .retry import RetryBaseT
from .retry import retry_all # noqa
from .retry import retry_always # noqa
from .retry import retry_any # noqa
from .retry import retry_if_exception # noqa
from .retry import retry_if_exception_type # noqa
from .retry import retry_if_exception_cause_type # noqa
from .retry import retry_if_not_exception_type # noqa
from .retry import retry_if_not_result # noqa
from .retry import retry_if_result # noqa
from .retry import retry_never # noqa
from .retry import retry_unless_exception_type # noqa
from .retry import retry_if_exception_message # noqa
from .retry import retry_if_not_exception_message # noqa
# Import all built-in stop strategies for easier usage.
from .stop import StopBaseT
from .stop import stop_after_attempt # noqa
from .stop import stop_after_delay # noqa
from .stop import stop_before_delay # noqa
from .stop import stop_all # noqa
from .stop import stop_any # noqa
from .stop import stop_never # noqa
from .stop import stop_when_event_set # noqa
# Import all built-in wait strategies for easier usage.
from .wait import WaitBaseT
from .wait import wait_chain # noqa
from .wait import wait_combine # noqa
from .wait import wait_exponential # noqa
from .wait import wait_fixed # noqa
from .wait import wait_incrementing # noqa
from .wait import wait_none # noqa
from .wait import wait_random # noqa
from .wait import wait_random_exponential # noqa
from .wait import wait_random_exponential as wait_full_jitter # noqa
from .wait import wait_exponential_jitter # noqa

WrappedFnReturnT = t.TypeVar("WrappedFnReturnT")
WrappedFn = t.TypeVar("WrappedFn", bound=t.Callable[..., t.Awaitable[t.Any]])
Expand All @@ -41,11 +81,31 @@ def is_coroutine_callable(call: t.Callable[..., t.Any]) -> bool:


class AsyncRetrying(BaseRetrying):
sleep: t.Callable[[float], t.Awaitable[t.Any]]

def __init__(self, sleep: t.Callable[[float], t.Awaitable[t.Any]] = sleep, **kwargs: t.Any) -> None:
super().__init__(**kwargs)
self.sleep = sleep
def __init__(
self,
sleep: t.Callable[[t.Union[int, float]], t.Union[None, t.Awaitable[None]]] = asyncio.sleep,
stop: "t.Union[StopBaseT, StopBaseT]" = stop_never,
wait: "t.Union[WaitBaseT, WaitBaseT]" = wait_none(),
retry: "t.Union[RetryBaseT, RetryBaseT]" = retry_if_exception_type(),
before: t.Callable[["RetryCallState"], t.Union[None, t.Awaitable[None]]] = before_nothing,
after: t.Callable[["RetryCallState"], t.Union[None, t.Awaitable[None]]] = after_nothing,
before_sleep: t.Optional[t.Callable[["RetryCallState"], t.Union[None, t.Awaitable[None]]]] = None,
reraise: bool = False,
retry_error_cls: t.Type["RetryError"] = RetryError,
retry_error_callback: t.Optional[t.Callable[["RetryCallState"], t.Union[t.Any, t.Awaitable[t.Any]]]] = None,
) -> None:
super().__init__(
sleep=sleep, # type: ignore[arg-type]
stop=stop, # type: ignore[arg-type]
wait=wait, # type: ignore[arg-type]
retry=retry, # type: ignore[arg-type]
before=before, # type: ignore[arg-type]
after=after, # type: ignore[arg-type]
before_sleep=before_sleep, # type: ignore[arg-type]
reraise=reraise,
retry_error_cls=retry_error_cls,
retry_error_callback=retry_error_callback,
)

async def __call__( # type: ignore[override]
self, fn: WrappedFn, *args: t.Any, **kwargs: t.Any
Expand All @@ -64,7 +124,7 @@ async def __call__( # type: ignore[override]
retry_state.set_result(result)
elif isinstance(do, DoSleep):
retry_state.prepare_for_next_attempt()
await self.sleep(do)
await self.sleep(do) # type: ignore[misc]
else:
return do # type: ignore[no-any-return]

Expand Down Expand Up @@ -120,7 +180,7 @@ async def __anext__(self) -> AttemptManager:
return AttemptManager(retry_state=self._retry_state)
elif isinstance(do, DoSleep):
self._retry_state.prepare_for_next_attempt()
await self.sleep(do)
await self.sleep(do) # type: ignore[misc]
else:
raise StopAsyncIteration

Expand All @@ -137,3 +197,39 @@ async def async_wrapped(*args: t.Any, **kwargs: t.Any) -> t.Any:
async_wrapped.retry_with = fn.retry_with # type: ignore[attr-defined]

return async_wrapped # type: ignore[return-value]


__all__ = [
"retry_all",
"retry_always",
"retry_any",
"retry_if_exception",
"retry_if_exception_type",
"retry_if_exception_cause_type",
"retry_if_not_exception_type",
"retry_if_not_result",
"retry_if_result",
"retry_never",
"retry_unless_exception_type",
"retry_if_exception_message",
"retry_if_not_exception_message",
"stop_after_attempt",
"stop_after_delay",
"stop_before_delay",
"stop_all",
"stop_any",
"stop_never",
"stop_when_event_set",
"wait_chain",
"wait_combine",
"wait_exponential",
"wait_fixed",
"wait_incrementing",
"wait_none",
"wait_random",
"wait_random_exponential",
"wait_full_jitter",
"wait_exponential_jitter",
"WrappedFn",
"AsyncRetrying",
]
Loading