innodatalabs / triq

Hackery to use trio async framework with PyQt
MIT License
2 stars 0 forks source link

How to use qtrio? #5

Open mkroutikov opened 4 years ago

mkroutikov commented 4 years ago

Looks like the latest addition to qtrio (open_emissions_nursery) is all we need.

Here is a sketch of the code:

import qtrio
import inspect

_diaper = None

def aconnect(signal, async_callable):
    '''Connects signal to an async handler'''
    if _diaper is None:
        raise RuntimeError('I am super confused. Did you forget to use run()?')
    _diaper.connect(signal, async_callable)

def run(ui_builder, *av):
   '''Main application runner. ui_builder is sync or async function where app is constructed and showed'''
    runner = qtrio.Runner()

    async def main():
        global _diaper
        async with qtrio.open_emissions_nursery(until=runner.application.lastWindowClosed) as _diaper:
            x = ui_builder(*av)
            if inspect.iscoroutine(x):
                await x

    runner.run(main)

Note that presently we:

  1. Do not care much for signal disconnect. Because all connections are "static" and never change. Hence a simple global emissions nursery
  2. We do not want pass diaper to all presenters (that would require a massive refactoring of the existing apps). Hence global function aconnect to connect signal to an async handler.

To use this, just do something like:

def ui_builder():  # can also be async
   ui = Ui()
   controller = Controller()
   presenter = Presenter(ui, controller)  # this does all the connections, may use aconnect if target is async
   ui.show()

if __name__ == '__main__':
   run(ui_builder)

Basically the above provides a minimally intrusive way to incorporate async jobs into legacy apps. cc: @altendkey

altendky commented 4 years ago
  1. I'm not sure I ever got my head around the nuances but FYI https://bugreports.qt.io/browse/PYSIDE-1313 was triggered in the example included there in part by having left a signal connected. One of those 'I do not care but if I clean it up maybe it'll be a bit more robust' kind of situations. You know, cleaning up after yourself is just good practice even if it usually doesn't matter.
  2. Yep, QTrio doesn't force a global emissions nursery on you but it's easy enough to make one for yourself if that's what you want.
nicoddemus commented 4 years ago

About 1), when connecting signals to async slots using an emissions nursery, do the normal connection rules apply? I mean, if either the signal owner or the slot owner are destroyed, the connection is undone automatically, so I wonder if the same happens here.

altendky commented 4 years ago

I certainly haven't dealt with that explicitly. See https://github.com/altendky/qtrio/issues/97.