I’m trying to execute code inside a jupyter kernel in a Qt application. I have the below snipplet that is supposed to asynchronously run the code and then print the result
JavaScript
x
41
41
1
import sys
2
import asyncio
3
4
import qasync
5
from qasync import QApplication
6
from PySide6.QtWidgets import QWidget
7
from jupyter_client import AsyncKernelManager
8
9
10
CODE = """print('test')"""
11
12
13
class Test():
14
def __init__(self):
15
kernel_manager = AsyncKernelManager()
16
kernel_manager.start_kernel()
17
18
self.client = kernel_manager.client()
19
self.client.start_channels()
20
21
def run(self):
22
loop = asyncio.get_event_loop()
23
asyncio.ensure_future(self.execute(), loop=loop)
24
25
async def execute(self):
26
self.client.execute(CODE)
27
response: Coroutine = self.client.get_shell_msg()
28
print('Before')
29
res = await response
30
print('After')
31
32
33
def main():
34
app = QApplication(sys.argv)
35
test = Test()
36
test.run()
37
sys.exit(app.exec())
38
39
40
main()
41
With the above I get the following output
JavaScript
1
6
1
/tmp/test/test.py:16: RuntimeWarning: coroutine 'KernelManager._async_start_kernel' was never awaited
2
kernel_manager.start_kernel()
3
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
4
/tmp/test/test.py:22: DeprecationWarning: There is no current event loop
5
loop = asyncio.get_event_loop()
6
so trying to adjust the code according to an example from qasync to something like
JavaScript
1
9
1
async def main():
2
app = QApplication(sys.argv)
3
test = Test()
4
test.run()
5
sys.exit(app.exec())
6
7
8
qasync.run(main())
9
will result in the following exception
JavaScript
1
13
13
1
Traceback (most recent call last):
2
File "/tmp/test/test.py", line 40, in <module>
3
qasync.run(main())
4
File "/tmp/test/.venv/lib/python3.10/site-packages/qasync/__init__.py", line 821, in run
5
return asyncio.run(*args, **kwargs)
6
File "/usr/lib/python3.10/asyncio/runners.py", line 44, in run
7
return loop.run_until_complete(main)
8
File "/tmp/test/.venv/lib/python3.10/site-packages/qasync/__init__.py", line 409, in run_until_complete
9
return future.result()
10
File "/tmp/test/test.py", line 34, in main
11
app = QApplication(sys.argv)
12
RuntimeError: Please destroy the QApplication singleton before creating a new QApplication instance.
13
I’m pretty at lost at this point, does anyone know how to get this to work?
Advertisement
Answer
You have to create a QEventLoop, also start_kernel must use await. On the other hand it first imports PySide6 and then the other libraries that depend on PySide6 like qasync so that it can deduce the correct Qt binding.
JavaScript
1
48
48
1
import sys
2
import asyncio
3
from functools import cached_property
4
5
from PySide6.QtWidgets import QApplication
6
import qasync
7
8
from jupyter_client import AsyncKernelManager
9
10
11
CODE = """print('test')"""
12
13
14
class Test:
15
@cached_property
16
def kernel_manager(self):
17
return AsyncKernelManager()
18
19
@cached_property
20
def client(self):
21
return self.kernel_manager.client()
22
23
async def start(self):
24
await self.kernel_manager.start_kernel()
25
self.client.start_channels()
26
asyncio.ensure_future(self.execute())
27
28
async def execute(self):
29
self.client.execute(CODE)
30
response = self.client.get_shell_msg()
31
print("Before")
32
res = await response
33
print("After", res)
34
35
36
def main():
37
app = QApplication(sys.argv)
38
loop = qasync.QEventLoop(app)
39
asyncio.set_event_loop(loop)
40
test = Test()
41
asyncio.ensure_future(test.start())
42
with loop:
43
loop.run_forever()
44
45
46
if __name__ == "__main__":
47
main()
48