Async I/O bridge for wxPython — run asyncio coroutines with wx GUI
Project description
aiowx
Bridge wxPython with Python asyncio — run
async/awaitcoroutines in your wx GUI.
Installation
As a dependency
uv add aiowx
# or with pip:
pip install aiowx
From source
git clone https://github.com/Row0902/aiowx.git
cd aiowx
uv sync # install deps + dev deps
uv build # build wheel + source dist
Requires Python 3.12+, wxPython ≥ 4.2.5, and uv.
Quick start
import asyncio
import wx
from aiowx import AsyncBind, WxAsyncApp, StartCoroutine
class CounterFrame(wx.Frame):
def __init__(self):
super().__init__(None, title="aiowx counter")
self.label = wx.StaticText(self, label="0")
btn = wx.Button(self, label="+1")
AsyncBind(wx.EVT_BUTTON, self.on_click, btn)
StartCoroutine(self.tick, self)
async def on_click(self, _event):
self.label.SetLabel(str(int(self.label.GetLabel()) + 1))
async def tick(self):
while True:
self.label.SetLabel(str(int(self.label.GetLabel()) + 1))
await asyncio.sleep(1)
async def main():
app = WxAsyncApp()
frame = CounterFrame()
frame.Show()
app.SetTopWindow(frame)
await app.MainLoop()
asyncio.run(main())
API
| Function | Purpose | Async |
|---|---|---|
WxAsyncApp() |
Drop-in replacement for wx.App |
— |
await app.MainLoop() |
Start the event loop | ✅ |
AsyncBind(event, coro, widget) |
Bind a wx event to a coroutine | — |
StartCoroutine(coro, window) |
Fire a coroutine attached to a window | — |
await AsyncShowDialog(dlg) |
Show a dialog modally (modless path) | ✅ |
await AsyncShowDialogModal(dlg) |
Show an OS dialog safely | ✅ |
WxAsyncApp
Create instead of wx.App. Interleaves the wx event loop with asyncio so both GUI events and coroutines run cooperatively.
app = WxAsyncApp()
await app.MainLoop()
AsyncBind
Bind a wx event to an async callback. Works alongside regular wx.Bind.
AsyncBind(wx.EVT_BUTTON, on_submit, submit_btn)
async def on_submit(event):
result = await fetch_data() # non-blocking I/O
display.SetLabel(f"Got: {result}")
StartCoroutine
Run a coroutine immediately, attached to a wx.Window. It is automatically cancelled when the window is destroyed — no manual cleanup.
task = StartCoroutine(poll_sensor(sensor), panel)
# ...
task.cancel() # optional early cancel
AsyncShowDialog / AsyncShowDialogModal
Show dialogs without blocking the event loop.
AsyncShowDialog: works with custom dialogs (modless path).AsyncShowDialogModal: for OS-native dialogs (wx.FileDialog,wx.DirDialog, etc.). Runs on the wx main thread (thread-safe).
async def pick_file(parent):
dlg = wx.FileDialog(parent)
result = await AsyncShowDialogModal(dlg)
if result == wx.ID_OK:
path.SetLabel(dlg.GetPath())
Note: the asyncio event loop is blocked while the modal dialog is open. This is expected desktop GUI behavior — identical to how
ShowModalworks in a traditional wx app.
Patterns
Background task with cancellation
import asyncio
from aiowx import StartCoroutine
class MonitorFrame(wx.Frame):
def __init__(self):
super().__init__(None)
self.running = True
self.task = StartCoroutine(self.watchdog, self)
async def watchdog(self):
while self.running:
await asyncio.sleep(5)
if not self.check_health():
wx.MessageBox("Connection lost")
break
Dialog with await
async def save_file(parent):
dlg = wx.FileDialog(
parent,
style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT,
)
if await AsyncShowDialogModal(dlg) == wx.ID_OK:
with open(dlg.GetPath(), "w") as f:
f.write(data)
Performance
Values measured on Windows (Core i7-7700K @ 4.2 GHz):
| Scenario | Latency | Latency at max throughput | Max throughput |
|---|---|---|---|
| asyncio only (reference) | 0 ms | 17 ms | 571 325 msg/s |
| wx only (reference) | 0 ms | 19 ms | 94 591 msg/s |
| aiowx (GUI) | 5 ms | 19 ms | 52 304 msg/s |
| aiowx (GUI + asyncio) | 5 ms / 0 ms | 24 ms / 12 ms | 40 302 + 134 000 msg/s |
CPU usage at idle: 0% on Windows, ~1–2% on macOS.
Requirements
- Python ≥ 3.12
- wxPython ≥ 4.2.5 (4.2.5+ includes Python 3.14 wheels)
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file aiowx-0.2.0.tar.gz.
File metadata
- Download URL: aiowx-0.2.0.tar.gz
- Upload date:
- Size: 6.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.23 {"installer":{"name":"uv","version":"0.11.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b18d97e9233ea69587aceb3f753b1106b59cf43efe461cde42e87d4113183ce6
|
|
| MD5 |
6ed7730962d3328523afe6e1013311f8
|
|
| BLAKE2b-256 |
e494ddbe8a565fc8fee36df8f53825b4cd8d4dcf6e4c6da8909cf359968b72f0
|
File details
Details for the file aiowx-0.2.0-py3-none-any.whl.
File metadata
- Download URL: aiowx-0.2.0-py3-none-any.whl
- Upload date:
- Size: 6.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.23 {"installer":{"name":"uv","version":"0.11.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ff8509f3db0b9e271a2697ca6525cbdf87306f97f97e8ee0d3b39f4e626955f8
|
|
| MD5 |
86473874c786b5643dc5b5e534409ec0
|
|
| BLAKE2b-256 |
7609fb3683ba5a286493c72262c8f6a5a8265953a19919802c03be1794045bd3
|