flet
flet copied to clipboard
RFP: Async support in Flet Python client
Discussed in https://github.com/flet-dev/flet/discussions/72
Problem
It is currently impossible to call async method from Flet event handlers. They are synchronous functions run in separate threads. This limitation requires to use bulky constructs like:
search_data = new_event_loop().run_until_complete(get_weather(search_value))
where get_weather(search_value) is async function.
Solution
As in other languages like C# a "proper" async must be implemented from ground up - it's impossible/ineffective to partially support calling async methods from sync ones. The entire program must be running in an event loop (in Python terms).
Flet Python client must be re-implemented to use asyncio library.
Sample code
To be backward compatible Flet client will be providing both sync and async methods, for example async version of "Hello, world" might look like:
import asyncio
import flet
from flet import Page, Text, ElevatedButton
async def main():
async def btn_click(e):
var result = await some_call_to_rest_api()
page.controls.append(Text(result))
await page.update_async()
await page.add_async(
Text("Hello!"),
ElevatedButton("Call async method", on_click=btn_click)
)
asyncio.run(flet.app_async(target=main))
All async methods will have _async suffix. Sync methods will be wrappers around async.
WebSockets client will be replaced with websockets library based on asyncio.
Resources:
- https://docs.python.org/3/library/asyncio.html
Having asyncio support "natively" would be awesome -- but it does seem like a lot of work. Sprinkling async and await all over the place does make any code look unwieldy, and maintaining the sync alternatives seems like almost doubling the maintenance effort.
Anyone wanting to call into async functions from flet code could take advantage of the minimal unsync package, where a simple usage example would be:
import asyncio
import flet
from flet import ElevatedButton
from flet import Page
from unsync import unsync
def clicked(event):
something_async()
@unsync
async def something_async():
print("Starting an async operation")
await asyncio.sleep(1)
print("Finished")
def main(page: Page):
page.add(ElevatedButton("Click me to do something async", on_click=clicked))
page.update()
flet.app(target=main)
unsync maintains a singleton loop for its use, so the overhead is reasonable for most use cases.
Is there a chance to support asyncio soon? When can we expect this support, is there a rough date for it?
It's not a high priority right now. What would be your use case for that?
Easy integration of projects working with asyncio.
Currently, to bring these projects together with flet, I would have to create a workaround (calling async functions). For now I use qt and set the qt main loop as my asyncio event loop, bringing the two worlds together,... which allows me to use the gui with async functions.
If I could use the event loop of flet as asynchio loop, it would be easier, something like this:
import asyncio
import sys
from asyncqt import QEventLoop
from PySide2.QtWidgets import QApplication
from pykalah.view.main_window import MainWindow
def main() -> None:
"""The main function"""
app = QApplication(sys.argv)
loop = QEventLoop(app)
asyncio.set_event_loop(loop) # <-bring qt and asyncio together
window = MainWindow(None, initial_amount_pieces=6)
window.show()
with loop:
sys.exit(loop.run_forever())
if __name__ == "__main__":
main()```
It looks great, of course, it's just we don't have enough hands at the moment to implement that 😕
We go ahead with Async support in Flet: https://flet.dev/blog/flet-mobile-update#asyncio-support
How wonderful, thanks! :)