Async & eventual assertions¶
Poll a callable until an assertion passes or the timeout expires. Start with eventually() on a
callable value, chain the assertion you expect to eventually hold, and await the result. Use
eventually_sync() for the same polling without an event loop. See
Testing for usage.
eventually ¶
eventually(
*,
timeout: float = 5.0,
interval: float = 0.5,
ignoring: type[Exception] | RetriedInfo = (),
trace: bool = True,
) -> AsyncAssertionBuilder
Switch to async polling mode for eventual-consistency assertions.
The current val must be a callable (sync or async). Returns an
AsyncAssertionBuilder whose assertion
methods are coroutines that poll val() until the assertion passes or
timeout expires.
By default only a failing assertion is retried: any other exception raised by val() itself
propagates immediately. An AssertionError from val() reaches the same place a failing
assertion does and is retried the same way, which the timeout message names. A probe that
signals "not ready yet" by raising something else (a connection refused while a service boots,
a record not yet visible) can be retried too by listing those types in ignoring.
Polling itself is always strict - retrying requires hard failures - but the final timeout
failure honors the builder's mode: inside
soft_assertions() it is collected instead of raised,
and under assert_warn() it is logged.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
timeout
|
float
|
maximum seconds to keep retrying (default |
5.0
|
interval
|
float
|
seconds between retries (default |
0.5
|
ignoring
|
type[Exception] | RetriedInfo
|
an |
()
|
trace
|
bool
|
record a |
True
|
Examples:
Usage:
import asyncio
from assertpy import assert_that
counter = {"n": 0}
def get_count():
counter["n"] += 1
return counter["n"]
asyncio.run(
assert_that(get_count).eventually(timeout=2).is_equal_to(3)
)
Retry a probe that raises while the system under test is not ready yet:
await assert_that(get_order).eventually(timeout=10, ignoring=ConnectionError).has_status("PAID")
# or configure fluently on the returned builder
await assert_that(get_order).eventually().within(10).ignoring(ConnectionError).has_status("PAID")
Returns:
| Name | Type | Description |
|---|---|---|
AsyncAssertionBuilder |
AsyncAssertionBuilder
|
an async builder whose assertion methods are awaitable |
Raises:
| Type | Description |
|---|---|
TypeError
|
if |
ValueError
|
if |
Source code in assertpy/assertpy.py
2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 | |
eventually_sync ¶
eventually_sync(
*,
timeout: float = 5.0,
interval: float = 0.5,
ignoring: type[Exception] | RetriedInfo = (),
trace: bool = True,
) -> SyncAssertionBuilder
Switch to blocking polling mode for eventual-consistency assertions, without asyncio.
The synchronous sibling of eventually():
the current val must be a sync callable, and the returned
SyncAssertionBuilder exposes assertion methods
that block the calling thread (via time.sleep) while polling val() until the
assertion passes or timeout expires - no event loop and no await needed. A probe
that returns an awaitable raises TypeError; poll async probes with eventually().
Retry, failure-mode, and diagnostics semantics are identical to eventually(): only a
failing assertion (or an exception type listed in ignoring) is retried, the final
timeout failure honors the builder's soft/warn mode, and it carries the same
PollTrace flight recorder.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
timeout
|
float
|
maximum seconds to keep retrying (default |
5.0
|
interval
|
float
|
seconds between retries (default |
0.5
|
ignoring
|
type[Exception] | RetriedInfo
|
an |
()
|
trace
|
bool
|
record a |
True
|
Examples:
Usage:
from assertpy import assert_that
counter = {"n": 0}
def get_count():
counter["n"] += 1
return counter["n"]
assert_that(get_count).eventually_sync(timeout=2, interval=0.1).is_equal_to(3)
Retry a probe that raises while the system under test is not ready yet:
assert_that(get_order).eventually_sync(timeout=10, ignoring=ConnectionError).has_status("PAID")
# or configure fluently on the returned builder
assert_that(get_order).eventually_sync().within(10).ignoring(ConnectionError).has_status("PAID")
Returns:
| Name | Type | Description |
|---|---|---|
SyncAssertionBuilder |
SyncAssertionBuilder
|
a blocking builder whose assertion methods poll on call |
Raises:
| Type | Description |
|---|---|
TypeError
|
if |
ValueError
|
if |
Source code in assertpy/assertpy.py
2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 | |
AsyncAssertionBuilder ¶
AsyncAssertionBuilder(
func: Callable,
*,
builder_func: Callable,
description: str = "",
timeout: float = 5.0,
interval: float = 0.5,
ignoring: tuple[type[Exception], ...] = (),
kind: str | None = None,
logger: object = None,
trace: bool = True,
steps: tuple[_Step, ...] = (),
)
Async assertion builder that polls a callable until an assertion passes or timeout expires.
Do not instantiate directly; use eventually() instead.
A chain records the calls made on it and runs them together when awaited, so the wait covers every
link rather than only the first. The four coroutine methods below make it a coroutine to
asyncio.run() and Task, which take nothing else below 3.15.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
func
|
Callable
|
a sync or async callable that produces the value to test |
required |
builder_func
|
Callable
|
factory function to create assertion builders (receives |
required |
description
|
str
|
optional error description forwarded to the builder |
''
|
timeout
|
float
|
maximum seconds to keep retrying |
5.0
|
interval
|
float
|
seconds between retries |
0.5
|
ignoring
|
tuple[type[Exception], ...]
|
exception types the polling loop retries instead of propagating |
()
|
kind
|
str | None
|
the failure mode of the final timeout failure ( |
None
|
logger
|
object
|
the logger for |
None
|
trace
|
bool
|
record a |
True
|
Source code in assertpy/async_assertions.py
within ¶
Override the timeout (in seconds).
Infinity, or a number past the float range, retries until the assertion passes.
Raises:
| Type | Description |
|---|---|
TypeError
|
if |
ValueError
|
if |
Source code in assertpy/async_assertions.py
every ¶
Override the polling interval (in seconds).
Raises:
| Type | Description |
|---|---|
TypeError
|
if |
ValueError
|
if |
Source code in assertpy/async_assertions.py
ignoring ¶
Replace the exception types the polling loop retries instead of propagating.
Examples:
Usage:
await assert_that(get_order).eventually().within(10).ignoring(ConnectionError).has_status("PAID")
Raises:
| Type | Description |
|---|---|
TypeError
|
if any argument is not an |
Source code in assertpy/async_assertions.py
SyncAssertionBuilder ¶
SyncAssertionBuilder(
func: Callable,
*,
builder_func: Callable,
description: str = "",
timeout: float = 5.0,
interval: float = 0.5,
ignoring: tuple[type[Exception], ...] = (),
kind: str | None = None,
logger: object = None,
trace: bool = True,
steps: tuple[_Step, ...] = (),
last: Any = None,
)
Blocking assertion builder that polls a sync callable until an assertion passes or timeout expires.
Do not instantiate directly; use
eventually_sync() instead.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
func
|
Callable
|
a sync callable that produces the value to test (an async probe raises |
required |
builder_func
|
Callable
|
factory function to create assertion builders (receives |
required |
description
|
str
|
optional error description forwarded to the builder |
''
|
timeout
|
float
|
maximum seconds to keep retrying |
5.0
|
interval
|
float
|
seconds between retries |
0.5
|
ignoring
|
tuple[type[Exception], ...]
|
exception types the polling loop retries instead of propagating |
()
|
kind
|
str | None
|
the failure mode of the final timeout failure ( |
None
|
logger
|
object
|
the logger for |
None
|
trace
|
bool
|
record a |
True
|
Source code in assertpy/async_assertions.py
val
property
¶
The value the last passing poll saw.
Declared on the class rather than left to __getattr__, which answers every other name with a
polling call: reading .val off a chain would otherwise poll once and hand back a function.
Before anything has passed there is no such value, and __getattr__ says so. A raise here
would not: Python falls back to __getattr__ whenever an attribute lookup ends in
AttributeError, property included, so the message would have been swallowed and answered with
a polling call all the same.
within ¶
Override the timeout (in seconds).
Infinity, or a number past the float range, retries until the assertion passes.
Raises:
| Type | Description |
|---|---|
TypeError
|
if |
ValueError
|
if |
Source code in assertpy/async_assertions.py
every ¶
Override the polling interval (in seconds).
Raises:
| Type | Description |
|---|---|
TypeError
|
if |
ValueError
|
if |
Source code in assertpy/async_assertions.py
ignoring ¶
Replace the exception types the polling loop retries instead of propagating.
Examples:
Usage:
assert_that(get_order).eventually_sync().within(10).ignoring(ConnectionError).has_status("PAID")
Raises:
| Type | Description |
|---|---|
TypeError
|
if any argument is not an |