From 0ce76eed22da8124a8c1db5962afe87316a44a03 Mon Sep 17 00:00:00 2001 From: Daniel Johnson Date: Wed, 27 Dec 2023 18:41:08 -0500 Subject: [PATCH] And the big one - replace the FILE_NOT_FOUND error code with an exception, MissingGameExecutableError, that provides the custom message. --- lutris/exceptions.py | 15 +++++++++++++++ lutris/game.py | 10 +--------- lutris/runners/atari800.py | 4 ++-- lutris/runners/dolphin.py | 3 ++- lutris/runners/dosbox.py | 3 ++- lutris/runners/easyrpg.py | 4 ++-- lutris/runners/hatari.py | 4 ++-- lutris/runners/json.py | 3 ++- lutris/runners/jzintv.py | 4 ++-- lutris/runners/libretro.py | 4 ++-- lutris/runners/linux.py | 4 ++-- lutris/runners/mednafen.py | 3 ++- lutris/runners/mupen64plus.py | 3 ++- lutris/runners/o2em.py | 3 ++- lutris/runners/openmsx.py | 3 ++- lutris/runners/osmose.py | 3 ++- lutris/runners/pcsx2.py | 3 ++- lutris/runners/pico8.py | 3 ++- lutris/runners/rpcs3.py | 3 ++- lutris/runners/ryujinx.py | 3 ++- lutris/runners/snes9x.py | 3 ++- lutris/runners/steam.py | 4 ++-- lutris/runners/vice.py | 13 +++++-------- lutris/runners/wine.py | 5 +++-- lutris/runners/xemu.py | 3 ++- lutris/runners/yuzu.py | 5 +++-- tests/runners/test_pcsx2.py | 6 ++++-- 27 files changed, 73 insertions(+), 51 deletions(-) diff --git a/lutris/exceptions.py b/lutris/exceptions.py index 56e064b78..d2ad3c549 100644 --- a/lutris/exceptions.py +++ b/lutris/exceptions.py @@ -23,6 +23,7 @@ class DirectoryNotFoundError(MisconfigurationError): if not message and directory: message = _("The directory {} could not be found").format(directory) super().__init__(message, *args, **kwarg) + self.directory = directory class GameConfigError(MisconfigurationError): @@ -69,6 +70,20 @@ class MissingExecutableError(MisconfigurationError): """Raised when a program can't be located.""" +class MissingGameExecutableError(MissingExecutableError): + """Raise when a game's executable can't be found is not specified.""" + + def __init__(self, *args, message=None, filename=None, **kwargs): + if not message: + if filename: + message = _("The file {} could not be found").format(filename) + else: + message = _("This game has no executable set. The install process didn't finish properly.") + + super().__init__(message, *args, **kwargs) + self.filename = filename + + class EsyncLimitError(Exception): """Raised when the ESYNC limit is not set correctly.""" diff --git a/lutris/game.py b/lutris/game.py index a53b793d2..9876aeb87 100644 --- a/lutris/game.py +++ b/lutris/game.py @@ -272,15 +272,7 @@ class Game(GObject.Object): @staticmethod def get_config_error(gameplay_info): """Return a GameConfigError based on the runner's output.""" - error = gameplay_info["error"] - if error == "FILE_NOT_FOUND": - filename = gameplay_info["file"] - if filename: - message_text = _("The file {} could not be found").format(filename) - else: - message_text = _("This game has no executable set. The install process didn't finish properly.") - else: - message_text = _("Unhandled error: %s") % gameplay_info["error"] + message_text = _("Unhandled error: %s") % gameplay_info["error"] return GameConfigError(message_text) def get_browse_dir(self): diff --git a/lutris/runners/atari800.py b/lutris/runners/atari800.py index e27e58e37..c3b628a79 100644 --- a/lutris/runners/atari800.py +++ b/lutris/runners/atari800.py @@ -3,7 +3,7 @@ import os.path from gettext import gettext as _ from lutris.config import LutrisConfig -from lutris.exceptions import MissingBiosError +from lutris.exceptions import MissingBiosError, MissingGameExecutableError from lutris.runners.runner import Runner from lutris.util import display, extract, system @@ -141,7 +141,7 @@ class atari800(Runner): rom = self.game_config.get("main_file") or "" if not system.path_exists(rom): - return {"error": "FILE_NOT_FOUND", "file": rom} + raise MissingGameExecutableError(filename=rom) arguments.append(rom) return {"command": arguments} diff --git a/lutris/runners/dolphin.py b/lutris/runners/dolphin.py index 273b98c1d..d19fb6f4c 100644 --- a/lutris/runners/dolphin.py +++ b/lutris/runners/dolphin.py @@ -1,6 +1,7 @@ """Dolphin runner""" from gettext import gettext as _ +from lutris.exceptions import MissingGameExecutableError # Lutris Modules from lutris.runners.runner import Runner from lutris.util import system @@ -69,7 +70,7 @@ class dolphin(Runner): # Retrieve the path to the file iso = self.game_config.get("main_file") or "" if not system.path_exists(iso): - return {"error": "FILE_NOT_FOUND", "file": iso} + raise MissingGameExecutableError(filename=iso) command.extend(["-e", iso]) return {"command": command} diff --git a/lutris/runners/dosbox.py b/lutris/runners/dosbox.py index cb236be99..b77f30a7f 100644 --- a/lutris/runners/dosbox.py +++ b/lutris/runners/dosbox.py @@ -4,6 +4,7 @@ import shlex from gettext import gettext as _ from lutris import settings +from lutris.exceptions import MissingGameExecutableError # Lutris Modules from lutris.runners.commands.dosbox import dosexec, makeconfig # NOQA pylint: disable=unused-import from lutris.runners.runner import Runner @@ -150,7 +151,7 @@ class dosbox(Runner): def play(self): main_file = self.main_file if not system.path_exists(main_file): - return {"error": "FILE_NOT_FOUND", "file": main_file} + raise MissingGameExecutableError(filename=main_file) args = shlex.split(self.game_config.get("args") or "") command = self.get_command() diff --git a/lutris/runners/easyrpg.py b/lutris/runners/easyrpg.py index bad121677..1e2ae1372 100644 --- a/lutris/runners/easyrpg.py +++ b/lutris/runners/easyrpg.py @@ -2,7 +2,7 @@ from gettext import gettext as _ from os import path -from lutris.exceptions import DirectoryNotFoundError, GameConfigError +from lutris.exceptions import DirectoryNotFoundError, GameConfigError, MissingGameExecutableError # Lutris Modules from lutris.runners.runner import Runner @@ -571,7 +571,7 @@ class easyrpg(Runner): if replay_input: replay_input = path.expanduser(replay_input) if not path.isfile(replay_input): - return {"error": "FILE_NOT_FOUND", "file": replay_input} + raise MissingGameExecutableError(filename=replay_input) cmd.extend(("--replay-input", replay_input)) load_game_id = self.game_config.get("load_game_id") diff --git a/lutris/runners/hatari.py b/lutris/runners/hatari.py index be0d42f34..5cd69bb9c 100644 --- a/lutris/runners/hatari.py +++ b/lutris/runners/hatari.py @@ -5,7 +5,7 @@ from gettext import gettext as _ # Lutris Modules from lutris.config import LutrisConfig -from lutris.exceptions import MissingBiosError +from lutris.exceptions import MissingBiosError, MissingGameExecutableError from lutris.runners.runner import Runner from lutris.util import system @@ -179,7 +179,7 @@ class hatari(Runner): raise MissingBiosError() diska = self.game_config.get("disk-a") if not system.path_exists(diska): - return {"error": "FILE_NOT_FOUND", "file": diska} + raise MissingGameExecutableError(filename=diska) params.append("--disk-a") params.append(diska) diff --git a/lutris/runners/json.py b/lutris/runners/json.py index d63c513ec..0966c5c24 100644 --- a/lutris/runners/json.py +++ b/lutris/runners/json.py @@ -3,6 +3,7 @@ import json import os from lutris import settings +from lutris.exceptions import MissingGameExecutableError from lutris.runners.runner import Runner from lutris.util import datapath, system @@ -54,7 +55,7 @@ class JsonRunner(Runner): raise RuntimeError("Unhandled type %s" % option["type"]) main_file = self.game_config.get(self.entry_point_option) if not system.path_exists(main_file): - return {"error": "FILE_NOT_FOUND", "file": main_file} + raise MissingGameExecutableError(filename=main_file) arguments.append(main_file) return {"command": arguments} diff --git a/lutris/runners/jzintv.py b/lutris/runners/jzintv.py index 9de84a6e4..2b50d7cf6 100644 --- a/lutris/runners/jzintv.py +++ b/lutris/runners/jzintv.py @@ -2,7 +2,7 @@ import os from gettext import gettext as _ -from lutris.exceptions import MissingBiosError +from lutris.exceptions import MissingBiosError, MissingGameExecutableError # Lutris Modules from lutris.runners.runner import Runner from lutris.util import system @@ -81,7 +81,7 @@ class jzintv(Runner): raise MissingBiosError() rom_path = self.game_config.get("main_file") or "" if not system.path_exists(rom_path): - return {"error": "FILE_NOT_FOUND", "file": rom_path} + raise MissingGameExecutableError(filename=rom_path) romdir = os.path.dirname(rom_path) romfile = os.path.basename(rom_path) arguments += ["--rom-path=%s/" % romdir] diff --git a/lutris/runners/libretro.py b/lutris/runners/libretro.py index 71d11803b..286bf2661 100644 --- a/lutris/runners/libretro.py +++ b/lutris/runners/libretro.py @@ -7,7 +7,7 @@ from zipfile import ZipFile import requests from lutris import settings -from lutris.exceptions import GameConfigError, UnspecifiedVersionError +from lutris.exceptions import GameConfigError, MissingGameExecutableError, UnspecifiedVersionError from lutris.runners.runner import Runner from lutris.util import system from lutris.util.libretro import RetroConfig @@ -289,6 +289,6 @@ class libretro(Runner): if not file: raise GameConfigError(_("No game file specified")) if not system.path_exists(file): - return {"error": "FILE_NOT_FOUND", "file": file} + raise MissingGameExecutableError(filename=file) command.append(file) return {"command": command} diff --git a/lutris/runners/linux.py b/lutris/runners/linux.py index b7d474175..0027be880 100644 --- a/lutris/runners/linux.py +++ b/lutris/runners/linux.py @@ -6,7 +6,7 @@ from gettext import gettext as _ from typing import Callable # Lutris Modules -from lutris.exceptions import GameConfigError, MissingExecutableError +from lutris.exceptions import GameConfigError, MissingExecutableError, MissingGameExecutableError from lutris.runners.runner import Runner from lutris.util import system from lutris.util.strings import split_arguments @@ -158,7 +158,7 @@ class linux(Runner): exe = self.game_exe if not exe or not system.path_exists(exe): - return {"error": "FILE_NOT_FOUND", "file": exe} + raise MissingGameExecutableError(filename=exe) # Quit if the file is not executable mode = os.stat(exe).st_mode diff --git a/lutris/runners/mednafen.py b/lutris/runners/mednafen.py index 83462bbb9..6205ac57f 100644 --- a/lutris/runners/mednafen.py +++ b/lutris/runners/mednafen.py @@ -2,6 +2,7 @@ import subprocess from gettext import gettext as _ +from lutris.exceptions import MissingGameExecutableError # Lutris Modules from lutris.runners.runner import Runner from lutris.util import system @@ -521,7 +522,7 @@ class mednafen(Runner): options.append(control) if not system.path_exists(rom): - return {"error": "FILE_NOT_FOUND", "file": rom} + raise MissingGameExecutableError(filename=rom) command = self.get_command() for option in options: diff --git a/lutris/runners/mupen64plus.py b/lutris/runners/mupen64plus.py index cc0b5a958..f9ad5758d 100644 --- a/lutris/runners/mupen64plus.py +++ b/lutris/runners/mupen64plus.py @@ -4,6 +4,7 @@ from gettext import gettext as _ # Lutris Modules from lutris import settings +from lutris.exceptions import MissingGameExecutableError from lutris.runners.runner import Runner from lutris.util import system @@ -52,6 +53,6 @@ class mupen64plus(Runner): arguments.append("--windowed") rom = self.game_config.get("main_file") or "" if not system.path_exists(rom): - return {"error": "FILE_NOT_FOUND", "file": rom} + raise MissingGameExecutableError(filename=rom) arguments.append(rom) return {"command": arguments} diff --git a/lutris/runners/o2em.py b/lutris/runners/o2em.py index 284063014..f3f488627 100644 --- a/lutris/runners/o2em.py +++ b/lutris/runners/o2em.py @@ -2,6 +2,7 @@ import os from gettext import gettext as _ +from lutris.exceptions import MissingGameExecutableError # Lutris Modules from lutris.runners.runner import Runner from lutris.util import system @@ -122,7 +123,7 @@ class o2em(Runner): arguments.append("-s2=%s" % self.runner_config["controller2"]) rom_path = self.game_config.get("main_file") or "" if not system.path_exists(rom_path): - return {"error": "FILE_NOT_FOUND", "file": rom_path} + raise MissingGameExecutableError(filename=rom_path) romdir = os.path.dirname(rom_path) romfile = os.path.basename(rom_path) arguments.append("-romdir=%s/" % romdir) diff --git a/lutris/runners/openmsx.py b/lutris/runners/openmsx.py index e9307d665..2c2c0e6d8 100644 --- a/lutris/runners/openmsx.py +++ b/lutris/runners/openmsx.py @@ -1,6 +1,7 @@ # Standard Library from gettext import gettext as _ +from lutris.exceptions import MissingGameExecutableError # Lutris Modules from lutris.runners.runner import Runner from lutris.util import system @@ -23,5 +24,5 @@ class openmsx(Runner): def play(self): rom = self.game_config.get("main_file") or "" if not system.path_exists(rom): - return {"error": "FILE_NOT_FOUND", "file": rom} + raise MissingGameExecutableError(filename=rom) return {"command": self.get_command() + [rom]} diff --git a/lutris/runners/osmose.py b/lutris/runners/osmose.py index b7589d75a..178b6538b 100644 --- a/lutris/runners/osmose.py +++ b/lutris/runners/osmose.py @@ -1,6 +1,7 @@ # Standard Library from gettext import gettext as _ +from lutris.exceptions import MissingGameExecutableError # Lutris Modules from lutris.runners.runner import Runner from lutris.util import system @@ -40,7 +41,7 @@ class osmose(Runner): arguments = self.get_command() rom = self.game_config.get("main_file") or "" if not system.path_exists(rom): - return {"error": "FILE_NOT_FOUND", "file": rom} + raise MissingGameExecutableError(filename=rom) arguments.append(rom) if self.runner_config.get("fullscreen"): arguments.append("-fs") diff --git a/lutris/runners/pcsx2.py b/lutris/runners/pcsx2.py index db653d012..4073418d5 100644 --- a/lutris/runners/pcsx2.py +++ b/lutris/runners/pcsx2.py @@ -1,6 +1,7 @@ # Standard Library from gettext import gettext as _ +from lutris.exceptions import MissingGameExecutableError # Lutris Modules from lutris.runners.runner import Runner from lutris.util import system @@ -56,6 +57,6 @@ class pcsx2(Runner): iso = self.game_config.get("main_file") or "" if not system.path_exists(iso): - return {"error": "FILE_NOT_FOUND", "file": iso} + raise MissingGameExecutableError(filename=iso) arguments.append(iso) return {"command": arguments} diff --git a/lutris/runners/pico8.py b/lutris/runners/pico8.py index fe080b024..f5c989492 100644 --- a/lutris/runners/pico8.py +++ b/lutris/runners/pico8.py @@ -8,6 +8,7 @@ from time import sleep from lutris import settings from lutris.database.games import get_game_by_field +from lutris.exceptions import MissingGameExecutableError from lutris.runners.runner import Runner from lutris.util import system from lutris.util.downloader import Downloader @@ -210,7 +211,7 @@ class pico8(Runner): command.append("-run") cartPath = self.cart_path if not os.path.exists(cartPath): - return {"error": "FILE_NOT_FOUND", "file": cartPath} + raise MissingGameExecutableError(filename=cartPath) command.append(cartPath) else: diff --git a/lutris/runners/rpcs3.py b/lutris/runners/rpcs3.py index 3c04a62dd..7ac99f1bd 100644 --- a/lutris/runners/rpcs3.py +++ b/lutris/runners/rpcs3.py @@ -1,6 +1,7 @@ # Standard Library from gettext import gettext as _ +from lutris.exceptions import MissingGameExecutableError # Lutris Modules from lutris.runners.runner import Runner from lutris.util import system @@ -34,6 +35,6 @@ class rpcs3(Runner): eboot = self.game_config.get("main_file") or "" if not system.path_exists(eboot): - return {"error": "FILE_NOT_FOUND", "file": eboot} + raise MissingGameExecutableError(filename=eboot) arguments.append(eboot) return {"command": arguments} diff --git a/lutris/runners/ryujinx.py b/lutris/runners/ryujinx.py index ee4d74c36..be285162b 100644 --- a/lutris/runners/ryujinx.py +++ b/lutris/runners/ryujinx.py @@ -3,6 +3,7 @@ import os from gettext import gettext as _ from shutil import copyfile +from lutris.exceptions import MissingGameExecutableError from lutris.runners.runner import Runner from lutris.util import system from lutris.util.log import logger @@ -53,7 +54,7 @@ class ryujinx(Runner): arguments = self.get_command() rom = self.game_config.get("main_file") or "" if not system.path_exists(rom): - return {"error": "FILE_NOT_FOUND", "file": rom} + raise MissingGameExecutableError(filename=rom) arguments.append(rom) return {"command": arguments} diff --git a/lutris/runners/snes9x.py b/lutris/runners/snes9x.py index 56a8db73d..e62b3c7a2 100644 --- a/lutris/runners/snes9x.py +++ b/lutris/runners/snes9x.py @@ -6,6 +6,7 @@ from gettext import gettext as _ # Lutris Modules from lutris import settings +from lutris.exceptions import MissingGameExecutableError from lutris.runners.runner import Runner from lutris.util import system from lutris.util.log import logger @@ -83,5 +84,5 @@ class snes9x(Runner): rom = self.game_config.get("main_file") or "" if not system.path_exists(rom): - return {"error": "FILE_NOT_FOUND", "file": rom} + raise MissingGameExecutableError(filename=rom) return {"command": self.get_command() + [rom]} diff --git a/lutris/runners/steam.py b/lutris/runners/steam.py index 73fbb0a80..bf8f1b28c 100644 --- a/lutris/runners/steam.py +++ b/lutris/runners/steam.py @@ -3,7 +3,7 @@ import os from gettext import gettext as _ from lutris.command import MonitoredCommand -from lutris.exceptions import UnavailableRunnerError +from lutris.exceptions import MissingGameExecutableError, UnavailableRunnerError from lutris.runners import NonInstallableRunnerError from lutris.runners.runner import Runner from lutris.util import linux, system @@ -217,7 +217,7 @@ class steam(Runner): if self.game_config.get("run_without_steam") and binary_path: # Start without steam if not system.path_exists(binary_path): - return {"error": "FILE_NOT_FOUND", "file": binary_path} + raise MissingGameExecutableError(filename=binary_path) command = [binary_path] else: # Start through steam diff --git a/lutris/runners/vice.py b/lutris/runners/vice.py index aabc0733f..4cd030fd3 100644 --- a/lutris/runners/vice.py +++ b/lutris/runners/vice.py @@ -4,7 +4,7 @@ from gettext import gettext as _ # Lutris Modules from lutris import settings -from lutris.exceptions import GameConfigError, MisconfigurationError, MissingExecutableError +from lutris.exceptions import GameConfigError, MisconfigurationError, MissingExecutableError, MissingGameExecutableError from lutris.runners.runner import Runner from lutris.util import system from lutris.util.log import logger @@ -32,12 +32,9 @@ class vice(Runner): ] game_options = [ { - "option": - "main_file", - "type": - "file", - "label": - _("ROM file"), + "option": "main_file", + "type": "file", + "label": _("ROM file"), "help": _( "The game data, commonly called a ROM image.\n" "Supported formats: X64, D64, G64, P64, D67, D71, D81, " @@ -198,7 +195,7 @@ class vice(Runner): if not rom: raise GameConfigError(_("No rom provided")) if not system.path_exists(rom): - return {"error": "FILE_NOT_FOUND", "file": rom} + raise MissingGameExecutableError(filename=rom) params = [self.get_executable(machine)] rom_dir = os.path.dirname(rom) diff --git a/lutris/runners/wine.py b/lutris/runners/wine.py index dcf07a3d6..d1360c99b 100644 --- a/lutris/runners/wine.py +++ b/lutris/runners/wine.py @@ -10,7 +10,8 @@ from lutris.api import format_runner_version, get_default_runner_version_info from lutris.config import LutrisConfig from lutris.database.games import get_game_by_field from lutris.exceptions import ( - EsyncLimitError, FsyncUnsupportedError, MisconfigurationError, MissingExecutableError, UnspecifiedVersionError + EsyncLimitError, FsyncUnsupportedError, MisconfigurationError, MissingExecutableError, MissingGameExecutableError, + UnspecifiedVersionError ) from lutris.game import Game from lutris.gui.dialogs import FileDialog @@ -1143,7 +1144,7 @@ class wine(Runner): launch_info["env"]["WINE_LARGE_ADDRESS_AWARE"] = "1" if not game_exe or not system.path_exists(game_exe): - return {"error": "FILE_NOT_FOUND", "file": game_exe} + raise MissingGameExecutableError(filename=game_exe) if launch_info["env"].get("WINEESYNC") == "1": limit_set = is_esync_limit_set() diff --git a/lutris/runners/xemu.py b/lutris/runners/xemu.py index 41b437fae..c2dc11586 100644 --- a/lutris/runners/xemu.py +++ b/lutris/runners/xemu.py @@ -1,5 +1,6 @@ from gettext import gettext as _ +from lutris.exceptions import MissingGameExecutableError from lutris.runners.runner import Runner from lutris.util import system @@ -41,6 +42,6 @@ class xemu(Runner): iso = self.game_config.get("main_file") or "" if not system.path_exists(iso): - return {"error": "FILE_NOT_FOUND", "file": iso} + raise MissingGameExecutableError(filename=iso) arguments += ["-dvd_path", iso] return {"command": arguments} diff --git a/lutris/runners/yuzu.py b/lutris/runners/yuzu.py index 43564d4ce..8af28edb5 100644 --- a/lutris/runners/yuzu.py +++ b/lutris/runners/yuzu.py @@ -3,6 +3,7 @@ import os from gettext import gettext as _ from shutil import copyfile +from lutris.exceptions import MissingGameExecutableError from lutris.runners.runner import Runner from lutris.util import system from lutris.util.log import logger @@ -48,7 +49,7 @@ class yuzu(Runner): @property def yuzu_data_dir(self): """Return dir where Yuzu files lie.""" - candidates = ("~/.local/share/yuzu", ) + candidates = ("~/.local/share/yuzu",) for candidate in candidates: path = system.fix_path_case(os.path.join(os.path.expanduser(candidate), "nand")) if system.path_exists(path): @@ -64,7 +65,7 @@ class yuzu(Runner): rom = self.game_config.get("main_file") or "" if not system.path_exists(rom): - return {"error": "FILE_NOT_FOUND", "file": rom} + raise MissingGameExecutableError(filename=rom) arguments += ["-g", rom] return {"command": arguments} diff --git a/tests/runners/test_pcsx2.py b/tests/runners/test_pcsx2.py index f28424fc5..2787e9f0c 100644 --- a/tests/runners/test_pcsx2.py +++ b/tests/runners/test_pcsx2.py @@ -1,6 +1,7 @@ import unittest from unittest.mock import MagicMock, patch +from lutris.exceptions import MissingGameExecutableError from lutris.runners.pcsx2 import pcsx2 @@ -19,8 +20,9 @@ class TestPCSX2Runner(unittest.TestCase): mock_config.game_config = {'main_file': main_file} mock_config.runner_config = MagicMock() self.runner.config = mock_config - expected = {'error': 'FILE_NOT_FOUND', 'file': main_file} - self.assertEqual(self.runner.play(), expected) + with self.assertRaises(MissingGameExecutableError) as cm: + self.runner.play() + self.assertEqual(cm.exception.filename, main_file) @patch('lutris.util.system.path_exists') @patch('os.path.isfile')