Notes#

I/O in AsyncKivy#

asynckivy does not have any I/O primitives unlike trio and asyncio do, thus threads may be the best way to perform them without blocking the main-thread:

from concurrent.futures import ThreadPoolExecutor
import asynckivy as ak

executor = ThreadPoolExecutor()


def thread_blocking_operation():
    '''
    This function is called from outside the main-thread so you should not
    perform any graphics-related operations here.
    '''


async def async_fn():
    r = await ak.run_in_thread(thread_blocking_operation)
    print("return value:", r)

    r = await ak.run_in_executor(executor, thread_blocking_operation)
    print("return value:", r)

Unhandled exceptions (not BaseException) are propagated to the caller so you can catch them like you do in synchronous code:

import requests
import asynckivy as ak

async def async_fn(label):
    try:
        response = await ak.run_in_thread(lambda: requests.get('htt...', timeout=10))
    except requests.Timeout:
        label.text = "TIMEOUT!"
    else:
        label.text = "RECEIVED"

Kivy’s Event System#

(under construction)

The Problem with Async Generators#

asyncio and trio do some hacky stuff, sys.set_asyncgen_hooks() and sys.get_asyncgen_hooks(), which likely hinders asynckivy-flavored async generators. You can see its details here.

Because of that, the APIs that create async generators might not work perfectly if asyncio or trio is running. Here is a list of them:

Places where async operations are disallowed#

Most of the asynckivy APIs that return an async iterator don’t allow to perform async operations during the iteration. Here is a list of them:

async for __ in rest_of_touch_events(...):
    await awaitable  # NOT ALLOWED
    async with async_context_manager:  # NOT ALLOWED
        ...
    async for __ in async_iterator:  # NOT ALLOWED
        ...

Animations may not end in time#

All the animation-related APIs don’t guarantee that they will end in time. It probably doesn’t matter as long as the step parameter is small enough. However, in case it’s not, be aware of what might happen.

async for dt, et, p in anim_with_dt_et_ratio(duration=2.0, step=0.6):
    print(dt, et, p)

dt

et

p

0.6

0.6

0.3

0.6

1.2

0.6

0.6

1.8

0.9

0.6

2.4

1.2

Look at the bottom row. et largely exceeds the duration and p largely exceeds 1.0. If you really want it to end in time, consider wrapping it in asynckivy.move_on_after().

async with move_on_after(2.0):
    async for dt, et, p in anim_with_dt_et_progress(duration=2.0, step=0.6):
        print(dt, et, p)

dt

et

p

0.6

0.6

0.3

0.6

1.2

0.6

0.6

1.8

0.9