I'm currently diving into Flexx for making a UI to my Python program. I'm starting to get the hang of it but I'm running into a problem.
I need to be able to call a PyComponent
's method from outside the scope of the App
. I understand that app.cls
gives the class that was used to instanciate the App, but it's not the actual instance, so I can't do something like app.cls.my_method(...)
.
Is there a way to get the instance of the component inside the app wrapper, only knowing the App
instance?
Thanks!
EDIT: After looking at the source, I found the mostly undocumented AppManager
and Session
definitions and could get a reference to the component's instance with:
from flexx.app import manager
app_instance = manager.get_connections('MyAppName')[0].app
But if I call one of its methods from a watchdog.events.FileSystemEventHandler
instantiated by the watchdog
library, I get the following traceback:
File "myfile.py", line 37, in on_created
manager.get_connections('MyAppName')[0].app.update_verbose(False)
File "lib\site-packages\flexx\event\_action.py", line 150, in __call__
if loop.can_mutate(ob):
File "lib\site-packages\flexx\event\_loop.py", line 85, in can_mutate
active = self.get_active_component()
File "lib\site-packages\flexx\event\_loop.py", line 103, in get_active_component
if len(self._local._active_components) > 0:
AttributeError: '_thread._local' object has no attribute '_active_components'
Note that update_verbose
is a Flexx action that mutates a property. I suspect an issue where the watchdog handler is running on a different thread but I can't see what to change...
As suspected, the problem probably comes from the fact that the FileSystemEventHandler
is running on a different thread than the Flexx loop. Thanks to the author almarklein for his help on solving this.
The solution was to get a reference to the root object, not with the complicated method described above in my question, but rather with the return value from the launch
call:
root = app.launch('app')
Then inside the event handler, tell the main loop to call my method (decorated with @flx.action
):
flx.loop.call_soon(root.my_action, 'argument`)
Hope this helps someone some day!