{"id":4319,"library":"waiting","title":"Waiting for Stuff","description":"The 'waiting' library provides a simple utility for busy-waiting, where the program pauses execution until a specified predicate function returns `True`. It supports various modes, including timeouts, custom sleep intervals, exponential backoff, and aggregation of multiple predicates (ANY/ALL). The current version is 1.5.0, released in August 2024, with a sporadic but recently updated release cadence.","status":"active","version":"1.5.0","language":"en","source_language":"en","source_url":"https://github.com/getslash/waiting","tags":["utility","waiting","polling","timeout","busy-waiting"],"install":[{"cmd":"pip install waiting","lang":"bash","label":"Install stable version"}],"dependencies":[],"imports":[{"note":"The primary function to wait for a predicate to become true.","symbol":"wait","correct":"from waiting import wait"},{"note":"Exception raised when a wait operation exceeds its specified timeout.","symbol":"TimeoutExpired","correct":"from waiting import wait, TimeoutExpired"},{"note":"Used with 'wait' to pause until any of a list of predicates returns true.","symbol":"ANY","correct":"from waiting import wait, ANY"},{"note":"Used with 'wait' to pause until all of a list of predicates return true.","symbol":"ALL","correct":"from waiting import wait, ALL"}],"quickstart":{"code":"import time\nfrom waiting import wait, TimeoutExpired\n\ndef check_condition():\n    # Simulate a condition that eventually becomes true\n    if not hasattr(check_condition, 'counter'):\n        check_condition.counter = 0\n    check_condition.counter += 1\n    print(f\"Checking condition (attempt {check_condition.counter})...\")\n    return check_condition.counter >= 3\n\nprint(\"Starting to wait...\")\ntry:\n    # Wait for the condition for a maximum of 5 seconds, polling every 0.5 seconds\n    # Use 'waiting_for' for more descriptive timeout messages\n    result = wait(\n        check_condition,\n        timeout_seconds=5,\n        sleep_seconds=0.5,\n        waiting_for=\"the counter to reach 3\"\n    )\n    print(f\"Condition met! Result: {result}\")\nexcept TimeoutExpired as e:\n    print(f\"Wait timed out: {e}\")\n\nprint(\"--- Demonstrating TimeoutExpired without waiting_for ---\")\ntry:\n    wait(lambda: False, timeout_seconds=0.1)\nexcept TimeoutExpired as e:\n    print(f\"TimeoutExpired message (less descriptive): {e}\")","lang":"python","description":"This quickstart demonstrates the core `wait` function, showing how to wait for a predicate to become true, handling timeouts, and customizing polling intervals. It also highlights the benefit of the `waiting_for` argument for clearer error messages."},"warnings":[{"fix":"For asynchronous contexts, consider `asyncio.sleep()` or async-compatible polling libraries. If `waiting` must be used, run it in a separate thread or process to avoid blocking the main event loop.","message":"The `wait` function is a blocking operation. In asynchronous Python applications (e.g., using `asyncio`), directly calling `wait` will block the entire event loop, potentially freezing your application.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Always use the `waiting_for` argument in `wait()` calls to provide a descriptive message. This message will be included in the `TimeoutExpired` exception, greatly aiding debugging. Example: `wait(predicate, timeout_seconds=..., waiting_for=\"database to be ready\")`.","message":"By default, the `TimeoutExpired` exception provides a generic message. When dealing with complex waiting conditions, this can make debugging difficult.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Ensure that predicates used with `ANY` or `ALL` are idempotent or that their side effects are not critical to occur on every single poll once satisfied. For predicates requiring continuous side effects, wrap them in a single predicate or handle side effects outside the predicate function.","message":"When using `ANY` or `ALL` with multiple predicates, the library's documentation notes that it does not call a predicate once it has been satisfied (for efficiency). If a predicate has side effects that are expected to occur on every poll, this behavior for `ANY`/`ALL` could be unexpected.","severity":"gotcha","affected_versions":"All versions"}],"env_vars":null,"last_verified":"2026-04-11T00:00:00.000Z","next_check":"2026-07-10T00:00:00.000Z"}