Async python for Event-Driven applications
Project description
AsyncED
Async python for Event-Driven applications
Installation
pip install asynced
Usage
At the core of asynced
lies StateVar
. It can (but does not have to) contain
a value, can be watched for changed, and can easily be mapped to other
StateVar
instances.
For the sake of brevity, next examples are assumed to be run from within an async function, as StateVar
requires a running event loop..
Creating an empty state var is as easy as:
>>> from asynced import StateVar
>>> spam = StateVar()
We can check whether it is set:
>>> spam.is_set
False
Let's create an asyncio.Task
that prints the spam value once it's set.
>>> async def print_spam():
... print(await spam)
...
... task = asyncio.create_task(print_spam)
Nothing is printed yet until we set the statevar:
>>> spam.set('Spam!')
Spam!
After we set the statevar, we see that print_spam
printed the value.
Up to here, we've done nothing that asyncio.Future
cannot do. But an
asyncio.Future
can only be set once, whereas a StateVar
can be set to a
different value as much as needed.
We can watch for any changes of a statevar by async iteration:
>>> async def print_spam_changes():
... async for value in spam:
... print(value)
...
... task = asyncio.create_task(print_spam_changes)
Now any time we set spam
to a different value, it'll be printed:
>>> spam.set('Spam and ham!')
Spam and ham!
>>> spam.set('Spam and eggs!')
Spam and eggs!
Neat eh?
A StateVar
can also be constructed by passing async iterable, making it
behave more like an asyncio.Task
:
>>> async def slowrange(*args):
... for i in range(*args):
... await asyncio.sleep(1)
... yield i
...
>>> count4 = StateVar(slowrange(4))
>>> await asyncio.sleep(3.14)
>>> await count4
2
As we see here, the statevar will set itself to the values from the async iterable in the background automatically.
Mapping
StateVar
's can also be constructed by applying a function to another
StateVar
:
>>> count4_inv = StateVar(slowrange(4)).map(lambda i: -i)
>>> async for i in count4_inv:
... print(i)
Now with one-second intervals, 0
, -1
, -2
and -3
will be printed.
StateVar.map
only works for functions with a single argument, i.e. for one
statevar at a time. But fear not, mapping multiple statevars together is
possible by using asynced.statefunction
. It transforms any function
(a: A, b: B, ...) -> R
into one that accepts State
's (State
is the superclass of StateVar
) and returns a
new StateVar
(or some other that subclasses State
),
(a: State[A], b: State[B], ...) -> StateVar[R]
.
>>> from asynced import statefunction
>>> @statefunction
... def sadd(_a: float, _b: float) -> float:
... return _a + _b
...
>>> a, b = StateVar(), StateVar()
>>> c = sadd(a, b)
Here, c
will be set iff both a
and b
are set:
>>>import calendar c.is_set
False
>>> a.set(12)
c.is_set
False
>>> b.set(30)
>>> await c
42
Now, every time that a
or b
change, c
will change as well.
StateTuple
In the same way as StateVar
, a StateTuple
can be awaited to get the current
value once it's available, and async-iterated to get the values once they are
set. Additionally, it can also be used as a tuple of individual StateVar
instances.
>>> st = StateTuple(2) # equivalent StateTuple(StateVar(), StateVar())
>>> st[0].set('spam')
>>> st[1].set('ham')
>>> await st
('spam', 'ham')
>>> await st[-1]
'ham'
>>> st[1] = 'eggs' # equivalent to st[1].set('eggs')
>>> await st
('spam', 'eggs')
>>> s0, s1 = st
>>> await s1
'eggs'
>>> st2 = 2 * st # equivalent to StateTuple((st[0], st[1], st[0], st[1]))
>>> st2[2] = 'bacon'
>>> await st2
('bacon', 'eggs', 'bacon', 'eggs')
>>> await st
('bacon', 'eggs')
StateDict
Like StateTuple
, a StateDict
is a collection of individual StateVar
's.
It is more similar to a collections.defaultdict
than a regular dict, because
accessing keys without values will return an empty StateVar
.
>>> sd = StateDict()
>>> await sd
{}
>>> sd['spam'] = 'Spam!'
>>> await sd
{'spam': 'Spam!'}
>>> ham = sd['ham']
>>> ham.is_set
False
>>> list(sd.keys())
['spam']
>>> sd['ham'] = 'Ham and eggs!'
>>> await ham
'Ham and eggs!'
.get()
StateVar
, StateTuple
and StateDict
all implement a .get()
method,
that can be used to get the current value, without having to use await
.
If no value has been set, it will raise a LookupError
. Alternatively,
you can pass a default
value, that is to be returned in case no value is set.
Error handling
If the async iterable used to create e.g. a StateVar
raises an error,
the .is_error
property will become True
, and the error will be raised when
its awaited, or when.get
or .map
are called. The exception will propagate
to its mapped "child" State
's.
If the async iterable is exhausted (or raises StopAsyncIteration
directly),
.is_stopped
will be set to True
instead, and StopAsyncIteration
will be only reraised for the waiters of __aiter__
and __anext__
.
API reference
*~ coming soon ~*
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file asynced-1.1.1.tar.gz
.
File metadata
- Download URL: asynced-1.1.1.tar.gz
- Upload date:
- Size: 17.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/1.1.13 CPython/3.10.4 Linux/5.13.0-41-generic
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | a6a5cfe8b64e546a802dadb16181fccd6dcbdedc1c6257bed16528dc219ed7dc |
|
MD5 | 02c07c97a187a96b3808db9d9d57b0a4 |
|
BLAKE2b-256 | 7dfc31c7f315cc77ec3415e6bc7e5c61c30145e80c94932532e17d675a4d1115 |
File details
Details for the file asynced-1.1.1-py3-none-any.whl
.
File metadata
- Download URL: asynced-1.1.1-py3-none-any.whl
- Upload date:
- Size: 17.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/1.1.13 CPython/3.10.4 Linux/5.13.0-41-generic
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 5686c468b0665398df2ec6ae461e991471ef4ea9ec8f770d1ff3668c517e8fcd |
|
MD5 | 29b11c20a83331dfef275a3597f7ee18 |
|
BLAKE2b-256 | fa635387e37e5b6b9a3703b9dc1c081e83c0e4f9b2d1e86b21584937e9533d9e |