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
Metadata
Release files for aiowx 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| aiowx-0.3.0.tar.gz | 7.3 kB | Without provenance | Details for aiowx-0.3.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| aiowx-0.3.0-py3-none-any.whl | Python 3 | none | any | Details for aiowx-0.3.0-py3-none-any.whl |
Total release size: 14.9 kB
Release files / aiowx-0.3.0.tar.gz
| Download URL | aiowx-0.3.0.tar.gz |
|---|---|
| Size | 7.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
87b16239f5b7ba32fa1f75efadac334cfa0d9a319bed7f7e4f8d31dc054f9ef8
|
|
BLAKE2b-256 checksum How to use checksums |
777d8a9d8800eb16a574057327e92a0e06d8016b2273bc38e8034240c46a1a02
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is 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}
|
Release files / aiowx-0.3.0-py3-none-any.whl
| Download URL | aiowx-0.3.0-py3-none-any.whl |
|---|---|
| Size | 7.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
242098ae57b10fa0bc1b93e721ea818a4e6723bbf3829e203ac86920cd0ea124
|
|
BLAKE2b-256 checksum How to use checksums |
69bebad889f893b16e36badc863acb5bc8240b124097a025af6f23f89d7f50f8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is 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}
|
Security for aiowx 0.3.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.