• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

insolor / async-tkinter-loop / 18337161454

08 Oct 2025 07:27AM UTC coverage: 99.074% (-0.9%) from 100.0%
18337161454

Pull #178

github

web-flow
Merge 0b1ad262d into 81f3fbc56
Pull Request #178: Run tests on Python 3.14

20 of 21 new or added lines in 2 files covered. (95.24%)

107 of 108 relevant lines covered (99.07%)

4.95 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.3
/async_tkinter_loop/async_tkinter_loop.py
1
import _tkinter
5✔
2
import asyncio
5✔
3
import tkinter as tk
5✔
4
from collections.abc import Callable, Coroutine
5✔
5
from functools import wraps
5✔
6
from typing import Any
5✔
7

8
from typing_extensions import ParamSpec
5✔
9

10

11
async def main_loop(root: tk.Tk) -> None:
5✔
12
    """
13
    An asynchronous implementation of tkinter mainloop. The function is not intended to be called directly from your
14
    code.
15

16
    Args:
17
        root: tkinter root window object
18
    """
19
    while True:
20
        # Process all pending events
21
        while root.dooneevent(_tkinter.DONT_WAIT) > 0:
5✔
22
            pass
5✔
23

24
        try:
5✔
25
            root.winfo_exists()  # Will throw TclError if the main window is destroyed
5✔
26
        except tk.TclError:
5✔
27
            break
5✔
28

29
        await asyncio.sleep(0.01)
5✔
30

31

32
def get_event_loop() -> asyncio.AbstractEventLoop:
5✔
33
    """
34
    A helper function which returns a running event loop.
35

36
    Returns:
37
        event loop
38
    """
NEW
39
    return asyncio.get_running_loop()
×
40

41

42
def async_mainloop(root: tk.Tk, event_loop: asyncio.AbstractEventLoop | None = None) -> None:
5✔
43
    """
44
    A function, which is a substitute to the standard `root.mainloop()`.
45

46
    Args:
47
        root: tkinter root object
48
        event_loop: asyncio event loop (optional)
49
    """
50
    event_loop = event_loop or asyncio.new_event_loop()
5✔
51
    event_loop.run_until_complete(main_loop(root))
5✔
52

53

54
P = ParamSpec("P")
5✔
55

56

57
def async_handler(
5✔
58
    async_function: Callable[P, Coroutine[Any, Any, None]],
59
    *args: Any,  # noqa: ANN401
60
    event_loop: asyncio.AbstractEventLoop | None = None,
61
    **kwargs: Any,  # noqa: ANN401
62
) -> Callable[P, None]:
63
    """
64
    A helper function which allows to use async functions as command handlers (e.g. button click handlers) or event
65
    handlers.
66

67
    Args:
68
        async_function: async function
69
        args: positional parameters which will be passed to the async function
70
        event_loop: asyncio event loop (optional, for testing purposes)
71
        kwargs: keyword parameters which will be passed to the async function
72

73
    Returns:
74
        A sync function, which runs the original async function in an async event loop.
75

76
    Usage examples:
77
    ```python
78
    import tkinter as tk
79
    from async_tkinter_loop import async_handler
80

81
    async def some_async_function():
82
        print("Wait...")
83
        await asyncio.sleep(0.5)
84
        print("Done!")
85

86
    button = tk.Button("Press me", command=async_handler(some_async_function))
87

88
    # ----
89

90
    async def some_async_function(event):
91
        print("Wait...")
92
        await asyncio.sleep(0.5)
93
        print("Done!")
94

95
    root.bind("<1>", command=async_handler(some_async_function))
96

97
    # ----
98

99
    # Also, it can be used as a decorator
100
    @async_handler
101
    async def some_async_function():
102
        print("Wait...")
103
        await asyncio.sleep(0.5)
104
        print("Done!")
105

106
    button = tk.Button("Press me", command=some_async_function)
107
    ```
108
    """
109
    event_loop = event_loop or get_event_loop()
5✔
110

111
    @wraps(async_function)
5✔
112
    def wrapper(*handler_args) -> None:
5✔
113
        event_loop.create_task(async_function(*handler_args, *args, **kwargs))
5✔
114

115
    return wrapper
5✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc