flet-dev / flet

Flet enables developers to easily build realtime web, mobile and desktop apps in Python. No frontend experience required.
https://flet.dev
Apache License 2.0
9.89k stars 390 forks source link

Unable to update page using Threading #3571

Closed vishnu-rvb closed 1 day ago

vishnu-rvb commented 4 days ago

Duplicate Check

Describe the bug

i am using threading to call page.update() periodically at a set time from a new thread. I also have a button called refresh that changes modifies page controls. sometimes it is seen that page.update() is raising an error which i am not sure why and why its only sometimes and not all times. i am sharing the relevant segments of the code.

Code

from flet import app,Page
import time,threading
ThreadExit = threading.Event()

def newThread(func):
    def wrapped(*args,**kwargs):
        thread=threading.Thread(target=func,args=args,kwargs=kwargs)
        thread.start()
    return wrapped

def clockSchedule(func):
    @newThread
    def wrapped(*args,**kwargs):
        while not ThreadExit.is_set():
            func(*args,**kwargs)
            time.sleep(kwargs['dt'])
    return wrapped

class GUIApp:
    def Build(self,page: Page):
        #adds several flet controls including Refresh button
    def RefreshItems(self,page:Page):
        #modifies the added flet controls, triggered by press of Refresh button

    @clockSchedule    
    def updatePage(self,dt,page: Page):
        page.update()

    def run(self):
        target=lambda page:(self.Build(page),self.updatePage(dt=1/30,page=page))
        app(target=target)
        ThreadExit.set()
        quit()

if __name__=='__main__': GUIApp().run()

To reproduce

1)Initial state: image 2)Clicking Refresh button multiple times 3)When error is raised: image

Expected behavior

Expected RefreshItems function call to be completed but is terminated due to the raised error

Screenshots

Error seen

File "c:\Users\User\Documents\GitHub\Quarentine-Manager\main.py", line 27, in updatePage
    page.update()
  File "C:\Program Files\Python310\lib\site-packages\flet_core\page.py", line 718, in update
    r = self.__update(self)
  File "C:\Program Files\Python310\lib\site-packages\flet_core\page.py", line 832, in __update
    commands, added_controls, removed_controls = self.__prepare_update(*controls)
  File "C:\Program Files\Python310\lib\site-packages\flet_core\page.py", line 848, in __prepare_update        
    control.build_update_commands(
  File "C:\Program Files\Python310\lib\site-packages\flet_core\control.py", line 464, in build_update_commands
    ctrl.build_update_commands(
  File "C:\Program Files\Python310\lib\site-packages\flet_core\control.py", line 464, in build_update_commands
    ctrl.build_update_commands(
  File "C:\Program Files\Python310\lib\site-packages\flet_core\control.py", line 464, in build_update_commands
    ctrl.build_update_commands(
  [Previous line repeated 1 more time]
  File "C:\Program Files\Python310\lib\site-packages\flet_core\control.py", line 480, in build_update_commands
    assert self.__uid is not None
AssertionError

Operating System

Windows

Operating system details

Windows 10

Flet version

Name: flet Version: 0.23.2 Summary: Flet for Python - easily build interactive multi-platform apps in Python Home-page: https://flet.dev Author: Appveyor Systems Inc. Author-email: hello@flet.dev License: Apache-2.0 Location: c:\program files\python310\lib\site-packages Requires: cookiecutter, fastapi, flet-runtime, packaging, qrcode, uvicorn, watchdog Required-by:

Regression

No, it isn't

Suggestions

Seems like page update is hindered when refresh is in the process of modifying flet controls. would prefer if update checks and waits for end of refresh function call

Additional details

No response

ndonkoHenri commented 4 days ago

Please provide some runnable code which reproduces the issue.

ethans333 commented 2 days ago

Im getting the same issue

ndonkoHenri commented 2 days ago

Im getting the same issue

Saying it like this doesnt help at all. Provide some runnable code to test the issue.

burhansvural commented 1 day ago

@vishnu-rvb

Please share the entire code so we can fully examine the issue.

ethans333 commented 1 day ago

Fixed the issue. What I ended up doing is locking the threads right before creating/modifying the UI (this involves creating elements, updating the page, etc.) and then unlocking them right after.

I believe the issue arose from a race condition involving the state of the page where certain threads were updating different versions of the same page.

I order to fix your specific issue go ahead and lock and unlock the threads before in after updating the page in the page function, like this:

   import Threading

   lock = Threading.lock

   ...

    def updatePage(self,dt,page: Page):
        lock.aquire()
        page.update()
        lock.release()

If that doesn't work maybe try adding it to your RefreshItems function as well.

vishnu-rvb commented 1 day ago

@ethans333 yeah i too fixed my issue by disabling page update when controls are added but concern wise it should be page.updates responsibility to sort out its internal race conditions.

@ndonkoHenri i will share a demo reproducing code for future references soon

ethans333 commented 1 day ago

Agreed