Metadata-Version: 2.1
Name: aioretry
Version: 5.0.1
Summary: Asyncio retry utility for Python 3.7+
Home-page: https://github.com/kaelzhang/python-aioretry
Author: Kael Zhang
Author-email: i+pypi@kael.me
License: MIT
Description: [![](https://travis-ci.org/kaelzhang/python-aioretry.svg?branch=master)](https://travis-ci.org/kaelzhang/python-aioretry)
        [![](https://codecov.io/gh/kaelzhang/python-aioretry/branch/master/graph/badge.svg)](https://codecov.io/gh/kaelzhang/python-aioretry)
        [![](https://img.shields.io/pypi/v/aioretry.svg)](https://pypi.org/project/aioretry/)
        [![](https://img.shields.io/pypi/l/aioretry.svg)](https://github.com/kaelzhang/python-aioretry)
        
        # aioretry
        
        Asyncio retry utility for Python 3.7+
        
        - [Upgrade guide](#upgrade-guide)
        
        ## Install
        
        ```sh
        $ pip install aioretry
        ```
        
        ## Usage
        
        ```py
        import asyncio
        from typing import (
          Tuple
        )
        
        from aioretry import (
            retry,
            # Tuple[bool, Union[int, float]]
            RetryPolicyStrategy,
            RetryInfo
        )
        
        # This example shows the usage with python typings
        def retry_policy(info: RetryInfo) -> RetryPolicyStrategy:
            """
            - It will always retry until succeeded
            - If fails for the first time, it will retry immediately,
            - If it fails again,
              aioretry will perform a 100ms delay before the second retry,
              200ms delay before the 3rd retry,
              the 4th retry immediately,
              100ms delay before the 5th retry,
              etc...
            """
            return False, (info.fails - 1) % 3 * 0.1
        
        
        @retry(retry_policy)
        async def connect_to_server():
            # connec to server
            ...
        
        asyncio.run(connect_to_server())
        ```
        
        ### Use as class instance method decorator
        
        We could also use `retry` as a decorator for instance method
        
        ```py
        class Client:
            @retry(retry_policy)
            async def connect(self):
                await self._connect()
        
        asyncio.run(Client().connect())
        ```
        
        ### Use instance method as retry policy
        
        `retry_policy` could be the method name of the class if `retry` is used as a decorator for instance method.
        
        ```py
        class ClientWithConfigurableRetryPolicy(Client):
            def __init__(self, max_retries: int = 3):
                self._max_retries = max_retries
        
            def _retry_policy(self, info: RetryInfo) -> RetryPolicyStrategy:
                return info.fails > self._max_retries, info.fails * 0.1
        
            # Then aioretry will use `self._retry_policy` as the retry policy.
            # And by using a str as the parameter `retry_policy`,
            # the decorator must be used for instance methods
            @retry('_retry_policy')
            async def connect(self):
                await self._connect()
        
        asyncio.run(ClientWithConfigurableRetryPolicy(10).connect())
        ```
        
        ### Register an `before_retry` callback
        
        We could also register an `before_retry` callback which will be executed after every failure of the target function if the corresponding retry is not abandoned.
        
        ```py
        class ClientTrackableFailures(ClientWithConfigurableRetryPolicy):
            # `before_retry` could either be a sync function or an async function
            async def _before_retry(self, info: RetryInfo) -> None:
                await self._send_failure_log(info.exception, info.fails)
        
            @retry(
              retry_policy='_retry_policy',
        
              # Similar to `retry_policy`,
              # `before_retry` could either be a Callable or a str
              before_retry='_before_retry'
            )
            async def connect(self):
                await self._connect()
        ```
        
        ### Only retry for certain types of exceptions
        
        ```py
        def retry_policy(info: RetryInfo) -> RetryPolicyStrategy:
            if isinstance(info.exception, (KeyError, ValueError)):
                # If it raises a KeyError or a ValueError, it will not retry.
                return True, 0
        
            # Otherwise, retry immediately
            return False, 0
        
        @retry(retry_policy)
        async def foo():
            # do something that might raise KeyError, ValueError or RuntimeError
            ...
        ```
        
        ## APIs
        
        ### retry(retry_policy, before_retry)(fn)
        
        - **fn** `Callable[[...], Awaitable]` the function to be wrapped. The function should be an async function or normal function returns an awaitable.
        - **retry_policy** `Union[str, RetryPolicy]`
        - **before_retry?** `Optional[Union[str, Callable[[RetryInfo], Optional[Awaitable]]]]` If specified, `before_retry` is called after each failure of `fn` and before the corresponding retry. If the retry is abandoned, `before_retry` will not be executed.
        
        Returns a wrapped function which accepts the same arguments as `fn` and returns an `Awaitable`.
        
        ### RetryPolicy
        
        ```py
        RetryPolicy = Callable[[RetryInfo], Tuple[bool, Union[float, int]]]
        ```
        
        Retry policy is used to determine what to do next after the `fn` fails to do some certain thing.
        
        ```py
        abandon, delay = retry_policy(info)
        ```
        
        - **info** `RetryInfo`
          - **info.fails** `int` is the counter number of how many times function `fn` performs as a failure. If `fn` fails for the first time, then `fails` will be `1`.
          - **info.exception** `Exception` is the exception that `fn` raised.
          - **info.since** `datetime` is the datetime when the first failure happens.
        - If `abandon` is `True`, then aioretry will give up the retry and raise the exception directly, otherwise aioretry will sleep `delay` seconds (`asyncio.sleep(delay)`) before the next retry.
        
        ```py
        def retry_policy(info: RetryInfo):
            if isinstance(info.exception, KeyError):
                # Just raise exceptions of type KeyError
                return True, 0
        
            return False, info.fails * 0.1
        ```
        
        ### Python typings
        
        ```py
        from aioretry import (
            # The type of retry_policy function
            RetryPolicy,
            # The type of the return value of retry_policy function
            RetryPolicyStrategy,
            # The type of before_retry function
            BeforeRetry,
            RetryInfo
        )
        ```
        
        ## Upgrade guide
        
        Since `5.0.0`, aioretry introduces `RetryInfo` as the only parameter of `retry_policy` or `before_retry`
        
        ### 2.x -> 5.x
        
        2.x
        
        ```py
        def retry_policy(fails: int):
            """A policy that gives no chances to retry
            """
        
            return True, 0.1 * fails
        ```
        
        5.x
        
        ```py
        def retry_policy(info: RetryInfo):
            return True, 0.1 * info.fails
        ```
        
        ### 3.x -> 5.x
        
        3.x
        
        ```py
        def before_retry(e: Exception, fails: int):
            ...
        ```
        
        5.x
        
        ```py
        # Change the sequence of the parameters
        def before_retry(info: RetryInfo):
            info.exception
            info.fails
            ...
        ```
        
        ### 4.x -> 5.x
        
        Since `5.0.0`, both `retry_policy` and `before_retry` have only one parameter of type `RetryInfo` respectively.
        
        ## License
        
        [MIT](LICENSE)
        
Keywords: aioretry
Platform: UNKNOWN
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: Implementation :: PyPy
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: License :: OSI Approved :: MIT License
Requires-Python: >=3.7
Description-Content-Type: text/markdown
