aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/python
diff options
context:
space:
mode:
authorrobot-piglet <robot-piglet@yandex-team.com>2024-07-02 11:20:50 +0300
committerrobot-piglet <robot-piglet@yandex-team.com>2024-07-02 11:31:57 +0300
commit5f2323ef7bd3c3874a5dbbcaf67db0cc094117ab (patch)
tree75b5e2730de828fb35d22cbf1a6c504606825cd6 /contrib/python
parente6141b6d4e256d98ce597ab2491e70bf90e7338a (diff)
downloadydb-5f2323ef7bd3c3874a5dbbcaf67db0cc094117ab.tar.gz
Intermediate changes
Diffstat (limited to 'contrib/python')
-rw-r--r--contrib/python/tenacity/py3/.dist-info/METADATA2
-rw-r--r--contrib/python/tenacity/py3/README.rst20
-rw-r--r--contrib/python/tenacity/py3/tenacity/__init__.py28
-rw-r--r--contrib/python/tenacity/py3/tenacity/_utils.py12
-rw-r--r--contrib/python/tenacity/py3/tenacity/asyncio/__init__.py (renamed from contrib/python/tenacity/py3/tenacity/_asyncio.py)101
-rw-r--r--contrib/python/tenacity/py3/tenacity/asyncio/retry.py125
-rw-r--r--contrib/python/tenacity/py3/tenacity/retry.py10
-rw-r--r--contrib/python/tenacity/py3/ya.make5
8 files changed, 258 insertions, 45 deletions
diff --git a/contrib/python/tenacity/py3/.dist-info/METADATA b/contrib/python/tenacity/py3/.dist-info/METADATA
index 3e509464e2..cd789a8975 100644
--- a/contrib/python/tenacity/py3/.dist-info/METADATA
+++ b/contrib/python/tenacity/py3/.dist-info/METADATA
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: tenacity
-Version: 8.3.0
+Version: 8.4.1
Summary: Retry code until it succeeds
Home-page: https://github.com/jd/tenacity
Author: Julien Danjou
diff --git a/contrib/python/tenacity/py3/README.rst b/contrib/python/tenacity/py3/README.rst
index bdf7ff2117..65dd208bdf 100644
--- a/contrib/python/tenacity/py3/README.rst
+++ b/contrib/python/tenacity/py3/README.rst
@@ -79,7 +79,7 @@ Examples
Basic Retry
~~~~~~~~~~~
-.. testsetup:: *
+.. testsetup::
import logging
#
@@ -568,28 +568,34 @@ in retry strategies like ``retry_if_result``. This can be done accessing the
Async and retry
~~~~~~~~~~~~~~~
-Finally, ``retry`` works also on asyncio and Tornado (>= 4.5) coroutines.
+Finally, ``retry`` works also on asyncio, Trio, and Tornado (>= 4.5) coroutines.
Sleeps are done asynchronously too.
.. code-block:: python
@retry
- async def my_async_function(loop):
+ async def my_asyncio_function(loop):
await loop.getaddrinfo('8.8.8.8', 53)
.. code-block:: python
@retry
+ async def my_async_trio_function():
+ await trio.socket.getaddrinfo('8.8.8.8', 53)
+
+.. code-block:: python
+
+ @retry
@tornado.gen.coroutine
- def my_async_function(http_client, url):
+ def my_async_tornado_function(http_client, url):
yield http_client.fetch(url)
-You can even use alternative event loops such as `curio` or `Trio` by passing the correct sleep function:
+You can even use alternative event loops such as `curio` by passing the correct sleep function:
.. code-block:: python
- @retry(sleep=trio.sleep)
- async def my_async_function(loop):
+ @retry(sleep=curio.sleep)
+ async def my_async_curio_function():
await asks.get('https://example.org')
Contribute
diff --git a/contrib/python/tenacity/py3/tenacity/__init__.py b/contrib/python/tenacity/py3/tenacity/__init__.py
index bcee3f5910..7de36d4345 100644
--- a/contrib/python/tenacity/py3/tenacity/__init__.py
+++ b/contrib/python/tenacity/py3/tenacity/__init__.py
@@ -24,7 +24,8 @@ import typing as t
import warnings
from abc import ABC, abstractmethod
from concurrent import futures
-from inspect import iscoroutinefunction
+
+from . import _utils
# Import all built-in retry strategies for easier usage.
from .retry import retry_base # noqa
@@ -87,6 +88,7 @@ except ImportError:
if t.TYPE_CHECKING:
import types
+ from . import asyncio as tasyncio
from .retry import RetryBaseT
from .stop import StopBaseT
from .wait import WaitBaseT
@@ -593,16 +595,24 @@ def retry(func: WrappedFn) -> WrappedFn: ...
@t.overload
def retry(
- sleep: t.Callable[[t.Union[int, float]], t.Optional[t.Awaitable[None]]] = sleep,
+ sleep: t.Callable[[t.Union[int, float]], t.Union[None, 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,
+ 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]: ...
@@ -624,7 +634,7 @@ def retry(*dargs: t.Any, **dkw: t.Any) -> t.Any:
f"this will probably hang indefinitely (did you mean retry={f.__class__.__name__}(...)?)"
)
r: "BaseRetrying"
- if iscoroutinefunction(f):
+ if _utils.is_coroutine_callable(f):
r = AsyncRetrying(*dargs, **dkw)
elif (
tornado
@@ -640,7 +650,7 @@ def retry(*dargs: t.Any, **dkw: t.Any) -> t.Any:
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
diff --git a/contrib/python/tenacity/py3/tenacity/_utils.py b/contrib/python/tenacity/py3/tenacity/_utils.py
index 4e34115e0e..f11a088814 100644
--- a/contrib/python/tenacity/py3/tenacity/_utils.py
+++ b/contrib/python/tenacity/py3/tenacity/_utils.py
@@ -87,3 +87,15 @@ def is_coroutine_callable(call: typing.Callable[..., typing.Any]) -> bool:
partial_call = isinstance(call, functools.partial) and call.func
dunder_call = partial_call or getattr(call, "__call__", None)
return inspect.iscoroutinefunction(dunder_call)
+
+
+def wrap_to_async_func(
+ call: typing.Callable[..., typing.Any],
+) -> typing.Callable[..., typing.Awaitable[typing.Any]]:
+ if is_coroutine_callable(call):
+ return call
+
+ async def inner(*args: typing.Any, **kwargs: typing.Any) -> typing.Any:
+ return call(*args, **kwargs)
+
+ return inner
diff --git a/contrib/python/tenacity/py3/tenacity/_asyncio.py b/contrib/python/tenacity/py3/tenacity/asyncio/__init__.py
index b06303f484..6d63ebcfab 100644
--- a/contrib/python/tenacity/py3/tenacity/_asyncio.py
+++ b/contrib/python/tenacity/py3/tenacity/asyncio/__init__.py
@@ -19,34 +19,87 @@ import functools
import sys
import typing as t
+import tenacity
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
from tenacity import _utils
+# Import all built-in retry strategies for easier usage.
+from .retry import RetryBaseT
+from .retry import retry_all # noqa
+from .retry import retry_any # noqa
+from .retry import retry_if_exception # noqa
+from .retry import retry_if_result # noqa
+from ..retry import RetryBaseT as SyncRetryBaseT
+
+if t.TYPE_CHECKING:
+ from tenacity.stop import StopBaseT
+ from tenacity.wait import WaitBaseT
+
WrappedFnReturnT = t.TypeVar("WrappedFnReturnT")
WrappedFn = t.TypeVar("WrappedFn", bound=t.Callable[..., t.Awaitable[t.Any]])
-def asyncio_sleep(duration: float) -> t.Awaitable[None]:
+def _portable_async_sleep(seconds: float) -> t.Awaitable[None]:
+ # If trio is already imported, then importing it is cheap.
+ # If trio isn't already imported, then it's definitely not running, so we
+ # can skip further checks.
+ if "trio" in sys.modules:
+ # If trio is available, then sniffio is too
+ import trio
+ import sniffio
+
+ if sniffio.current_async_library() == "trio":
+ return trio.sleep(seconds)
+ # Otherwise, assume asyncio
# Lazy import asyncio as it's expensive (responsible for 25-50% of total import overhead).
import asyncio
- return asyncio.sleep(duration)
+ return asyncio.sleep(seconds)
class AsyncRetrying(BaseRetrying):
- sleep: t.Callable[[float], t.Awaitable[t.Any]]
-
def __init__(
self,
- sleep: t.Callable[[float], t.Awaitable[t.Any]] = asyncio_sleep,
- **kwargs: t.Any,
+ sleep: t.Callable[
+ [t.Union[int, float]], t.Union[None, t.Awaitable[None]]
+ ] = _portable_async_sleep,
+ stop: "StopBaseT" = tenacity.stop.stop_never,
+ wait: "WaitBaseT" = tenacity.wait.wait_none(),
+ retry: "t.Union[SyncRetryBaseT, RetryBaseT]" = tenacity.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__(**kwargs)
- self.sleep = sleep
+ super().__init__(
+ sleep=sleep, # type: ignore[arg-type]
+ stop=stop,
+ wait=wait,
+ 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
@@ -65,31 +118,21 @@ class AsyncRetrying(BaseRetrying):
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]
- @classmethod
- def _wrap_action_func(cls, fn: t.Callable[..., t.Any]) -> t.Callable[..., t.Any]:
- if _utils.is_coroutine_callable(fn):
- return fn
-
- async def inner(*args: t.Any, **kwargs: t.Any) -> t.Any:
- return fn(*args, **kwargs)
-
- return inner
-
def _add_action_func(self, fn: t.Callable[..., t.Any]) -> None:
- self.iter_state.actions.append(self._wrap_action_func(fn))
+ self.iter_state.actions.append(_utils.wrap_to_async_func(fn))
async def _run_retry(self, retry_state: "RetryCallState") -> None: # type: ignore[override]
- self.iter_state.retry_run_result = await self._wrap_action_func(self.retry)(
+ self.iter_state.retry_run_result = await _utils.wrap_to_async_func(self.retry)(
retry_state
)
async def _run_wait(self, retry_state: "RetryCallState") -> None: # type: ignore[override]
if self.wait:
- sleep = await self._wrap_action_func(self.wait)(retry_state)
+ sleep = await _utils.wrap_to_async_func(self.wait)(retry_state)
else:
sleep = 0.0
@@ -97,7 +140,7 @@ class AsyncRetrying(BaseRetrying):
async def _run_stop(self, retry_state: "RetryCallState") -> None: # type: ignore[override]
self.statistics["delay_since_first_attempt"] = retry_state.seconds_since_start
- self.iter_state.stop_run_result = await self._wrap_action_func(self.stop)(
+ self.iter_state.stop_run_result = await _utils.wrap_to_async_func(self.stop)(
retry_state
)
@@ -127,7 +170,7 @@ class AsyncRetrying(BaseRetrying):
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
@@ -146,3 +189,13 @@ class AsyncRetrying(BaseRetrying):
async_wrapped.retry_with = fn.retry_with # type: ignore[attr-defined]
return async_wrapped # type: ignore[return-value]
+
+
+__all__ = [
+ "retry_all",
+ "retry_any",
+ "retry_if_exception",
+ "retry_if_result",
+ "WrappedFn",
+ "AsyncRetrying",
+]
diff --git a/contrib/python/tenacity/py3/tenacity/asyncio/retry.py b/contrib/python/tenacity/py3/tenacity/asyncio/retry.py
new file mode 100644
index 0000000000..94b8b15428
--- /dev/null
+++ b/contrib/python/tenacity/py3/tenacity/asyncio/retry.py
@@ -0,0 +1,125 @@
+# Copyright 2016–2021 Julien Danjou
+# Copyright 2016 Joshua Harlow
+# Copyright 2013-2014 Ray Holder
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+import abc
+import typing
+
+from tenacity import _utils
+from tenacity import retry_base
+
+if typing.TYPE_CHECKING:
+ from tenacity import RetryCallState
+
+
+class async_retry_base(retry_base):
+ """Abstract base class for async retry strategies."""
+
+ @abc.abstractmethod
+ async def __call__(self, retry_state: "RetryCallState") -> bool: # type: ignore[override]
+ pass
+
+ def __and__( # type: ignore[override]
+ self, other: "typing.Union[retry_base, async_retry_base]"
+ ) -> "retry_all":
+ return retry_all(self, other)
+
+ def __rand__( # type: ignore[misc,override]
+ self, other: "typing.Union[retry_base, async_retry_base]"
+ ) -> "retry_all":
+ return retry_all(other, self)
+
+ def __or__( # type: ignore[override]
+ self, other: "typing.Union[retry_base, async_retry_base]"
+ ) -> "retry_any":
+ return retry_any(self, other)
+
+ def __ror__( # type: ignore[misc,override]
+ self, other: "typing.Union[retry_base, async_retry_base]"
+ ) -> "retry_any":
+ return retry_any(other, self)
+
+
+RetryBaseT = typing.Union[
+ async_retry_base, typing.Callable[["RetryCallState"], typing.Awaitable[bool]]
+]
+
+
+class retry_if_exception(async_retry_base):
+ """Retry strategy that retries if an exception verifies a predicate."""
+
+ def __init__(
+ self, predicate: typing.Callable[[BaseException], typing.Awaitable[bool]]
+ ) -> None:
+ self.predicate = predicate
+
+ async def __call__(self, retry_state: "RetryCallState") -> bool: # type: ignore[override]
+ if retry_state.outcome is None:
+ raise RuntimeError("__call__() called before outcome was set")
+
+ if retry_state.outcome.failed:
+ exception = retry_state.outcome.exception()
+ if exception is None:
+ raise RuntimeError("outcome failed but the exception is None")
+ return await self.predicate(exception)
+ else:
+ return False
+
+
+class retry_if_result(async_retry_base):
+ """Retries if the result verifies a predicate."""
+
+ def __init__(
+ self, predicate: typing.Callable[[typing.Any], typing.Awaitable[bool]]
+ ) -> None:
+ self.predicate = predicate
+
+ async def __call__(self, retry_state: "RetryCallState") -> bool: # type: ignore[override]
+ if retry_state.outcome is None:
+ raise RuntimeError("__call__() called before outcome was set")
+
+ if not retry_state.outcome.failed:
+ return await self.predicate(retry_state.outcome.result())
+ else:
+ return False
+
+
+class retry_any(async_retry_base):
+ """Retries if any of the retries condition is valid."""
+
+ def __init__(self, *retries: typing.Union[retry_base, async_retry_base]) -> None:
+ self.retries = retries
+
+ async def __call__(self, retry_state: "RetryCallState") -> bool: # type: ignore[override]
+ result = False
+ for r in self.retries:
+ result = result or await _utils.wrap_to_async_func(r)(retry_state)
+ if result:
+ break
+ return result
+
+
+class retry_all(async_retry_base):
+ """Retries if all the retries condition are valid."""
+
+ def __init__(self, *retries: typing.Union[retry_base, async_retry_base]) -> None:
+ self.retries = retries
+
+ async def __call__(self, retry_state: "RetryCallState") -> bool: # type: ignore[override]
+ result = True
+ for r in self.retries:
+ result = result and await _utils.wrap_to_async_func(r)(retry_state)
+ if not result:
+ break
+ return result
diff --git a/contrib/python/tenacity/py3/tenacity/retry.py b/contrib/python/tenacity/py3/tenacity/retry.py
index c5e55a653f..9211631bd8 100644
--- a/contrib/python/tenacity/py3/tenacity/retry.py
+++ b/contrib/python/tenacity/py3/tenacity/retry.py
@@ -30,10 +30,16 @@ class retry_base(abc.ABC):
pass
def __and__(self, other: "retry_base") -> "retry_all":
- return retry_all(self, other)
+ return other.__rand__(self)
+
+ def __rand__(self, other: "retry_base") -> "retry_all":
+ return retry_all(other, self)
def __or__(self, other: "retry_base") -> "retry_any":
- return retry_any(self, other)
+ return other.__ror__(self)
+
+ def __ror__(self, other: "retry_base") -> "retry_any":
+ return retry_any(other, self)
RetryBaseT = typing.Union[retry_base, typing.Callable[["RetryCallState"], bool]]
diff --git a/contrib/python/tenacity/py3/ya.make b/contrib/python/tenacity/py3/ya.make
index 1670ca9908..d75e15b99f 100644
--- a/contrib/python/tenacity/py3/ya.make
+++ b/contrib/python/tenacity/py3/ya.make
@@ -2,7 +2,7 @@
PY3_LIBRARY()
-VERSION(8.3.0)
+VERSION(8.4.1)
LICENSE(Apache-2.0)
@@ -15,9 +15,10 @@ NO_CHECK_IMPORTS(
PY_SRCS(
TOP_LEVEL
tenacity/__init__.py
- tenacity/_asyncio.py
tenacity/_utils.py
tenacity/after.py
+ tenacity/asyncio/__init__.py
+ tenacity/asyncio/retry.py
tenacity/before.py
tenacity/before_sleep.py
tenacity/nap.py