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 - or 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]
| tuple[type[Exception], ...] = (),
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] | tuple[type[Exception], ...]
|
an |
()
|
trace
|
bool
|
record a |
True
|
Examples:
Usage:
import asyncio
from assertpy2 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 assertpy2/assertpy.py
1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 | |
eventually_sync ¶
eventually_sync(
*,
timeout: float = 5.0,
interval: float = 0.5,
ignoring: type[Exception]
| tuple[type[Exception], ...] = (),
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] | tuple[type[Exception], ...]
|
an |
()
|
trace
|
bool
|
record a |
True
|
Examples:
Usage:
from assertpy2 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 assertpy2/assertpy.py
1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 | |
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 assertpy2/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 assertpy2/async_assertions.py
every ¶
Override the polling interval (in seconds).
Raises:
| Type | Description |
|---|---|
TypeError
|
if |
ValueError
|
if |
Source code in assertpy2/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 assertpy2/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 assertpy2/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 assertpy2/async_assertions.py
every ¶
Override the polling interval (in seconds).
Raises:
| Type | Description |
|---|---|
TypeError
|
if |
ValueError
|
if |
Source code in assertpy2/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 |