### Install Tenacity Source: https://tenacity.readthedocs.io/en/latest/index.html Command to install the library via pip. ```bash $ pip install tenacity ``` -------------------------------- ### Open Changelog Template with Reno Source: https://tenacity.readthedocs.io/en/latest/index.html Use this command to open a template file in your editor for creating a new changelog entry. Ensure you have tox installed and configured. ```bash tox -e reno -- new some-slug-for-my-change --edit ``` -------------------------------- ### Wait Incrementing Strategy Source: https://tenacity.readthedocs.io/en/latest/api.html Waits an incremental amount of time after each attempt, starting from a specified value and increasing by a set increment. ```APIDOC ### Class: `wait_incrementing` Wait an incremental amount of time after each attempt. Starting at a starting value and incrementing by a value for each attempt (and restricting the upper limit to some maximum value). Parameters: - `start` (Union[int, float, datetime.timedelta]): The initial wait time. - `increment` (Union[int, float, datetime.timedelta]): The amount to increment the wait time by for each attempt. - `max` (Union[int, float, datetime.timedelta]): The maximum wait time. ``` -------------------------------- ### Incrementing Wait Strategy Source: https://tenacity.readthedocs.io/en/latest/api.html Waits an incremental amount of time after each attempt, starting from a specified value and increasing by a set increment, up to a maximum. Useful for gradually increasing retry delays. ```python from tenacity import wait_incrementing # Example usage (not a runnable snippet, just configuration) wait_incrementing(start=0, increment=100, max=1000) ``` -------------------------------- ### Combine Retry Conditions Source: https://tenacity.readthedocs.io/en/latest/index.html Combine multiple retry conditions using the bitwise OR operator (`|`) to create complex retry logic. This example retries if the result is None or if any exception occurs. ```python def is_none_p(value): """Return True if value is None""" return value is None @retry(retry=(retry_if_result(is_none_p) | retry_if_exception_type())) def might_return_none(): print("Retry forever ignoring Exceptions with no wait if return value is None") ``` -------------------------------- ### Log Before Retry Attempts Source: https://tenacity.readthedocs.io/en/latest/index.html Use the `before_log` callback to log messages before each retry attempt. Configure a logger and specify the logging level. ```python import logging import sys logging.basicConfig(stream=sys.stderr, level=logging.DEBUG) logger = logging.getLogger(__name__) @retry(stop=stop_after_attempt(3), before=before_log(logger, logging.DEBUG)) def raise_my_exception(): raise MyException("Fail") ``` -------------------------------- ### Log After Failed Retry Attempts Source: https://tenacity.readthedocs.io/en/latest/index.html Use the `after_log` callback to log messages after a call fails and a retry is about to occur. This helps track failed attempts. ```python import logging import sys logging.basicConfig(stream=sys.stderr, level=logging.DEBUG) logger = logging.getLogger(__name__) @retry(stop=stop_after_attempt(3), after=after_log(logger, logging.DEBUG)) def raise_my_exception(): raise MyException("Fail") ``` -------------------------------- ### tenacity.after Source: https://tenacity.readthedocs.io/en/latest/api.html Strategy functions executed after a retry attempt. ```APIDOC ## tenacity.after.after_log ### Description Logs the finished attempt to a specified logger. ### Parameters - **logger** (logging.Logger) - Required - The logger instance. - **log_level** (int) - Required - The logging level. - **sec_format** (str) - Optional - Format string for seconds (default: '%0.3f'). ``` -------------------------------- ### Wait Base Class Source: https://tenacity.readthedocs.io/en/latest/api.html Abstract base class for all wait strategies. ```APIDOC ## Wait Functions Those functions can be used as the wait keyword argument of `tenacity.retry()`. ### Class: `wait_base` Abstract base class for wait strategies. ``` -------------------------------- ### Exponential Backoff with Jitter Source: https://tenacity.readthedocs.io/en/latest/api.html Implements exponential backoff with added random jitter. The wait time is calculated as min(initial * 2**n + random.uniform(0, jitter), maximum). Suitable for resolving contention between multiple processes. ```python from tenacity import wait_exponential_jitter # Example usage (not a runnable snippet, just configuration) wait_exponential_jitter(initial=1, max=60, exp_base=2, jitter=1) ``` -------------------------------- ### Wait Combine Strategy Source: https://tenacity.readthedocs.io/en/latest/api.html Combines several waiting strategies into one. ```APIDOC ### Class: `wait_combine` Combine several waiting strategies. ``` -------------------------------- ### Implement custom before_sleep callback Source: https://tenacity.readthedocs.io/en/latest/index.html Define a custom function to execute before sleeping during retry attempts, useful for logging state information. ```python import logging logging.basicConfig(stream=sys.stderr, level=logging.DEBUG) logger = logging.getLogger(__name__) def my_before_sleep(retry_state): if retry_state.attempt_number < 1: loglevel = logging.INFO else: loglevel = logging.WARNING logger.log( loglevel, 'Retrying %s: attempt %s ended with: %s', retry_state.fn, retry_state.attempt_number, retry_state.outcome) @retry(stop=stop_after_attempt(3), before_sleep=my_before_sleep) def raise_my_exception(): raise MyException("Fail") try: raise_my_exception() except RetryError: pass ``` -------------------------------- ### Configure wait strategies between retries Source: https://tenacity.readthedocs.io/en/latest/index.html Defines various waiting behaviors including fixed, random, exponential, and chained delays. ```python @retry(wait=wait_fixed(2)) def wait_2_s(): print("Wait 2 second between retries") raise Exception ``` ```python @retry(wait=wait_random(min=1, max=2)) def wait_random_1_to_2_s(): print("Randomly wait 1 to 2 seconds between retries") raise Exception ``` ```python @retry(wait=wait_exponential(multiplier=1, min=4, max=10)) def wait_exponential_1(): print("Wait 2^x * 1 second between each retry starting with 4 seconds, then up to 10 seconds, then 10 seconds afterwards") raise Exception ``` ```python @retry(wait=wait_fixed(3) + wait_random(0, 2)) def wait_fixed_jitter(): print("Wait at least 3 seconds, and add up to 2 seconds of random delay") raise Exception ``` ```python @retry(wait=wait_random_exponential(multiplier=1, max=60)) def wait_exponential_jitter(): print("Randomly wait up to 2^x * 1 seconds between each retry until the range reaches 60 seconds, then randomly up to 60 seconds afterwards") raise Exception ``` ```python @retry(wait=wait_chain(*[wait_fixed(3) for i in range(3)] + [wait_fixed(7) for i in range(2)] + [wait_fixed(9)])) def wait_fixed_chained(): print("Wait 3s for 3 attempts, 7s for the next 2 attempts and 9s for all attempts thereafter") raise Exception ``` -------------------------------- ### Chaining Wait Strategies Source: https://tenacity.readthedocs.io/en/latest/api.html Chain multiple wait strategies together. The last strategy is used if all preceding ones are exhausted. Useful for complex retry logic. ```python from tenacity import retry, wait_fixed, wait_chain @retry(wait=wait_chain(*[wait_fixed(1) for i in range(3)] + [wait_fixed(2) for j in range(5)] + [wait_fixed(5) for k in range(4)])) def wait_chained(): print("Wait 1s for 3 attempts, 2s for 5 attempts and 5s thereafter.") ``` -------------------------------- ### Retry code blocks with context managers Source: https://tenacity.readthedocs.io/en/latest/index.html Use a for loop combined with a context manager to retry arbitrary code blocks without wrapping them in a function. ```python from tenacity import Retrying, RetryError, stop_after_attempt try: for attempt in Retrying(stop=stop_after_attempt(3)): with attempt: raise Exception('My code is failing!') except RetryError: pass ``` ```python from tenacity import AsyncRetrying, RetryError, stop_after_attempt async def function(): try: async for attempt in AsyncRetrying(stop=stop_after_attempt(3)): with attempt: raise Exception('My code is failing!') except RetryError: pass ``` -------------------------------- ### Wait Exponential Strategy Source: https://tenacity.readthedocs.io/en/latest/api.html Applies exponential backoff with customizable multiplier, base, and limits. Suitable for resources unavailable for unknown durations, not for contention. ```APIDOC ### Class: `wait_exponential` Wait strategy that applies exponential backoff. It allows for a customized multiplier and an ability to restrict the upper and lower limits to some maximum and minimum value. The intervals are fixed (i.e. there is no jitter), so this strategy is suitable for balancing retries against latency when a required resource is unavailable for an unknown duration, but _not_ suitable for resolving contention between multiple processes for a shared resource. Use wait_random_exponential for the latter case. Parameters: - `multiplier` (Union[int, float]): The multiplier for the exponential backoff. - `max` (Union[int, float, datetime.timedelta]): The maximum wait time. - `exp_base` (Union[int, float]): The base for the exponential calculation. - `min` (Union[int, float, datetime.timedelta]): The minimum wait time. ``` -------------------------------- ### Wait None Strategy Source: https://tenacity.readthedocs.io/en/latest/api.html A strategy that does not wait at all before retrying. ```APIDOC ### Class: `wait_none` Wait strategy that doesn’t wait at all before retrying. ``` -------------------------------- ### Exponential Backoff Wait Strategy Source: https://tenacity.readthedocs.io/en/latest/api.html Applies exponential backoff with customizable multiplier, min, and max wait times. Suitable for balancing retries against latency when a resource is unavailable for an unknown duration. ```python from tenacity import wait_exponential # Example usage (not a runnable snippet, just configuration) wait_exponential(multiplier=1, max=100, exp_base=2, min=0) ``` -------------------------------- ### None Wait Strategy Source: https://tenacity.readthedocs.io/en/latest/api.html A strategy that does not wait at all before retrying. Use with caution as it can lead to rapid, continuous retries. ```python from tenacity import wait_none # Example usage (not a runnable snippet, just configuration) wait_none() ``` -------------------------------- ### Wait Exponential Jitter Strategy Source: https://tenacity.readthedocs.io/en/latest/api.html Applies exponential backoff with jitter, suitable for resolving contention. Wait time is calculated as min(initial * 2**n + random.uniform(0, jitter), maximum). ```APIDOC ### Class: `wait_exponential_jitter` Wait strategy that applies exponential backoff and jitter. It allows for a customized initial wait, maximum wait and jitter. This implements the strategy described here: https://cloud.google.com/storage/docs/retry-strategy The wait time is min(initial * 2**n + random.uniform(0, jitter), maximum) where n is the retry count. Parameters: - `initial` (float): The initial wait time. - `max` (float): The maximum wait time. - `exp_base` (float): The base for the exponential calculation. - `jitter` (float): The jitter to add to the wait time. ``` -------------------------------- ### Wait Random Exponential Strategy Source: https://tenacity.readthedocs.io/en/latest/api.html Provides a random wait with exponentially widening windows, suitable for mediating contention in distributed systems. Uses the 'Full Jitter' algorithm. ```APIDOC ### Class: `wait_random_exponential` Random wait with exponentially widening window. An exponential backoff strategy used to mediate contention between multiple uncoordinated processes for a shared resource in distributed systems. This is the sense in which “exponential backoff” is meant in e.g. Ethernet networking, and corresponds to the “Full Jitter” algorithm described in this blog post: https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/ Each retry occurs at a random time in a geometrically expanding interval. It allows for a custom multiplier and an ability to restrict the upper limit of the random interval to some maximum value. Example: ```python wait_random_exponential(multiplier=0.5, # initial window 0.5s max=60) # max 60s timeout ``` When waiting for an unavailable resource to become available again, as opposed to trying to resolve contention for a shared resource, the wait_exponential strategy (which uses a fixed interval) may be preferable. Parameters: - `multiplier` (Union[int, float]): The multiplier for the exponential backoff. - `max` (Union[int, float, datetime.timedelta]): The maximum wait time. - `exp_base` (Union[int, float]): The base for the exponential calculation. - `min` (Union[int, float, datetime.timedelta]): The minimum wait time. ``` -------------------------------- ### Log Before Sleep Interval Source: https://tenacity.readthedocs.io/en/latest/index.html Use `before_sleep_log` to log messages specifically before the wait interval between retries. This is useful for monitoring delays. ```python import logging import sys logging.basicConfig(stream=sys.stderr, level=logging.DEBUG) logger = logging.getLogger(__name__) @retry(stop=stop_after_attempt(3), before_sleep=before_sleep_log(logger, logging.DEBUG)) def raise_my_exception(): raise MyException("Fail") ``` -------------------------------- ### Random Exponential Wait Strategy Source: https://tenacity.readthedocs.io/en/latest/api.html Provides random waits within an exponentially widening window. Ideal for mediating contention for a shared resource in distributed systems, corresponding to the 'Full Jitter' algorithm. ```python from tenacity import wait_random_exponential # Example usage (not a runnable snippet, just configuration) wait_random_exponential(multiplier=0.5, max=60) # Initial window 0.5s, max 60s ``` -------------------------------- ### Wait Fixed Strategy Source: https://tenacity.readthedocs.io/en/latest/api.html Waits a fixed amount of time between each retry. ```APIDOC ### Class: `wait_fixed` Wait strategy that waits a fixed amount of time between each retry. Parameters: - `wait` (Union[int, float, datetime.timedelta]): The fixed amount of time to wait. ``` -------------------------------- ### Fixed Wait Strategy Source: https://tenacity.readthedocs.io/en/latest/api.html Waits a fixed amount of time between each retry. Simple and predictable. ```python from tenacity import wait_fixed # Example usage (not a runnable snippet, just configuration) wait_fixed(10) # Waits 10 seconds between retries ``` -------------------------------- ### Wait Random Strategy Source: https://tenacity.readthedocs.io/en/latest/api.html Waits a random amount of time within a specified minimum and maximum range. ```APIDOC ### Class: `wait_random` Wait strategy that waits a random amount of time between min/max. Parameters: - `min` (Union[int, float, datetime.timedelta]): The minimum wait time. - `max` (Union[int, float, datetime.timedelta]): The maximum wait time. ``` -------------------------------- ### tenacity.Retrying Source: https://tenacity.readthedocs.io/en/latest/api.html The main controller class for managing retry attempts, including stop, wait, and retry strategies. ```APIDOC ## tenacity.Retrying ### Description Retrying controller class that manages the retry lifecycle. ### Parameters - **sleep** (Callable) - Optional - Sleep strategy (default: sleep). - **stop** (StopBaseT) - Optional - Stop strategy (default: stop_never). - **wait** (WaitBaseT) - Optional - Wait strategy (default: wait_none). - **retry** (RetryBaseT) - Optional - Retry condition (default: retry_if_exception_type). - **before** (Callable) - Optional - Function called before an attempt. - **after** (Callable) - Optional - Function called after an attempt. - **before_sleep** (Callable) - Optional - Function called before sleeping. - **reraise** (bool) - Optional - Whether to reraise the exception. - **retry_error_cls** (Type) - Optional - Exception class to raise on failure. - **retry_error_callback** (Callable) - Optional - Callback function on final failure. ``` -------------------------------- ### Stop retrying based on attempts or delay Source: https://tenacity.readthedocs.io/en/latest/index.html Configures stop conditions to limit the number of retries or the total duration. ```python @retry(stop=stop_after_attempt(7)) def stop_after_7_attempts(): print("Stopping after 7 attempts") raise Exception ``` ```python @retry(stop=stop_after_delay(10)) def stop_after_10_s(): print("Stopping after 10 seconds") raise Exception ``` ```python @retry(stop=(stop_after_delay(10) | stop_after_attempt(5))) def stop_after_10_s_or_5_retries(): print("Stopping after 10 seconds or 5 retries") raise Exception ``` -------------------------------- ### Retry on Specific Exceptions Source: https://tenacity.readthedocs.io/en/latest/index.html Use `retry_if_exception_type` to retry only when specific exceptions occur. Other exceptions will be raised immediately. ```python class ClientError(Exception): """Some type of client error.""" @retry(retry=retry_if_exception_type(IOError)) def might_io_error(): print("Retry forever with no wait if an IOError occurs, raise any other errors") raise Exception @retry(retry=retry_if_not_exception_type(ClientError)) def might_client_error(): print("Retry forever with no wait if any error other than ClientError occurs. Immediately raise ClientError.") raise Exception ``` -------------------------------- ### Implement basic retry logic Source: https://tenacity.readthedocs.io/en/latest/index.html Uses the @retry decorator to automatically retry a function when an exception occurs. ```python import random from tenacity import retry @retry def do_something_unreliable(): if random.randint(0, 10) > 1: raise IOError("Broken sauce, everything is hosed!!!111one") else: return "Awesome sauce!" print(do_something_unreliable()) ``` -------------------------------- ### Random Wait Strategy Source: https://tenacity.readthedocs.io/en/latest/api.html Waits a random amount of time between a specified minimum and maximum value. Useful for avoiding synchronized retries in distributed systems. ```python from tenacity import wait_random # Example usage (not a runnable snippet, just configuration) wait_random(min=1, max=5) # Waits between 1 and 5 seconds ``` -------------------------------- ### tenacity.nap Source: https://tenacity.readthedocs.io/en/latest/api.html Sleep strategies used to delay execution between retry attempts. ```APIDOC ## tenacity.nap.sleep ### Description Delays execution for a given number of seconds. ### Parameters - **seconds** (float) - Required - Number of seconds to sleep. ``` -------------------------------- ### Tenacity Stop Functions Source: https://tenacity.readthedocs.io/en/latest/api.html Functions that can be used as the 'stop' keyword argument of tenacity.retry(). These define the conditions under which retries should cease. ```APIDOC ## Stop Functions Those functions can be used as the stop keyword argument of `tenacity.retry()`. ### `stop_after_attempt(max_attempt_number: int)` Stop when the previous attempt >= max_attempt. ### `stop_after_delay(max_delay: Union[int, float, datetime.timedelta])` Stop when the time from the first attempt >= limit. ### `stop_all(*stops)` Stop if all the stop conditions are valid. ### `stop_any(*stops)` Stop if any of the stop condition is valid. ### `stop_base` Abstract base class for stop strategies. ### `stop_when_event_set(event: threading.Event)` Stop when the given event is set. ``` -------------------------------- ### Wait Chain Strategy Source: https://tenacity.readthedocs.io/en/latest/api.html Chains multiple waiting strategies together. The last strategy is used if all preceding strategies are exhausted. ```APIDOC ### Class: `wait_chain` Chain two or more waiting strategies. If all strategies are exhausted, the very last strategy is used thereafter. For example: ```python @retry(wait=wait_chain(*[wait_fixed(1) for i in range(3)] + [wait_fixed(2) for j in range(5)] + [wait_fixed(5) for k in range(4)])) def wait_chained(): print("Wait 1s for 3 attempts, 2s for 5 attempts and 5s thereafter.") ``` ``` -------------------------------- ### Tenacity Retry Functions Source: https://tenacity.readthedocs.io/en/latest/api.html Functions that can be used as the 'retry' keyword argument of tenacity.retry(). These define the conditions under which a retry should occur. ```APIDOC ## Retry Functions Those functions can be used as the retry keyword argument of `tenacity.retry()`. ### `retry_all(*retries)` Retries if all the retries condition are valid. ### `retry_any(*retries)` Retries if any of the retries condition is valid. ### `retry_base` Abstract base class for retry strategies. ### `retry_if_exception(predicate: Callable[[BaseException], bool])` Retry strategy that retries if an exception verifies a predicate. ### `retry_if_exception_cause_type(exception_types: Union[Type[BaseException], Tuple[Type[BaseException], ...]] = )` Retries if any of the causes of the raised exception is of one or more types. The check on the type of the cause of the exception is done recursively (until finding an exception in the chain that has no __cause__) ### `retry_if_exception_message(message: Optional[str] = None, match: Optional[str] = None)` Retries if an exception message equals or matches. ### `retry_if_exception_type(exception_types: Union[Type[BaseException], Tuple[Type[BaseException], ...]] = )` Retries if an exception has been raised of one or more types. ### `retry_if_not_exception_message(message: Optional[str] = None, match: Optional[str] = None)` Retries until an exception message equals or matches. ### `retry_if_not_exception_type(exception_types: Union[Type[BaseException], Tuple[Type[BaseException], ...]] = )` Retries except an exception has been raised of one or more types. ### `retry_if_not_result(predicate: Callable[[Any], bool])` Retries if the result refutes a predicate. ### `retry_if_result(predicate: Callable[[Any], bool])` Retries if the result verifies a predicate. ### `retry_unless_exception_type(exception_types: Union[Type[BaseException], Tuple[Type[BaseException], ...]] = )` Retries until an exception is raised of one or more types. ``` -------------------------------- ### tenacity.retry Source: https://tenacity.readthedocs.io/en/latest/api.html The primary decorator used to wrap functions with a Retrying object to enable retry logic. ```APIDOC ## tenacity.retry ### Description Wrap a function with a new Retrying object to apply retry behavior. ### Parameters - **dargs** (positional arguments) - Optional - Positional arguments passed to the Retrying object. - **dkw** (keyword arguments) - Optional - Keyword arguments passed to the Retrying object. ``` -------------------------------- ### Custom Callback to Return Last Value Source: https://tenacity.readthedocs.io/en/latest/index.html Define a custom callback function that accepts `retry_state` and can return the result of the last attempt. This can be used with `retry_error_callback` to control the final return value when retries fail. ```python def return_last_value(retry_state): """return the result of the last call attempt""" return retry_state.outcome.result() def is_false(value): """Return True if value is False""" return value is False # will return False after trying 3 times to get a different result @retry(stop=stop_after_attempt(3), retry_error_callback=return_last_value, retry=retry_if_result(is_false)) def eventually_return_false(): return False ``` -------------------------------- ### Modify retry arguments at runtime Source: https://tenacity.readthedocs.io/en/latest/index.html Use retry_with to override decorator parameters dynamically or instantiate Retrying directly for variable-based configuration. ```python @retry(stop=stop_after_attempt(3)) def raise_my_exception(): raise MyException("Fail") try: raise_my_exception.retry_with(stop=stop_after_attempt(4))() except Exception: pass print(raise_my_exception.retry.statistics) ``` ```python def never_good_enough(arg1): raise Exception('Invalid argument: {}'.format(arg1)) def try_never_good_enough(max_attempts=3): retryer = Retrying(stop=stop_after_attempt(max_attempts), reraise=True) retryer(never_good_enough, 'I really do try') ``` -------------------------------- ### Retry asynchronous functions Source: https://tenacity.readthedocs.io/en/latest/index.html Apply retry logic to asyncio or Tornado coroutines, including support for alternative event loops. ```python @retry async def my_async_function(loop): await loop.getaddrinfo('8.8.8.8', 53) ``` ```python @retry @tornado.gen.coroutine def my_async_function(http_client, url): yield http_client.fetch(url) ``` ```python @retry(sleep=trio.sleep) async def my_async_function(loop): await asks.get('https://example.org') ``` -------------------------------- ### Access Retry Statistics Source: https://tenacity.readthedocs.io/en/latest/index.html The `retry` attribute attached to a decorated function provides access to statistics about the retry attempts made. ```python @retry(stop=stop_after_attempt(3)) def raise_my_exception(): raise MyException("Fail") try: raise_my_exception() except Exception: pass print(raise_my_exception.retry.statistics) ``` -------------------------------- ### Set results in retry state Source: https://tenacity.readthedocs.io/en/latest/index.html Manually set a result on the retry state to enable strategies like retry_if_result. ```python from tenacity import AsyncRetrying, retry_if_result async def function(): async for attempt in AsyncRetrying(retry=retry_if_result(lambda x: x < 3)): with attempt: result = 1 # Some complex calculation, function call, etc. if not attempt.retry_state.outcome.failed: attempt.retry_state.set_result(result) return result ``` -------------------------------- ### Reraise Last Exception on Final Failure Source: https://tenacity.readthedocs.io/en/latest/index.html Set `reraise=True` to have the last encountered exception raised at the end of the stack trace when retries are exhausted. This makes debugging easier by showing the original error prominently. ```python @retry(reraise=True, stop=stop_after_attempt(3)) def raise_my_exception(): raise MyException("Fail") try: raise_my_exception() except MyException: # timed out retrying pass ``` -------------------------------- ### Explicitly Raise TryAgain for Retry Source: https://tenacity.readthedocs.io/en/latest/index.html Raise the `TryAgain` exception within your function to explicitly signal that a retry should occur. This is useful for conditional retries not covered by other decorators. ```python @retry def do_something(): result = something_else() if result == 23: raise TryAgain ``` -------------------------------- ### Retry forever without waiting Source: https://tenacity.readthedocs.io/en/latest/index.html Default behavior when using the @retry decorator without arguments. ```python @retry def never_gonna_give_you_up(): print("Retry forever ignoring Exceptions, don't wait between retries") raise Exception ``` -------------------------------- ### Retry Based on Function Result Source: https://tenacity.readthedocs.io/en/latest/index.html Use `retry_if_result` to retry only if the function's return value meets a specific condition. The condition function should return True to trigger a retry. ```python def is_none_p(value): """Return True if value is None""" return value is None @retry(retry=retry_if_result(is_none_p)) def might_return_none(): print("Retry with no wait if return value is None") ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.