Skip to content

Completion of concurrent tasks after run_forever. #55

Closed
@draustin

Description

@draustin

It seems that run_forever has the effect of calling QApplication.exec() while simultaneously running the event loop tasks. When exec returns, the event loop stops and run_forever returns. At this point I would like to send a stop signal to the other tasks to perform cleanup actions, and then restart the loop and run it until the tasks are complete. I came up with a solution, pasted below. This issue is a suggestion to elaborate the docstring / add an example, and to help others.

Thanks for your work.

import sys

from PyQt5 import QtWidgets
import qasync
import asyncio


class Widget(QtWidgets.QWidget):
    """A widget with a single label."""

    def __init__(self):
        QtWidgets.QWidget.__init__(self)

        self._label = QtWidgets.QLabel()
        b0 = QtWidgets.QHBoxLayout()
        self.setLayout(b0)
        b0.addWidget(self._label)

    def set_text(self, text):
        """Set the text of the label."""
        self._label.setText(text)


stop_flag = False


async def start_counting(widget):
    try:
        n = 0
        while not stop_flag:
            widget.set_text(str(n))
            await asyncio.sleep(1)
            n += 1
        print('Counting stopped.')
    except BaseException as e:
        print('Counting cancelled.')


app = QtWidgets.QApplication(sys.argv)
widget = Widget()
widget.show()
loop = qasync.QEventLoop(app)
task = loop.create_task(start_counting(widget))
# Runs until last widget closed, like QApplication.exec().
loop.run_forever()
assert not loop.is_running()
# Looking at the __init__.py in qasync, it seems that it stopped running because QApplication.exec() returned.
# However, our counting task is incomplete.
tasks = asyncio.all_tasks()
assert len(tasks) == 1

# Send stop signal. Alternative, can cancel.
stop_flag = True
# task.cancel()

# Restart the loop to finish the tasks. In this example there is only one, but gather them for generality.
gathered = asyncio.gather(*tasks)
loop.run_until_complete(gathered)

# The following does not work.
# loop.run_forever()

print('All done.')

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions