Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"RuntimeError: no running event loop" from asyncio.create_task #121

Open
SJChannel opened this issue Apr 25, 2024 · 3 comments
Open

"RuntimeError: no running event loop" from asyncio.create_task #121

SJChannel opened this issue Apr 25, 2024 · 3 comments

Comments

@SJChannel
Copy link

I am testing with python 3.12.3 and PySide6 6.7.0. When using qasync >= 0.24.2, the attached script fails on the call to asyncio.create_task with this exception:

Traceback (most recent call last):
  File "/Users/jdp/python/./qtest.py", line 38, in <module>
    aw = MyAppWindow()
         ^^^^^^^^^^^^^
  File "/Users/jdp/python/./qtest.py", line 22, in __init__
    self.task = asyncio.create_task(self.my_task())
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/local/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/asyncio/tasks.py", line 417, in create_task
    loop = events.get_running_loop()
           ^^^^^^^^^^^^^^^^^^^^^^^^^
RuntimeError: no running event loop
sys:1: RuntimeWarning: coroutine 'MyAppWindow.my_task' was never awaited

The failure does not occur with qasync 0.24.0. Uncommenting the statement

#asyncio.events._set_running_loop(loop)

works around the problem, but it is undesirable because it uses a private API.
qtest.py.txt

@SJChannel
Copy link
Author

A different solution that seems to work OK is to create the event loop like this:

loop = qasync.QEventLoop(qApp, already_running=True)

Is that how it should be done? The docstring for class _QEventLoop says, "If the event loop shall be used with an existing and already running QApplication it must be specified in the constructor via already_running=True". I am a little bit confused by that. In my example, the QApplication does indeed exist, but it is not yet running when the QEventLoop is created. (I.e., QApplication.exec() has not been called yet.)

@shseah601
Copy link

When you are within MainWindow class, my work around is to run asyncio.create_task in QTimer

class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)
 
        # function provided from .ui file generated to .py
        self.setupUi(self)

        ... rest of your code / configuration 

        # Trigger after event loop is set for asyncio
        QtCore.QTimer.singleShot(10, self.setup_after_asyncio_event_loop)
    
    def setup_after_asyncio_event_loop(self):
        asyncio.create_task(...)
        asyncio.create_task(...)

With this you most probably running asyncio.create_task after event loop is set, and you wont need to make any changes to event loop. I tried QTimer with 1ms do works, but use 10ms to make sure that the program has more time to setup the event loop before it get used in the rest of the program.

Hope this helps.

@iamthebull
Copy link

I'm also having the same issue. Is this a bug or just something we will always have to work around? I used this workaround.

When you are within MainWindow class, my work around is to run asyncio.create_task in QTimer

My program:

import sys
import asyncio
from qasync import QApplication, QEventLoop, asyncSlot
from PySide6.QtWidgets import QMainWindow, QLabel
from PySide6.QtCore import QTimer

async def hello():
	print('hello')

class MainWindow(QMainWindow):
	def __init__(self) -> None:
		super().__init__()
		self.setWindowTitle('Client App')

		self.label = QLabel('Main Window')
		self.setCentralWidget(self.label)
		QTimer.singleShot(100, self.ready)

	@asyncSlot()
	async def ready(self):
		task = asyncio.create_task(hello())

	def showEvent(self, event):
		print('main window show event')
	
if __name__ == "__main__":
	print('app starting')

	app = QApplication(sys.argv)

	event_loop = QEventLoop(app)
	asyncio.set_event_loop(event_loop)

	app_close_event = asyncio.Event()
	app.aboutToQuit.connect(app_close_event.set)

	main_window = MainWindow()
	main_window.show()

	with event_loop:
		event_loop.run_until_complete(app_close_event.wait())

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants