Open mdickinson opened 4 years ago
Note that there's an existing workaround which isn't horrible: instead of using configure_traits
to start the event loop, start the event loop the asyncio way, and then use edit_traits
instead of configure_traits
.
I think... with configure_traits, the event loop is started here for Qt: https://github.com/enthought/traitsui/blob/b23a4cc87b60b4abc777d33aa583ad3310cbb553/traitsui/qt4/view_application.py#L129-L131
Not sure if asyncio can work with wx, but here it the wx counterpart: https://github.com/enthought/traitsui/blob/b23a4cc87b60b4abc777d33aa583ad3310cbb553/traitsui/wx/view_application.py#L137-L141)
Perhaps we just need to provide another implementation of this view_application
?
Just dropping in to say this would be useful for us. As discussed offline, using async requests to keep an application updated with the status of a long-running job that's being run remotely is something we've been playing around with a little bit.
I've got a small version working as Mark describes, using the same workaround.
There's two places we'd need to make changes: Pyface GUI
object and TraitsUI ViewApplication
. This could be improved by having ViewApplication
use Pyface GUI
rather than the lower-level code it currently uses (which could probably then be removed).
I don't think I'd be in favour of having asyncqt
be a required dependency of Pyface/TraitsUI (but I could be convinced otherwise, I guess). There may be an argument for pushing generic event loop code somewhere outside of Pyface: we have discussed dispatch="async"
as a potential option for Traits handlers (it is almost trivial to implement), so I could see an argument where we go all-in that Traits event loops are always AsyncIO event loops, and Pyface and TraitsUI just make sure that they use one from the appropriate backend.
There is https://github.com/sirk390/wxasync but I haven't looked for code quality. In principle integrating any event loop with async should be feasible.
I don't think I'd be in favour of having
asyncqt
be a required dependency of Pyface/TraitsUI
No, me neither. I just want a way to tell Pyface / TraitsUI: "here's an asyncio-compatible event loop. use it!", or maybe "here's a factory that creates an asyncio-compatible event loop. use it!", or perhaps "grab the current asyncio event loop (yay global state!) and use that".
So the first step is probably to figure out how this would/could/should look to a user.
One possible approach would be to contribute an asyncqt
toolkit via setup.py
(possibly in a different library, such as Traits Futures) which is almost the same as the qt
toolkit but has a different implementation of the init.py
module (https://github.com/enthought/pyface/blob/master/pyface/ui/qt4/init.py) which sets up asyncio dispatch and special-cases the GUI object to pull in an async-aware version.
A similar thing would need to be done for TraitsUI and Enable (and possibly Mayavi), and I don't think we're quite at the point where we could pull it off.
But this would have minimal impact on code as written - just switch the toolkit and you suddenly have async support.
From some experimentation last week, integrating
asyncqt
into a TraitsUI GUI works almost seamlessly, making it easy to use otherasyncio
-aware packages likeaiohttp
from a TraitsUI GUI. I think this could be extremely valuable for things like making async requests from a running GUI.The one sticking point is starting the event loop: currently, the Qt backend for TraitsUI/Pyface starts the Qt event loop directly, via a
qt_app.exec_
call. To integrate withasyncqt
, we instead need to be able to start the event loop through something like the asyncioget_event_loop().run_forever()
. (Note that Pyface would not need any awareness ofasyncqt
for this; only awareness ofasyncio
.)What's the easiest way to make it possible in Pyface to start the event loop through
asyncio
instead of directly through Qt?[It wasn't clear to me whether this issue belongs in Pyface or TraitsUI; feel free to migrate if necessary]