[PyQt] Fwd: Integrating asyncio with Qt event loop?

Erik Hvatum ice.rikh at gmail.com
Thu Oct 16 20:54:44 BST 2014


Hi Piotr,

Arve and I meant to keep the discussion on the list, but I sometimes forgot
to reply to the list address and instead replied directly.  The full thread
is reproduced below.

FYI, if you just want a resumable slot function and you don't care about
futures or anything else in asyncio, it can be done using generator
expressions (see attached file for an example, or contents pasted in at the
very end of this email).

Cheers,
Erik

Hi!

I found your post titled "Integrating asyncio with Qt event loop?" at
http://www.riverbankcomputing.com/pipermail/pyqt/2014-August/034628.html
but looking at quotes inside the post it seems to be continuation of
earlier discussion. I would like to know where this discussion took
place. Could you please point me to it?

Thank you in advance.

Regards,
Piotr

---------- Forwarded message ----------
From: Erik Hvatum <ice.rikh at gmail.com>
Date: Thu, Aug 7, 2014 at 5:13 PM
Subject: Re: [PyQt] Integrating asyncio with Qt event loop?
To: Arve Knudsen <arve.knudsen at gmail.com>, "pyqt at riverbankcomputing.com" <
pyqt at riverbankcomputing.com>


Brilliant!  Works like a charm; our code
<https://github.com/erikhvatum/zplab/blob/68328cb37289bdf94ae0b10d4dc5e9583578934d/acquisition/dm6000b/function_units/objective_turret.py>
is going to get a lot cleaner.

Tusen takk,
Erik


On Thu, Aug 7, 2014 at 4:29 PM, Arve Knudsen <arve.knudsen at gmail.com> wrote:

> Hi Erik
>
> I think you could use an asyncio.Future for this purpose. You can yield
> from the Future, and set its result upon arrival of the signal. I've
> concocted an example program that should show what I mean; it creates a
> 2-second timer which is waited on asynchronously, once its timeout fires
> the program exits:
>
>     import quamash
>     import asyncio
>     from PyQt5.QtWidgets import *
>     from PyQt5.QtCore import *
>
>
>     @asyncio.coroutine
>     def _go():
>         def on_timeout():
>             print('Timeout')
>             fut.set_result(True)
>
>         fut = asyncio.Future()
>         timer = QTimer()
>         timer.setSingleShot(True)
>         timer.setInterval(2000)
>         timer.start()
>         timer.timeout.connect(on_timeout)
>         print('Yielding until signal...')
>         yield from fut
>         print('Continuing execution after yield from')
>
>     with quamash.QEventLoop(app=QApplication([])) as loop:
>         w = QMainWindow()
>         w.show()
>         loop.run_until_complete(_go())
>     print('Coroutine has ended')
>
> HTH,
> Arve
>
>
> On Thu, Aug 7, 2014 at 12:31 AM, Erik Hvatum <ice.rikh at gmail.com> wrote:
>
>> Thank you :)
>>
>> A quick question to help as I dig into this: how might one go about
>> "yield from wait_for_a_qt_signal"?  That is, I want my coroutine to resume
>> execution when some certain signal is emitted.  Perhaps this desire
>> indicates that I'm going about things the wrong way...
>>
>> -Erik
>>
>> PS: forgot to reply to the list the first time around
>>
>>
>> On Sat, Jul 5, 2014 at 12:34 PM, Arve Knudsen <arve.knudsen at gmail.com>
>> wrote:
>>
>>> Quamash, in the unix branch (
>>> https://github.com/aknuds1/quamash/tree/unix), now works perfectly for
>>> thread and subprocess execution on OS X, Linux and Windows, I'm pleased to
>>> say. Would love some feedback.
>>>
>>> Arve
>>>
>>>
>>> On Tue, Jul 1, 2014 at 3:12 PM, Arve Knudsen <arve.knudsen at gmail.com>
>>> wrote:
>>>
>>>> Now, even subprocess execution works. At least on Windows/PyQt, haven't
>>>> tested on other platforms.
>>>>
>>>> Arve
>>>>
>>>>
>>>> On Mon, Jun 30, 2014 at 4:03 PM, Arve Knudsen <arve.knudsen at gmail.com>
>>>> wrote:
>>>>
>>>>> Erik, Tamás, feel free to try my Quamash fork
>>>>> <https://github.com/aknuds1/quamash>, it's currently quite
>>>>> functional, except that subprocess execution is somehow broken.
>>>>>
>>>>> Arve
>>>>>
>>>>> On Fri, Jun 27, 2014 at 1:34 PM, Arve Knudsen <arve.knudsen at gmail.com>
>>>>> wrote:
>>>>>
>>>>>> My fork is now semi-functional with Python 3.4 and PyQt 5. I can at
>>>>>> least perform simple asynchronous tasks within a Qt application, but lots
>>>>>> remain to implement.
>>>>>>
>>>>>> Arve
>>>>>>
>>>>>>
>>>>>> On Fri, Jun 27, 2014 at 9:24 AM, Arve Knudsen <arve.knudsen at gmail.com
>>>>>> > wrote:
>>>>>>
>>>>>>> I've created a fork on GitHub: https://github.com/aknuds1/quamash.
>>>>>>> Do you know where to locate information on writing an asyncio event loop
>>>>>>> though? Not sure where to begin.
>>>>>>>
>>>>>>> Thanks,
>>>>>>> Arve
>>>>>>>
>>>>>>>
>>>>>>> On Thu, Jun 26, 2014 at 9:30 PM, Arve Knudsen <
>>>>>>> arve.knudsen at gmail.com> wrote:
>>>>>>>
>>>>>>>> Thanks. I'm thinking I might try to modify his code, if it isn't
>>>>>>>> too much work.
>>>>>>>>
>>>>>>>> Arve
>>>>>>>>
>>>>>>>>
>>>>>>>> On Thu, Jun 26, 2014 at 7:32 PM, Tamás Bajusz <gbtami at gmail.com>
>>>>>>>> wrote:
>>>>>>>>
>>>>>>>>> Unfortunately, I know that github project only. (
>>>>>>>>> https://github.com/harvimt/quamash)
>>>>>>>>> Try to contact him at mark.harviston at gmail.com
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> On Thu, Jun 26, 2014 at 7:27 PM, Arve Knudsen <
>>>>>>>>> arve.knudsen at gmail.com> wrote:
>>>>>>>>>
>>>>>>>>>> Tamás, has Mark Harviston's implementation been updated to work
>>>>>>>>>> with the latest Python (3.4)? I think I read somewhere that it's based on
>>>>>>>>>> an outdated API.
>>>>>>>>>>
>>>>>>>>>> Arve
>>>>>>>>>>
>>>>>>>>>> On Thu, Jun 26, 2014 at 6:29 PM, Tamás Bajusz <gbtami at gmail.com>
>>>>>>>>>> wrote:
>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> http://haypo-notes.readthedocs.org/asyncio.html#replacing-the-event-loop
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> On Thu, Jun 26, 2014 at 5:20 PM, Arve Knudsen <
>>>>>>>>>>> arve.knudsen at gmail.com> wrote:
>>>>>>>>>>>
>>>>>>>>>>>>  Hi guys
>>>>>>>>>>>>
>>>>>>>>>>>> I am looking to integrate Python 3.4 asyncio
>>>>>>>>>>>> <https://docs.python.org/3/library/asyncio.html> with Qt's
>>>>>>>>>>>> event loop (via PyQt 5), specifically in order to asynchronously monitor
>>>>>>>>>>>> output (stdout/stderr) from a child process. Maybe this is somewhat
>>>>>>>>>>>> off-topic for this list, but can someone tell me if such integration exists
>>>>>>>>>>>> (and works)?
>>>>>>>>>>>>
>>>>>>>>>>>> Thanks,
>>>>>>>>>>>> Arve
>>>>>>>>>>>>
>>>>>>>>>>>> _______________________________________________
>>>>>>>>>>>> PyQt mailing list    PyQt at riverbankcomputing.com
>>>>>>>>>>>> http://www.riverbankcomputing.com/mailman/listinfo/pyqt
>>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>
>>>>>>>>
>>>>>>>
>>>>>>
>>>>>
>>>>
>>>
>>
>> _______________________________________________
>> PyQt mailing list    PyQt at riverbankcomputing.com
>> http://www.riverbankcomputing.com/mailman/listinfo/pyqt
>>
>
>
 #!/usr/bin/env python3
# By Erik Hvatum, 2014.  Copyright waived; the contents of this file
represent a trivial example, are public# domain, and may be used for
any purpose and/or relicensed without attribution.

from PyQt5 import Qt
def coroutine(func):    '''This is meant to act as a decorator.  Its
purpose is to call next once for you upon instantiation of    a
generator so that you don't have to.  If you want separate
instantiation and execution, for example    because you wish to make a
generator and kick it off later, don't use this.'''    def
start(*args, **kwargs):        cr = func(*args, **kwargs)
next(cr)        return cr    return start
class Dlg(Qt.QDialog):    def __init__(self):
super().__init__()        self.setAttribute(Qt.Qt.WA_DeleteOnClose)
        l = Qt.QHBoxLayout()        self.setLayout(l)
        self.resumable_operation = None
self.resumable_operation_step_count = 5
self.resumable_operation_step_time = 2
        self.do_timer = Qt.QTimer(self)
self.do_timer.setSingleShot(True)
self.do_timer.timeout.connect(self.do_timer_fired_slot)
        self.do_button = Qt.QPushButton('start')
self.do_button.clicked.connect(self.do_button_clicked_slot)
l.addWidget(self.do_button)
        self.abort_button = Qt.QPushButton('abort')
self.abort_button.clicked.connect(self.abort_button_clicked_slot)
  self.abort_button.setEnabled(False)
l.addWidget(self.abort_button)
        self.status_label = Qt.QLabel('ready to start')
l.addWidget(self.status_label)
        self.show()
    def do_button_clicked_slot(self):        if
self.resumable_operation is None:            self.resumable_operation
= self.resumable_operation_proc()            # Because
resumable_operation_proc has the @coroutine decorator,
self.resumable_operation.next() has            # been called and
resumable_operation_proc is now executing        else:
self.resumable_operation.send(True)
    def abort_button_clicked_slot(self):        try:            if
self.resumable_operation is not None:
self.resumable_operation.send(False)        except StopIteration:
      pass
    def do_timer_fired_slot(self):        try:            if
self.resumable_operation is not None:
self.resumable_operation.send(True)        except StopIteration:
     pass
    @coroutine    def resumable_operation_proc(self):
self.do_button.setText('next step')
self.abort_button.setEnabled(True)
        step = 1        while True:
self.do_button.setEnabled(False)
self.status_label.setText('doing step {}'.format(step))
self.do_timer.start(self.resumable_operation_step_time * 1000)
            keep_going = yield            if not keep_going or step ==
self.resumable_operation_step_count:                break
step += 1            self.do_button.setEnabled(True)
self.status_label.setText('ready for step {}'.format(step))
keep_going = yield            if not keep_going:                break
        self.do_timer.stop()        self.do_button.setText('start')
    self.do_button.setEnabled(True)
self.abort_button.setEnabled(False)
self.status_label.setText('ready to start')
self.resumable_operation = None
if __name__ == '__main__':    import sys    app =
Qt.QApplication(sys.argv)    dlg = Dlg()    app.exec_()
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.riverbankcomputing.com/pipermail/pyqt/attachments/20141016/82ce7042/attachment-0001.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: resumable_slot_with_generator_example.py
Type: text/x-python
Size: 3511 bytes
Desc: not available
URL: <http://www.riverbankcomputing.com/pipermail/pyqt/attachments/20141016/82ce7042/attachment-0001.py>


More information about the PyQt mailing list