flet icon indicating copy to clipboard operation
flet copied to clipboard

RFP: Async support in Flet Python client

Open FeodorFitsner opened this issue 3 years ago • 1 comments

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

FeodorFitsner avatar Jul 29 '22 18:07 FeodorFitsner

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.

mikaelho avatar Aug 03 '22 06:08 mikaelho

Is there a chance to support asyncio soon? When can we expect this support, is there a rough date for it?

TutorExilius avatar Nov 11 '22 12:11 TutorExilius

It's not a high priority right now. What would be your use case for that?

FeodorFitsner avatar Nov 14 '22 02:11 FeodorFitsner

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()```
    
 

TutorExilius avatar Nov 14 '22 17:11 TutorExilius

It looks great, of course, it's just we don't have enough hands at the moment to implement that 😕

FeodorFitsner avatar Nov 16 '22 04:11 FeodorFitsner

We go ahead with Async support in Flet: https://flet.dev/blog/flet-mobile-update#asyncio-support

FeodorFitsner avatar Dec 08 '22 20:12 FeodorFitsner

How wonderful, thanks! :)

TutorExilius avatar Dec 09 '22 00:12 TutorExilius