PyQt now also uses asyncio and its thread contains the main loop
This commit is contained in:
parent
bf2e854cdd
commit
089de1ff93
4 changed files with 50 additions and 19 deletions
15
poetry.lock
generated
15
poetry.lock
generated
|
@ -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]]
|
[[package]]
|
||||||
name = "aiohappyeyeballs"
|
name = "aiohappyeyeballs"
|
||||||
|
@ -1452,6 +1452,17 @@ files = [
|
||||||
{file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"},
|
{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]]
|
[[package]]
|
||||||
name = "qrcode"
|
name = "qrcode"
|
||||||
version = "7.4.2"
|
version = "7.4.2"
|
||||||
|
@ -1961,4 +1972,4 @@ server = ["alt-profanity-check"]
|
||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "2.0"
|
lock-version = "2.0"
|
||||||
python-versions = "^3.9"
|
python-versions = "^3.9"
|
||||||
content-hash = "a53a034e3cccdb40b71d708df2e82b2e5840639414a3bc727a31cb27b7a0d286"
|
content-hash = "8d19f746a97720e770c47baed26571c2e53aa79a5e7a5a10f62450f519f211a8"
|
||||||
|
|
|
@ -43,6 +43,7 @@ pyyaml = { version = "^6.0.1", optional = true }
|
||||||
alt-profanity-check = {version = "^1.4.1", optional = true}
|
alt-profanity-check = {version = "^1.4.1", optional = true}
|
||||||
pyqt6 = {version="^6.7.1", optional = true}
|
pyqt6 = {version="^6.7.1", optional = true}
|
||||||
mpv = "^1.0.7"
|
mpv = "^1.0.7"
|
||||||
|
qasync = "^0.27.1"
|
||||||
|
|
||||||
[tool.poetry.group.dev.dependencies]
|
[tool.poetry.group.dev.dependencies]
|
||||||
types-pyyaml = "^6.0.12.12"
|
types-pyyaml = "^6.0.12.12"
|
||||||
|
|
|
@ -452,6 +452,7 @@ class Client:
|
||||||
:type config: dict[str, Any]
|
:type config: dict[str, Any]
|
||||||
:rtype: None
|
:rtype: None
|
||||||
"""
|
"""
|
||||||
|
print("Starting client")
|
||||||
|
|
||||||
self.loop = asyncio.get_running_loop()
|
self.loop = asyncio.get_running_loop()
|
||||||
|
|
||||||
|
@ -495,7 +496,9 @@ class Client:
|
||||||
|
|
||||||
|
|
||||||
def create_async_and_start_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:
|
) -> None:
|
||||||
"""
|
"""
|
||||||
Create an asyncio event loop and start the client.
|
Create an asyncio event loop and start the client.
|
||||||
|
@ -512,7 +515,8 @@ def create_async_and_start_client(
|
||||||
if queue is not None:
|
if queue is not None:
|
||||||
logger.addHandler(QueueHandler(queue))
|
logger.addHandler(QueueHandler(queue))
|
||||||
|
|
||||||
client = Client(config)
|
if client is None:
|
||||||
|
client = Client(config)
|
||||||
|
|
||||||
asyncio.run(client.start_client(config))
|
asyncio.run(client.start_client(config))
|
||||||
|
|
||||||
|
|
45
syng/gui.py
45
syng/gui.py
|
@ -1,15 +1,18 @@
|
||||||
|
import asyncio
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
import sys
|
import sys
|
||||||
import logging
|
import logging
|
||||||
from logging.handlers import QueueListener
|
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 collections.abc import Callable
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import os
|
import os
|
||||||
from functools import partial
|
from functools import partial
|
||||||
import random
|
import random
|
||||||
from typing import TYPE_CHECKING, Any, Optional
|
from typing import TYPE_CHECKING, Any, Optional
|
||||||
import multiprocessing
|
import threading
|
||||||
import secrets
|
import secrets
|
||||||
import string
|
import string
|
||||||
import signal
|
import signal
|
||||||
|
@ -24,11 +27,11 @@ try:
|
||||||
except ImportError:
|
except ImportError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
from qasync import QEventLoop, QApplication
|
||||||
from PyQt6.QtCore import QTimer, Qt
|
from PyQt6.QtCore import QTimer, Qt
|
||||||
from PyQt6.QtGui import QCloseEvent, QIcon, QPixmap
|
from PyQt6.QtGui import QCloseEvent, QIcon, QPixmap
|
||||||
from PyQt6.QtWidgets import (
|
from PyQt6.QtWidgets import (
|
||||||
QApplication,
|
# QApplication,
|
||||||
QCheckBox,
|
QCheckBox,
|
||||||
QComboBox,
|
QComboBox,
|
||||||
QDateTimeEdit,
|
QDateTimeEdit,
|
||||||
|
@ -54,7 +57,7 @@ from qrcode.main import QRCode
|
||||||
import platformdirs
|
import platformdirs
|
||||||
|
|
||||||
from . import resources # noqa
|
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 .sources import available_sources
|
||||||
from .config import (
|
from .config import (
|
||||||
|
@ -626,8 +629,9 @@ class SyngGui(QMainWindow):
|
||||||
if os.name != "nt":
|
if os.name != "nt":
|
||||||
self.setWindowIcon(QIcon(":/icons/syng.ico"))
|
self.setWindowIcon(QIcon(":/icons/syng.ico"))
|
||||||
|
|
||||||
self.syng_server: Optional[Process] = None
|
self.loop = asyncio.get_event_loop()
|
||||||
self.syng_client: Optional[Process] = None
|
self.syng_server: Optional[threading.Thread] = None
|
||||||
|
self.syng_client: Optional[threading.Thread] = None
|
||||||
self.syng_client_logging_listener: Optional[QueueListener] = None
|
self.syng_client_logging_listener: Optional[QueueListener] = None
|
||||||
|
|
||||||
self.configfile = os.path.join(platformdirs.user_config_dir("syng"), "config.yaml")
|
self.configfile = os.path.join(platformdirs.user_config_dir("syng"), "config.yaml")
|
||||||
|
@ -752,9 +756,11 @@ class SyngGui(QMainWindow):
|
||||||
return
|
return
|
||||||
|
|
||||||
if not self.syng_client.is_alive():
|
if not self.syng_client.is_alive():
|
||||||
|
print("Client is not running")
|
||||||
self.syng_client = None
|
self.syng_client = None
|
||||||
self.set_client_button_start()
|
self.set_client_button_start()
|
||||||
else:
|
else:
|
||||||
|
print("Client is running")
|
||||||
self.set_client_button_stop()
|
self.set_client_button_stop()
|
||||||
|
|
||||||
def set_client_button_stop(self) -> None:
|
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():
|
if self.syng_client is None or not self.syng_client.is_alive():
|
||||||
self.save_config()
|
self.save_config()
|
||||||
config = self.gather_config()
|
config = self.gather_config()
|
||||||
queue: Queue[logging.LogRecord] = multiprocessing.Queue()
|
queue: Queue[logging.LogRecord] = Queue()
|
||||||
|
|
||||||
self.syng_client_logging_listener = QueueListener(
|
self.syng_client_logging_listener = QueueListener(
|
||||||
queue, LoggingLabelHandler(self.notification_label)
|
queue, LoggingLabelHandler(self.notification_label)
|
||||||
)
|
)
|
||||||
self.syng_client_logging_listener.start()
|
self.syng_client_logging_listener.start()
|
||||||
|
|
||||||
self.syng_client = multiprocessing.Process(
|
# self.syng_client = multiprocessing.Process(
|
||||||
target=create_async_and_start_client, args=[config, queue]
|
# target=create_async_and_start_client, args=[config, queue]
|
||||||
)
|
# )
|
||||||
self.syng_client.start()
|
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.notification_label.setText("")
|
||||||
self.timer.start(500)
|
self.timer.start(500)
|
||||||
self.set_client_button_stop()
|
self.set_client_button_stop()
|
||||||
else:
|
else:
|
||||||
self.syng_client.terminate()
|
self.client.quit_callback()
|
||||||
self.syng_client.join(1.0)
|
self.syng_client.join(1.0)
|
||||||
self.syng_client.kill()
|
|
||||||
self.set_client_button_start()
|
self.set_client_button_start()
|
||||||
|
|
||||||
# def start_syng_server(self) -> None:
|
# def start_syng_server(self) -> None:
|
||||||
|
@ -853,6 +863,9 @@ def run_gui() -> None:
|
||||||
signal.signal(signal.SIGINT, signal.SIG_DFL)
|
signal.signal(signal.SIGINT, signal.SIG_DFL)
|
||||||
|
|
||||||
app = QApplication([])
|
app = QApplication([])
|
||||||
|
event_loop = QEventLoop(app)
|
||||||
|
asyncio.set_event_loop(event_loop)
|
||||||
|
|
||||||
if os.name == "nt":
|
if os.name == "nt":
|
||||||
app.setWindowIcon(QIcon(os.path.join(base_dir, "syng.ico")))
|
app.setWindowIcon(QIcon(os.path.join(base_dir, "syng.ico")))
|
||||||
else:
|
else:
|
||||||
|
@ -861,7 +874,9 @@ def run_gui() -> None:
|
||||||
app.setDesktopFileName("rocks.syng.Syng")
|
app.setDesktopFileName("rocks.syng.Syng")
|
||||||
window = SyngGui()
|
window = SyngGui()
|
||||||
window.show()
|
window.show()
|
||||||
app.exec()
|
# app.exec()
|
||||||
|
with event_loop:
|
||||||
|
event_loop.run_forever()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
Loading…
Add table
Reference in a new issue