From 07ef43b13e014f5f2908238201449bc7aeecf918 Mon Sep 17 00:00:00 2001 From: loathingKernel <142770+loathingKernel@users.noreply.github.com> Date: Tue, 31 Jan 2023 13:59:22 +0200 Subject: [PATCH] Workers: Use a wrapper class that deletes the signals QObject before exiting --- rare/shared/workers/install_info.py | 11 ++++------ rare/shared/workers/move.py | 7 ++++-- rare/shared/workers/uninstall.py | 10 ++++----- rare/shared/workers/verify.py | 7 +++--- rare/shared/workers/wine_resolver.py | 9 ++++---- rare/shared/workers/worker.py | 32 ++++++++++++++++++++++++++++ 6 files changed, 52 insertions(+), 24 deletions(-) create mode 100644 rare/shared/workers/worker.py diff --git a/rare/shared/workers/install_info.py b/rare/shared/workers/install_info.py index b0c90136..1b5a921e 100644 --- a/rare/shared/workers/install_info.py +++ b/rare/shared/workers/install_info.py @@ -1,8 +1,7 @@ import os -import sys from logging import getLogger -from PyQt5.QtCore import QObject, QRunnable, pyqtSignal, pyqtSlot +from PyQt5.QtCore import QObject, pyqtSignal from legendary.lfs.eos import EOSOverlayApp from legendary.models.downloading import ConditionCheckResult @@ -12,26 +11,24 @@ from rare.lgndr.glue.arguments import LgndrInstallGameArgs from rare.lgndr.glue.exception import LgndrException from rare.lgndr.glue.monkeys import LgndrIndirectStatus from rare.models.install import InstallDownloadModel, InstallOptionsModel +from .worker import Worker logger = getLogger("InstallInfoWorker") -class InstallInfoWorker(QRunnable): +class InstallInfoWorker(Worker): class Signals(QObject): result = pyqtSignal(InstallDownloadModel) failed = pyqtSignal(str) finished = pyqtSignal() def __init__(self, core: LegendaryCore, options: InstallOptionsModel): - sys.excepthook = sys.__excepthook__ super(InstallInfoWorker, self).__init__() - self.setAutoDelete(True) self.signals = InstallInfoWorker.Signals() self.core = core self.options = options - @pyqtSlot() - def run(self): + def run_real(self): try: if not self.options.overlay: cli = LegendaryCLI(self.core) diff --git a/rare/shared/workers/move.py b/rare/shared/workers/move.py index a33677af..5027ae5c 100644 --- a/rare/shared/workers/move.py +++ b/rare/shared/workers/move.py @@ -6,9 +6,12 @@ from PyQt5.QtCore import pyqtSignal, QRunnable, QObject from legendary.lfs.utils import validate_files from legendary.models.game import VerifyResult, InstalledGame +from rare.lgndr.core import LegendaryCore +from .worker import Worker + # noinspection PyUnresolvedReferences -class MoveWorker(QRunnable): +class MoveWorker(Worker): class Signals(QObject): progress = pyqtSignal(int) finished = pyqtSignal(str) @@ -34,7 +37,7 @@ class MoveWorker(QRunnable): self.file_list = None self.total: int = 0 - def run(self): + def run_real(self): root_directory = Path(self.install_path) self.source_size = sum(f.stat().st_size for f in root_directory.glob("**/*") if f.is_file()) diff --git a/rare/shared/workers/uninstall.py b/rare/shared/workers/uninstall.py index 57d980b7..2bc9d795 100644 --- a/rare/shared/workers/uninstall.py +++ b/rare/shared/workers/uninstall.py @@ -1,9 +1,8 @@ import os import platform -import sys from logging import getLogger -from PyQt5.QtCore import QStandardPaths, QRunnable, QObject, pyqtSignal +from PyQt5.QtCore import QStandardPaths, QObject, pyqtSignal from legendary.core import LegendaryCore from rare.lgndr.cli import LegendaryCLI @@ -12,6 +11,7 @@ from rare.lgndr.glue.monkeys import LgndrIndirectStatus from rare.models.game import RareGame from rare.models.install import UninstallOptionsModel from rare.utils import config_helper +from .worker import Worker logger = getLogger("UninstallWorker") @@ -60,20 +60,18 @@ def uninstall_game(core: LegendaryCore, app_name: str, keep_files=False, keep_co return status.success, status.message -class UninstallWorker(QRunnable): +class UninstallWorker(Worker): class Signals(QObject): result = pyqtSignal(RareGame, bool, str) def __init__(self, core: LegendaryCore, rgame: RareGame, options: UninstallOptionsModel): - sys.excepthook = sys.__excepthook__ super(UninstallWorker, self).__init__() self.signals = UninstallWorker.Signals() - self.setAutoDelete(True) self.core = core self.rgame = rgame self.options = options - def run(self) -> None: + def run_real(self) -> None: self.rgame.state = RareGame.State.UNINSTALLING success, message = uninstall_game( self.core, self.rgame.app_name, self.options.keep_files, self.options.keep_config diff --git a/rare/shared/workers/verify.py b/rare/shared/workers/verify.py index 39583abe..638e32bc 100644 --- a/rare/shared/workers/verify.py +++ b/rare/shared/workers/verify.py @@ -10,11 +10,12 @@ from rare.lgndr.core import LegendaryCore from rare.lgndr.glue.arguments import LgndrVerifyGameArgs from rare.lgndr.glue.monkeys import LgndrIndirectStatus from rare.models.game import RareGame +from .worker import Worker logger = getLogger("VerifyWorker") -class VerifyWorker(QRunnable): +class VerifyWorker(Worker): class Signals(QObject): progress = pyqtSignal(RareGame, int, int, float, float) result = pyqtSignal(RareGame, bool, int, int) @@ -24,10 +25,8 @@ class VerifyWorker(QRunnable): total: int = 1 # set default to 1 to avoid DivisionByZero before it is initialized def __init__(self, core: LegendaryCore, args: Namespace, rgame: RareGame): - sys.excepthook = sys.__excepthook__ super(VerifyWorker, self).__init__() self.signals = VerifyWorker.Signals() - self.setAutoDelete(True) self.core = core self.args = args self.rgame = rgame @@ -36,7 +35,7 @@ class VerifyWorker(QRunnable): self.rgame.signals.progress.update.emit(num * 100 // total) self.signals.progress.emit(self.rgame, num, total, percentage, speed) - def run(self): + def run_real(self): self.rgame.signals.progress.start.emit() cli = LegendaryCLI(self.core) status = LgndrIndirectStatus() diff --git a/rare/shared/workers/wine_resolver.py b/rare/shared/workers/wine_resolver.py index f50f66d2..695edaf4 100644 --- a/rare/shared/workers/wine_resolver.py +++ b/rare/shared/workers/wine_resolver.py @@ -2,22 +2,22 @@ import os import subprocess from logging import getLogger -from PyQt5.QtCore import pyqtSignal, QRunnable, QObject, pyqtSlot +from PyQt5.QtCore import pyqtSignal, QObject from rare.lgndr.core import LegendaryCore from rare.models.pathspec import PathSpec +from .worker import Worker logger = getLogger("WineResolver") -class WineResolver(QRunnable): +class WineResolver(Worker): class Signals(QObject): result_ready = pyqtSignal(str) def __init__(self, core: LegendaryCore, path: str, app_name: str): super(WineResolver, self).__init__() self.signals = WineResolver.Signals() - self.setAutoDelete(True) self.wine_env = os.environ.copy() self.wine_env.update(core.get_app_environment(app_name)) self.wine_env["WINEDLLOVERRIDES"] = "winemenubuilder=d;mscoree=d;mshtml=d;" @@ -31,8 +31,7 @@ class WineResolver(QRunnable): self.winepath_binary = os.path.join(os.path.dirname(self.wine_binary), "winepath") self.path = PathSpec(core, app_name).cook(path) - @pyqtSlot() - def run(self): + def run_real(self): if "WINEPREFIX" not in self.wine_env or not os.path.exists(self.wine_env["WINEPREFIX"]): # pylint: disable=E1136 self.signals.result_ready[str].emit("") diff --git a/rare/shared/workers/worker.py b/rare/shared/workers/worker.py new file mode 100644 index 00000000..f72b50da --- /dev/null +++ b/rare/shared/workers/worker.py @@ -0,0 +1,32 @@ +import sys +from abc import abstractmethod +from typing import Optional + +from PyQt5.QtCore import QRunnable, QObject, pyqtSlot + + +class Worker(QRunnable): + def __init__(self): + sys.excepthook = sys.__excepthook__ + super(Worker, self).__init__() + self.setAutoDelete(True) + self.__signals: Optional[QObject] = None + + @property + def signals(self) -> QObject: + if self.__signals is None: + raise NotImplementedError + return self.__signals + + @signals.setter + def signals(self, obj: QObject): + self.__signals = obj + + @abstractmethod + def run_real(self): + pass + + @pyqtSlot() + def run(self): + self.run_real() + self.signals.deleteLater()