Skip to main content

async library for tkinter

Project description

AsyncTkinter

Youtube

asynctkinter is an async library that saves you from ugly callback-style code, like most of async libraries do. Let's say you want to do:

  1. print('A')
  2. wait for 1sec
  3. print('B')
  4. wait for a label to be pressed
  5. print('C')

in that order. Your code would look like this:

def what_you_want_to_do(label):
    bind_id = None
    print('A')

    def one_sec_later(__):
        nonlocal bind_id
        print('B')
        bind_id = label.bind('<Button>', on_press, '+')
    label.after(1000, one_sec_later)

    def on_press(event):
        label.unbind('<Button>', bind_id)
        print('C')

what_you_want_to_do(...)

It's not easy to understand. If you use asynctkinter, the code above will become:

import asynctkinter as at

async def what_you_want_to_do(label):
    print('A')
    await at.sleep(label.after, 1000)
    print('B')
    await at.event(label, '<Button>')
    print('C')

at.start(what_you_want_to_do(...))

Installation

Pin the minor version.

poetry add asynctkinter@~0.3
pip install "asynctkinter>=0.3,<0.4"

Usage

from functools import partial
import tkinter as tk
import asynctkinter as at


def main():
    at.install()
    root = tk.Tk()
    at.start(async_main(root))
    root.mainloop()


async def async_main(root):
    sleep = partial(at.sleep, root.after)
    label = tk.Label(root, text='Hello', font=('', 80))
    label.pack()

    # wait for 2sec
    await sleep(2000)

    # wait for a label to be pressed
    event = await at.event(label, '<Button>')
    print(f"pos: {event.x}, {event.y}")

    # wait until EITHER a label is pressed OR 5sec passes.
    # i.e. wait at most 5 seconds for a label to be pressed.
    tasks = await at.wait_any(
        at.event(label, '<Button>'),
        sleep(5000),
    )
    if tasks[0].finished:
        event = tasks[0].result
        print(f"The label was pressed. (pos: {event.x}, {event.y})")
    else:
        print("5sec passed")

    # wait until a label is pressed AND 5sec passes.
    tasks = await at.wait_all(
        at.event(label, '<Button>'),
        sleep(5000),
    )


if __name__ == "__main__":
    main()

threading

asynctkinter doesn't 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 ThreadPoolExecuter
import asynctkinter as at

executer = ThreadPoolExecuter()

async def async_fn(widget):
    # create a new thread, run a function inside it, then
    # wait for the completion of that thread
    r = await at.run_in_thread(thread_blocking_operation, after=widget.after)
    print("return value:", r)

    # run a function inside a ThreadPoolExecuter, and wait for its completion.
    # (ProcessPoolExecuter is not supported)
    r = await at.run_in_executer(executer, thread_blocking_operation, after=widget.after)
    print("return value:", r)

Exceptions(not BaseExceptions) are propagated to the caller, so you can catch them like you do in synchronous code:

import requests
import asynctkinter as at

async def async_fn(widget):
    try:
        r = await at.run_in_thread(lambda: requests.get('htt...', timeout=10), after=widget.after)
    except requests.Timeout:
        print("TIMEOUT!")
    else:
        print('RECEIVED:', r)

Note

  • You may want to read the asyncgui's documentation as it is the foundation of this library.
  • I'm not even a tkinter user so there may be plenty of weird code in the repository.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

asynctkinter-0.3.1.tar.gz (4.1 kB view hashes)

Uploaded Source

Built Distribution

asynctkinter-0.3.1-py3-none-any.whl (4.7 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page