pythonpython-asynciopyside6

Trouble connecting an async function to a PySide6 button signal


I'm currently working on a Python application using PySide6 for the GUI. I have a QPushButton and I want to connect its clicked signal to an asynchronous function, but I'm running into some issues.

Here's a simplified version of my code:

from PySide6.QtWidgets import QApplication, QMainWindow, QPushButton


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Async Function Example")
        self.login_button = QPushButton("Login", self)
        self.login_button.clicked.connect(self.login_button_clicked)

    async def login_button_clicked(self):
        # Perform async tasks
        print("test async button clicked!")


app = QApplication([])
window = MainWindow()
window.show()
app.exec()

However, when I run this code, I receive the following error:

RuntimeWarning: coroutine 'MainWindow.login_button_clicked' was never awaited
  app.exec()

I understand that the error is caused by not awaiting the asynchronous function. I have tried using the await keyword before the method call when connecting the signal, but PySide6 doesn't directly support connecting asynchronous functions to signals.

I've also attempted to work around this by using a helper function or a coroutine runner, but without success.

Could someone please guide me on how to properly connect an asynchronous function to a PySide6 button signal? Is there a recommended approach or workaround for this situation? Any code examples or suggestions would be greatly appreciated.

Thank you in advance for your help!


Solution

  • I ran into the same issue and I have created a package to solve it. The asyncio need to be setup properly to be able to work with PySide6.

    Your code can be changed to:

    pip install AsyncioPySide6
    
    import sys
    from AsyncioPySide6 import AsyncioPySide6
    from PySide6.QtWidgets import QApplication, QMainWindow, QPushButton
    
    
    class MainWindow(QMainWindow):
        def __init__(self):
            super().__init__()
            self.setWindowTitle("Async Function Example")
            self.login_button = QPushButton("Login", self)
            self.login_button.clicked.connect(self.login_button_clicked)
    
        def login_button_clicked(self):
            async def asyncTask():
                # Async wait for 4 seconds
                await asyncio.timeout(4)
    
                # Perform async tasks
                print("test async button clicked!")
                self.login_button.setEnabled(False)
            AsyncioPySide6.runTask(asyncTask())
    
    
    app = QApplication(sys.argv)
    with AsyncioPySide6.use_asyncio():
        main_window = MainWindow()
        main_window.show()
        app.exec()
    
    

    Basically, you can execute any asynchronous task by using AsyncioPySide6.runTask. You can even manipulate GUI components within async tasks without using QMetaObject.invoke.