PyQt now also uses asyncio and its thread contains the main loop

This commit is contained in:
Christoph Stahl 2024-10-10 15:39:53 +02:00
parent bf2e854cdd
commit 089de1ff93
4 changed files with 50 additions and 19 deletions

15
poetry.lock generated
View file

@ -1,4 +1,4 @@
# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand.
# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand.
[[package]]
name = "aiohappyeyeballs"
@ -1452,6 +1452,17 @@ files = [
{file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"},
]
[[package]]
name = "qasync"
version = "0.27.1"
description = "Python library for using asyncio in Qt-based applications"
optional = false
python-versions = ">=3.8,<4.0"
files = [
{file = "qasync-0.27.1-py3-none-any.whl", hash = "sha256:5d57335723bc7d9b328dadd8cb2ed7978640e4bf2da184889ce50ee3ad2602c7"},
{file = "qasync-0.27.1.tar.gz", hash = "sha256:8dc768fd1ee5de1044c7c305eccf2d39d24d87803ea71189d4024fb475f4985f"},
]
[[package]]
name = "qrcode"
version = "7.4.2"
@ -1961,4 +1972,4 @@ server = ["alt-profanity-check"]
[metadata]
lock-version = "2.0"
python-versions = "^3.9"
content-hash = "a53a034e3cccdb40b71d708df2e82b2e5840639414a3bc727a31cb27b7a0d286"
content-hash = "8d19f746a97720e770c47baed26571c2e53aa79a5e7a5a10f62450f519f211a8"

View file

@ -43,6 +43,7 @@ pyyaml = { version = "^6.0.1", optional = true }
alt-profanity-check = {version = "^1.4.1", optional = true}
pyqt6 = {version="^6.7.1", optional = true}
mpv = "^1.0.7"
qasync = "^0.27.1"
[tool.poetry.group.dev.dependencies]
types-pyyaml = "^6.0.12.12"

View file

@ -452,6 +452,7 @@ class Client:
:type config: dict[str, Any]
:rtype: None
"""
print("Starting client")
self.loop = asyncio.get_running_loop()
@ -495,7 +496,9 @@ class Client:
def create_async_and_start_client(
config: dict[str, Any], queue: Optional[Queue[LogRecord]] = None
config: dict[str, Any],
queue: Optional[Queue[LogRecord]] = None,
client: Optional[Client] = None,
) -> None:
"""
Create an asyncio event loop and start the client.
@ -512,7 +515,8 @@ def create_async_and_start_client(
if queue is not None:
logger.addHandler(QueueHandler(queue))
client = Client(config)
if client is None:
client = Client(config)
asyncio.run(client.start_client(config))

View file

@ -1,15 +1,18 @@
import asyncio
from io import BytesIO
import sys
import logging
from logging.handlers import QueueListener
from multiprocessing import Process, Queue
# from multiprocessing import Process, Queue
from queue import Queue
from collections.abc import Callable
from datetime import datetime
import os
from functools import partial
import random
from typing import TYPE_CHECKING, Any, Optional
import multiprocessing
import threading
import secrets
import string
import signal
@ -24,11 +27,11 @@ try:
except ImportError:
pass
from qasync import QEventLoop, QApplication
from PyQt6.QtCore import QTimer, Qt
from PyQt6.QtGui import QCloseEvent, QIcon, QPixmap
from PyQt6.QtWidgets import (
QApplication,
# QApplication,
QCheckBox,
QComboBox,
QDateTimeEdit,
@ -54,7 +57,7 @@ from qrcode.main import QRCode
import platformdirs
from . import resources # noqa
from .client import create_async_and_start_client, default_config
from .client import Client, create_async_and_start_client, default_config
from .sources import available_sources
from .config import (
@ -626,8 +629,9 @@ class SyngGui(QMainWindow):
if os.name != "nt":
self.setWindowIcon(QIcon(":/icons/syng.ico"))
self.syng_server: Optional[Process] = None
self.syng_client: Optional[Process] = None
self.loop = asyncio.get_event_loop()
self.syng_server: Optional[threading.Thread] = None
self.syng_client: Optional[threading.Thread] = None
self.syng_client_logging_listener: Optional[QueueListener] = None
self.configfile = os.path.join(platformdirs.user_config_dir("syng"), "config.yaml")
@ -752,9 +756,11 @@ class SyngGui(QMainWindow):
return
if not self.syng_client.is_alive():
print("Client is not running")
self.syng_client = None
self.set_client_button_start()
else:
print("Client is running")
self.set_client_button_stop()
def set_client_button_stop(self) -> None:
@ -767,24 +773,28 @@ class SyngGui(QMainWindow):
if self.syng_client is None or not self.syng_client.is_alive():
self.save_config()
config = self.gather_config()
queue: Queue[logging.LogRecord] = multiprocessing.Queue()
queue: Queue[logging.LogRecord] = Queue()
self.syng_client_logging_listener = QueueListener(
queue, LoggingLabelHandler(self.notification_label)
)
self.syng_client_logging_listener.start()
self.syng_client = multiprocessing.Process(
target=create_async_and_start_client, args=[config, queue]
)
self.syng_client.start()
# self.syng_client = multiprocessing.Process(
# target=create_async_and_start_client, args=[config, queue]
# )
self.client = Client(config)
asyncio.run_coroutine_threadsafe(self.client.start_client(config), self.loop)
# self.syng_client = threading.Thread(
# target=create_async_and_start_client, args=[config, queue, self.client]
# )
# self.syng_client.start()
self.notification_label.setText("")
self.timer.start(500)
self.set_client_button_stop()
else:
self.syng_client.terminate()
self.client.quit_callback()
self.syng_client.join(1.0)
self.syng_client.kill()
self.set_client_button_start()
# def start_syng_server(self) -> None:
@ -853,6 +863,9 @@ def run_gui() -> None:
signal.signal(signal.SIGINT, signal.SIG_DFL)
app = QApplication([])
event_loop = QEventLoop(app)
asyncio.set_event_loop(event_loop)
if os.name == "nt":
app.setWindowIcon(QIcon(os.path.join(base_dir, "syng.ico")))
else:
@ -861,7 +874,9 @@ def run_gui() -> None:
app.setDesktopFileName("rocks.syng.Syng")
window = SyngGui()
window.show()
app.exec()
# app.exec()
with event_loop:
event_loop.run_forever()
if __name__ == "__main__":