{"id":7854,"library":"waiter","title":"Waiter Library for Polling and Retries","description":"Waiter is a lightweight Python library providing utilities for delayed iteration, polling, and retrying operations. It's particularly useful for waiting for external resources, services, or conditions to become ready. The current version is 1.5.1, and it maintains an active release cadence with regular updates.","status":"active","version":"1.5.1","language":"en","source_language":"en","source_url":"https://github.com/coady/waiter","tags":["polling","retry","delay","wait","iteration","async"],"install":[{"cmd":"pip install waiter","lang":"bash","label":"Install stable version"}],"dependencies":[],"imports":[{"note":"Use for delayed iteration over an iterable.","symbol":"wait","correct":"from waiter import wait"},{"note":"Use for polling until a callable returns a truthy value.","symbol":"until","correct":"from waiter import until"},{"note":"Use for retrying a callable until it stops raising exceptions.","symbol":"until_successful","correct":"from waiter import until_successful"}],"quickstart":{"code":"import time\nfrom waiter import until_successful\n\n# Define a function that simulates checking a service or condition\nclass ServiceChecker:\n    def __init__(self):\n        self.attempts = 0\n\n    def check_status(self):\n        self.attempts += 1\n        if self.attempts < 3:\n            # Simulate a temporary failure by raising an exception\n            print(f\"Attempt {self.attempts}: Service not ready yet...\")\n            raise ConnectionError(\"Service not available\")\n        else:\n            # Simulate success after a few attempts\n            print(f\"Attempt {self.attempts}: Service is ready!\")\n            return f\"Service ready after {self.attempts} attempts\"\n\nchecker = ServiceChecker()\nresult = None\ntry:\n    # Use until_successful to retry calling the check_status method.\n    # It will keep retrying until the callable succeeds (doesn't raise an exception)\n    # or the timeout is reached.\n    result = until_successful(\n        checker.check_status,\n        timeout=5,  # Max time to wait in seconds\n        pause=0.5   # Time to wait between retries in seconds\n    )\n    print(f\"Polling successful: {result}\")\nexcept TimeoutError as e:\n    print(f\"Polling failed: {e}\")\nexcept Exception as e:\n    print(f\"An unexpected error occurred: {e}\")","lang":"python","description":"This quickstart demonstrates using `waiter.until_successful` to poll a function that initially fails but eventually succeeds. It illustrates how to define a retriable operation and handle potential `TimeoutError`."},"warnings":[{"fix":"Update your code to use `pause` instead of `sleep_seconds`. For example, `waiter.until(my_func, pause=1)`.","message":"The `sleep_seconds` argument in `waiter.wait`, `until`, and `until_successful` was renamed to `pause` in version 1.3.0.","severity":"breaking","affected_versions":">=1.3.0"},{"fix":"Ensure you provide an iterable object to `waiter.wait`. If you intend to poll a function, use `waiter.until` or `waiter.until_successful` instead. Example: `for _ in waiter.wait(range(10), pause=0.5): ...`","message":"`waiter.wait` expects an *iterable* (e.g., `range`, a list, or a generator) as its first argument, not a callable function. Passing a function will result in a `TypeError`.","severity":"gotcha","affected_versions":"All versions"},{"fix":"If your condition for retrying is a falsy return value, use `waiter.until`. If it's an exception, use `waiter.until_successful`. For example, `until(check_condition, timeout=10)` will retry if `check_condition()` returns `False` or `None`.","message":"`waiter.until_successful` only retries when the target callable *raises an exception*. It does *not* retry if the callable returns a falsy value (e.g., `None` or `False`). For that, you should use `waiter.until`.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Always wrap your `waiter` calls in a `try...except TimeoutError` block to gracefully handle scenarios where the condition isn't met in time.","message":"If the polling condition is not met within the specified `timeout`, `waiter` functions will raise a `TimeoutError`. Forgetting to handle this can lead to unhandled exceptions.","severity":"gotcha","affected_versions":"All versions"}],"env_vars":null,"last_verified":"2026-04-16T00:00:00.000Z","next_check":"2026-07-15T00:00:00.000Z","problems":[{"fix":"Provide an iterable object to `waiter.wait`. If you intended to poll a function for success, use `waiter.until` or `waiter.until_successful`. Correct example: `for _ in waiter.wait(range(5), pause=1): print('Waiting...')`","cause":"You are passing a callable function to `waiter.wait`, which expects an iterable (like `range(N)` or a list).","error":"TypeError: 'function' object is not iterable"},{"fix":"Ensure you pass the function reference (the function name without parentheses) to `until` or `until_successful`. Correct example: `until_successful(my_function, timeout=5)` instead of `until_successful(my_function(), timeout=5)`.","cause":"You are passing the *result* of a function call to `waiter.until` or `waiter.until_successful` instead of the function object itself, or passing a non-callable object.","error":"TypeError: '<callable_name>' object is not callable"},{"fix":"Increase the `timeout` parameter if the operation genuinely takes longer, or decrease `pause` if more frequent checks are needed. Review the logic of your callable to ensure it eventually succeeds. Always catch `TimeoutError` to handle the failure gracefully.","cause":"The target callable for `waiter.until` or `waiter.until_successful` did not meet its success condition (returned a truthy value/stopped raising exceptions) within the `timeout` period.","error":"TimeoutError: Callable did not return a truthy value or stop raising exceptions within X seconds"}]}