API Reference¶
- exception MotionEventAlreadyEndedError¶
This error occurs when an already-ended touch is passed to an asynckivy API that expects an ongoing touch. For instance:
import asynckivy as ak class MyWidget(Widget): def on_touch_up(self, touch): # not 'on_touch_down', oops! ak.start(self.handle_touch(touch)) return True async def handle_touch(self, touch): try: async for __ in ak.rest_of_touch_events(widget, touch): ... except ak.MotionEventAlreadyEndedError: ...
- anim_attrs(obj, *, duration=1.0, step=0, transition='linear', output_seq_type=<class 'tuple'>, **animated_properties) Awaitable ¶
Animates attibutes of any object.
import types obj = types.SimpleNamespace(x=0, size=(200, 300)) await anim_attrs(obj, x=100, size=(400, 400))
The
output_seq_type
parameter:obj = types.SimpleNamespace(size=(200, 300)) await anim_attrs(obj, size=(400, 400), output_seq_type=list) assert type(obj.size) is list
Warning
Unlike
kivy.animation.Animation
, this one does not support dictionary-type and nested-sequence.await anim_attrs(obj, pos_hint={'x': 1.}) # not supported await anim_attrs(obj, nested_sequence=[[10, 20, ]]) # not supported await anim_attrs(obj, color=(1, 0, 0, 1), pos=(100, 200)) # OK
Added in version 0.6.1.
- anim_attrs_abbr(obj, *, d=1.0, s=0, t='linear', output_seq_type=<class 'tuple'>, **animated_properties) Awaitable ¶
anim_attrs()
cannot animate attributes namedstep
,duration
andtransition
but this one can.Added in version 0.6.1.
- async anim_with_dt(*, step=0)¶
An async form of
kivy.clock.Clock.schedule_interval()
. The following callback-style code:def callback(dt): print(dt) if some_condition: return False Clock.schedule_interval(callback, 0.1)
is equivalent to the following async-style code:
async for dt in anim_with_dt(step=0.1): print(dt) if some_condition: break
Added in version 0.6.1.
- async anim_with_dt_et(*, step=0)¶
anim_with_dt()
andanim_with_et()
combined.async for dt, et in anim_with_dt_et(...): ...
Added in version 0.6.1.
- async anim_with_dt_et_ratio(*, base, step=0)¶
anim_with_dt()
,anim_with_et()
andanim_with_ratio()
combined.async for dt, et, p in anim_with_dt_et_ratio(...): ...
Added in version 0.6.1.
Changed in version 0.7.0: The
duration
parameter was replaced withbase
. The loop no longer ends on its own.
- async anim_with_et(*, step=0)¶
Generates the elapsed time of the loop.
async for et in anim_with_et(...): print(et)
The code above is equivalent to the following:
et = 0. async for dt in anim_with_dt(...): et += dt print(et)
Added in version 0.6.1.
- async anim_with_ratio(*, base, step=0)¶
async for p in anim_with_ratio(base=3): print(p)
The code above is equivalent to the following:
base = 3 async for et in anim_with_et(...): p = et / base print(p)
If you want non-linear ratio values, you may find
kivy.animation.AnimationTransition
helpful.from kivy.animation import AnimationTransition in_cubic = AnimationTransition.in_cubic async for p in anim_with_ratio(base=...): p = in_cubic(p) print(p)
Added in version 0.6.1.
Changed in version 0.7.0: The
duration
parameter was replaced withbase
. The loop no longer ends on its own.
- create_texture_from_text(*, markup=False, **label_kwargs) kivy.graphics.texture.Texture ¶
from kivy.metrics import sp texture = create_texture_from_text( text='Hello', font_size=sp(50), font_name='Roboto', color=(1, 0, 0, 1), )
See
kivy.core.text.LabelBase
for all the available keyword parameters.
- event(event_dispatcher, event_name, *, filter=None, stop_dispatching=False) Awaitable[tuple] ¶
Returns an awaitable that can be used to wait for:
a Kivy event to occur.
a Kivy property’s value to change.
# Wait for a button to be pressed. await event(button, 'on_press') # Wait for an 'on_touch_down' event to occur. __, touch = await event(widget, 'on_touch_down') # Wait for 'widget.x' to change. __, x = await ak.event(widget, 'x')
The
filter
parameter:# Wait for an 'on_touch_down' event to occur inside a widget. __, touch = await event(widget, 'on_touch_down', filter=lambda w, t: w.collide_point(*t.opos)) # Wait for 'widget.x' to become greater than 100. if widget.x <= 100: await event(widget, 'x', filter=lambda __, x: x > 100)
The
stop_dispatching
parameter:It only works for events not for properties. See Kivy’s Event System for details.
- fade_transition(*widgets, duration=1.0, step=0) AsyncContextManager ¶
Returns an async context manager that:
fades-out the given widgets on
__aenter__
.fades-in the given widgets on
__aexit__
.
async with fade_transition(widget1, widget2): ...
The
widgets
don’t have to be actual Kivy widgets. Anything that has an attribute namedopacity
would work.
- async interpolate(start, end, *, duration=1.0, step=0, transition='linear') AsyncIterator ¶
Interpolates between the values
start
andend
in an async-manner. Inspired by wasabi2d’s interpolate.async for v in interpolate(0, 100, duration=1.0, step=.3): print(int(v))
elapsed time
output
0 sec
0
0.3 sec
30
0.6 sec
60
0.9 sec
90
1.2 sec
100
- async interpolate_seq(start, end, *, duration, step=0, transition='linear', output_type=<class 'tuple'>) AsyncIterator ¶
Same as
interpolate()
except this one is for sequence types.async for v in interpolate_seq([0, 50], [100, 100], duration=1, step=0.3): print(v)
elapsed time
output
0
(0, 50)
0.3
(30, 65)
0.6
(60, 80)
0.9
(90, 95)
1.2 sec
(100, 100)
Added in version 0.7.0.
- move_on_after(seconds: float) AsyncContextManager[Task] ¶
Returns an async context manager that applies a time limit to its code block, like
trio.move_on_after()
does.async with move_on_after(seconds) as timeout_tracker: ... if timeout_tracker.finished: print("The code block was interrupted due to a timeout") else: print("The code block exited gracefully.")
Added in version 0.6.1.
- n_frames(n: int) Awaitable ¶
Waits for a specified number of frames.
await n_frames(2)
If you want to wait for one frame,
asynckivy.sleep()
is preferable for a performance reason.await sleep(0)
- class repeat_sleeping(*, step=0)¶
Returns an async context manager that provides an efficient way to repeat sleeping.
When there is a piece of code like this:
while True: await sleep(0) ...
it can be translated to:
async with repeat_sleeping(step=0) as sleep: while True: await sleep() ...
The latter is more suitable for situations requiring frequent sleeps, such as moving an object in every frame.
Restriction
You are not allowed to perform any kind of async operations inside the with-block except you can
await
the return value of the function that is bound to the identifier of the as-clause.async with repeat_sleeping(step=0) as sleep: await sleep() # OK await something_else # NOT ALLOWED async with async_context_manager: # NOT ALLOWED ... async for __ in async_iterator: # NOT ALLOWED ...
- async rest_of_touch_events(...) AsyncIterator[None] ¶
Returns an async iterator that yields each occurrence of on_touch_move, and stops when on_touch_up occurs.
async for __ in rest_of_touch_events(widget, touch): print('on_touch_move') print('on_touch_up')
This is a wrapper around
watch_touch
. While it may be more intuitive thanwatch_touch
, it has a few drawbacks—see The Problem with Async Generators.
- async run_in_executor(executor: ThreadPoolExecutor, func) Awaitable ¶
Runs a function within a
concurrent.futures.ThreadPoolExecutor
, and waits for the completion of the function.executor = ThreadPoolExecutor() ... return_value = await run_in_executor(executor, func)
See I/O in AsyncKivy for details.
- async run_in_thread(func, *, daemon=None) Awaitable ¶
Creates a new thread, runs a function within it, then waits for the completion of that function.
return_value = await run_in_thread(func)
See I/O in AsyncKivy for details.
- sleep(duration) Awaitable[float] ¶
An async form of
kivy.clock.Clock.schedule_once()
.dt = await sleep(5) # wait for 5 seconds
- sleep_free(duration) Awaitable[float] ¶
An async form of
kivy.clock.Clock.schedule_once_free()
.dt = await sleep_free(5) # wait for 5 seconds
- class suppress_event(event_dispatcher, event_name, *, filter=<function suppress_event.<lambda>>)¶
Returns a context manager that prevents the callback functions (including the default handler) bound to an event from being called.
from kivy.uix.button import Button btn = Button() btn.bind(on_press=lambda __: print("pressed")) with suppress_event(btn, 'on_press'): btn.dispatch('on_press')
The above code prints nothing because the callback function won’t be called.
Strictly speaking, this context manager doesn’t prevent all callback functions from being called. It only prevents the callback functions that were bound to an event before the context manager enters. Thus, the following code prints
pressed
.from kivy.uix.button import Button btn = Button() with suppress_event(btn, 'on_press'): btn.bind(on_press=lambda __: print("pressed")) btn.dispatch('on_press')
Warning
You need to be careful when you suppress an
on_touch_xxx
event. See Kivy’s Event System for details.
- class sync_attr(from_: Tuple[kivy.event.EventDispatcher, str], to_: Tuple[Any, str])¶
Returns a context manager that creates one-directional binding between attributes.
import types widget = Widget() obj = types.SimpleNamespace() with sync_attr(from_=(widget, 'x'), to_=(obj, 'xx')): widget.x = 10 assert obj.xx == 10 # synchronized obj.xx = 20 assert widget.x == 10 # but not the other way around
This can be particularly useful when combined with
transform()
.from kivy.graphics import Rotate async def rotate_widget(widget, *, angle=360.): rotate = Rotate(origin=widget.center) with ( transform(widget) as ig, sync_attr(from_=(widget, 'center'), to_=(rotate, 'origin')), ): ig.add(rotate) await anim_attrs(rotate, angle=angle)
Added in version 0.6.1.
- class sync_attrs(from_: Tuple[kivy.event.EventDispatcher, str], *to_)¶
When multiple
sync_attr
calls take the samefrom_
argument, they can be merged into a singlesync_attrs
call. For instance, the following code:with sync_attr((widget, 'x'), (obj1, 'x')), sync_attr((widget, 'x'), (obj2, 'xx')): ...
can be replaced with the following one:
with sync_attrs((widget, 'x'), (obj1, 'x'), (obj2, 'xx')): ...
This can be particularly useful when combined with
transform()
.from kivy.graphics import Rotate, Scale async def scale_and_rotate_widget(widget, *, scale=2.0, angle=360.): rotate = Rotate(origin=widget.center) scale = Scale(origin=widget.center) with ( transform(widget) as ig, sync_attrs((widget, 'center'), (rotate, 'origin'), (scale, 'origin')), ): ig.add(rotate) ig.add(scale) await wait_all( anim_attrs(rotate, angle=angle), anim_attrs(scale, x=scale, y=scale), )
Added in version 0.6.1.
- async touch_up_event(widget, touch, *, stop_dispatching=False, timeout=1.0) Awaitable ¶
(experimental state)
Returns an awaitable that waits for an
on_touch_up
event to occur.__, touch = await event(widget, 'on_touch_down') ... await touch_up_event(widget, touch)
This API “grabs” the touch, making it behave differently from the following example, which does not grab.
__, touch = await event(widget, 'on_touch_down') ... await event(widget, 'on_touch_up', filter=lambda w, t: t is touch)
Typically, this API is used with
asyncgui.move_on_when
.__, touch = await event(widget, 'on_touch_down', stop_dispatching=True) touch_move_event = partial( event, widget, 'on_touch_move', stop_dispatching=True, filter=lambda w, t: t is touch and t.grab_current is w) async with move_on_when(touch_up_event(widget, touch)): # This code block will be cancelled when the touch ends. while True: await touch_move_event() ...
An advantage of the code above, compared to
rest_of_touch_events
, is that it allows you to perform other async operations inside the with-block.
- transform(widget, *, use_outer_canvas=False) ContextManager[kivy.graphics.InstructionGroup] ¶
Returns a context manager that sandwiches the
widget
’s existing canvas instructions between akivy.graphics.PushMatrix
and akivy.graphics.PopMatrix
, and inserts ankivy.graphics.InstructionGroup
right next to thePushMatrix
. Those three instructions will be removed when the context manager exits.This may be useful when you want to animate a widget.
Usage
from kivy.graphics import Rotate async def rotate_widget(widget, *, angle=360.): with transform(widget) as ig: # <- InstructionGroup ig.add(rotate := Rotate(origin=widget.center)) await anim_attrs(rotate, angle=angle)
If the position or size of the
widget
changes during the animation, you might needsync_attr
.The use_outer_canvas parameter
While the context manager is active, the content of the widget’s canvas would be:
# ... represents existing instructions Widget: canvas.before: ... canvas: PushMatrix InstructionGroup ... PopMatrix canvas.after: ...
but if
use_outer_canvas
is True, it would be:Widget: canvas.before: PushMatrix InstructionGroup ... canvas: ... canvas.after: ... PopMatrix
- class watch_touch(widget, touch, *, stop_dispatching=False, timeout=1.0)¶
Returns an async context manager that provides an easy way to handle touch events.
async with watch_touch(widget, touch) as in_progress: while await in_progress(): print('on_touch_move') print('on_touch_up')
The
await in_progress()
waits for either anon_touch_move
event or anon_touch_up
event to occur, and returns True or False respectively when they occurred.Caution
You are not allowed to perform any kind of async operations inside the with-block except
await in_progress()
.async with watch_touch(widget, touch) as in_progress: await in_progress() # OK await something_else # NOT ALLOWED async with async_context_manager: # NOT ALLOWED ... async for __ in async_iterator: # NOT ALLOWED ...
If the
widget
is the type of widget that grabs touches by itself, such askivy.uix.button.Button
, you probably want to set thestop_dispatching
parameter to True in most cases.There are widgets/behaviors that can simulate a touch (e.g.
kivy.uix.scrollview.ScrollView
,kivy.uix.behaviors.DragBehavior
andkivy_garden.draggable.KXDraggableBehavior
). If many such widgets are in the parent stack of thewidget
, this API might mistakenly raise aasynckivy.MotionEventAlreadyEndedError
. If that happens, increase thetimeout
parameter.