Getting Started¶
Requirements¶
- Python 3.10 or later (CPython or PyPy)
- No third-party dependencies
Installation¶
Warning
Not yet published to PyPI. Install from GitHub:
or with uv:
Your first AsyncValue¶
An AsyncValue wraps an initial value. Read and
write it through the value property like a normal attribute:
from asyncio_util import AsyncValue
score = AsyncValue(0)
print(score.value) # 0
score.value = 10
print(score.value) # 10
The difference from a plain attribute: other tasks can await it.
import asyncio
from asyncio_util import AsyncValue
score = AsyncValue(0)
async def announcer():
value = await score.wait_value(lambda v: v >= 100)
print(f"reached {value}!")
async def game():
for points in (30, 40, 50):
await asyncio.sleep(0.1)
score.value += points # property supports augmented assignment
async def main():
await asyncio.gather(announcer(), game())
asyncio.run(main())
Output:
There is no polling here: announcer() sleeps until the assignment
score.value += points makes the predicate true, and it receives the exact
value that satisfied it.
Values vs. predicates¶
Every waiting API accepts either a plain value (compared with ==) or a
predicate function:
await score.wait_value(100) # value == 100
await score.wait_value(lambda v: v >= 100) # predicate(value) is True
Waiting for None
A plain None is treated as a value like any other:
await av.wait_value(None) waits until the value is None.
Timeouts¶
wait_value() and wait_transition() accept a timeout argument and raise
asyncio.TimeoutError when it expires:
The standard library idioms compose just as well — use whichever your codebase prefers:
await asyncio.wait_for(score.wait_value(100), timeout=1.0) # 3.10+
async with asyncio.timeout(1.0): # 3.11+
await score.wait_value(100)
When a wait is cancelled — by a timeout or otherwise — its internal waiter is cleaned up immediately; nothing leaks.
A note on equality¶
Assigning a value that compares equal (==) to the current one is a no-op:
no waiter wakes up and no transition is recorded. This deduplication is what
makes derived values (see Deriving and composing) cheap.
Thread safety¶
AsyncValue is not thread-safe. Assign value only from the thread
running the event loop. From another thread, hop onto the loop first:
Next steps¶
- Waiting for values — the full story on
wait_value,wait_transitionandheld_for. - Iterating over changes — consuming values as streams.
- Deriving and composing — building values out of values.
- Tasks and cancellation — structured helpers beyond
AsyncValue. - Events, streams and timing — the rest of the toolbox.