| import functools |
| from time import perf_counter, sleep |
| from typing import Callable, TypeVar |
|
|
| from pip._vendor.typing_extensions import ParamSpec |
|
|
| T = TypeVar("T") |
| P = ParamSpec("P") |
|
|
|
|
| def retry( |
| wait: float, stop_after_delay: float |
| ) -> Callable[[Callable[P, T]], Callable[P, T]]: |
| """Decorator to automatically retry a function on error. |
| |
| If the function raises, the function is recalled with the same arguments |
| until it returns or the time limit is reached. When the time limit is |
| surpassed, the last exception raised is reraised. |
| |
| :param wait: The time to wait after an error before retrying, in seconds. |
| :param stop_after_delay: The time limit after which retries will cease, |
| in seconds. |
| """ |
|
|
| def wrapper(func: Callable[P, T]) -> Callable[P, T]: |
|
|
| @functools.wraps(func) |
| def retry_wrapped(*args: P.args, **kwargs: P.kwargs) -> T: |
| |
| |
| start_time = perf_counter() |
| while True: |
| try: |
| return func(*args, **kwargs) |
| except Exception: |
| if perf_counter() - start_time > stop_after_delay: |
| raise |
| sleep(wait) |
|
|
| return retry_wrapped |
|
|
| return wrapper |
|
|