Catch and show game list errors at startup (#177)

* Catch and log errors for failed EA games list parsing
* Extend error logging for Epic Games
* Add error message box for errors loading game list
* Fix lint error in game_sims4.py
This commit is contained in:
Zash
2025-04-12 14:44:20 +02:00
committed by GitHub
parent 59487e7645
commit 9e30d7d104
4 changed files with 65 additions and 16 deletions
+14 -2
View File
@@ -8,6 +8,7 @@ from typing import Callable, Generic, TypeVar
import mobase
from PyQt6.QtCore import QDir, QFileInfo, QStandardPaths
from PyQt6.QtGui import QIcon
from PyQt6.QtWidgets import QMessageBox
from .basic_features.basic_save_game_info import (
BasicGameSaveGame,
@@ -380,11 +381,22 @@ class BasicGame(mobase.IPluginGame):
from .origin_utils import find_games as find_origin_games
from .steam_utils import find_games as find_steam_games
errors: list[tuple[str, Exception]] = []
BasicGame.steam_games = find_steam_games()
BasicGame.gog_games = find_gog_games()
BasicGame.origin_games = find_origin_games()
BasicGame.epic_games = find_epic_games()
BasicGame.eadesktop_games = find_eadesktop_games()
BasicGame.epic_games = find_epic_games(errors)
BasicGame.eadesktop_games = find_eadesktop_games(errors)
if errors:
QMessageBox.critical(
None,
"Errors loading game list",
(
"The following errors occurred while loading the list of available games:\n"
f"\n- {'\n\n- '.join('\n '.join(str(e) for e in messageError) for messageError in errors)}"
),
)
# File containing the plugin:
_fromName: str
+13 -2
View File
@@ -2,13 +2,14 @@
import configparser
import os
import sys
import xml.etree.ElementTree as et
from configparser import NoOptionError
from pathlib import Path
from typing import Dict
def find_games() -> Dict[str, Path]:
def find_games(errors: list[tuple[str, Exception]] | None = None) -> Dict[str, Path]:
"""
Find the list of EA Desktop games installed.
@@ -37,7 +38,17 @@ def find_games() -> Dict[str, Path]:
ini_content = "[mod_organizer]\n" + f.read()
config = configparser.ConfigParser()
config.read_string(ini_content)
try:
config.read_string(ini_content)
except configparser.ParsingError as e:
error_message = (
f'Failed to parse EA Desktop games list file "{user_ini}",\n'
" Try to run the launcher to recreate it."
)
print(error_message, e, file=sys.stderr)
if errors is not None:
errors.append((error_message, e))
return games
try:
install_path = Path(config.get("mod_organizer", "user.downloadinplacedir"))
+36 -12
View File
@@ -9,8 +9,12 @@ import winreg
from collections.abc import Iterable
from pathlib import Path
ErrorList = list[tuple[str, Exception]]
def find_epic_games() -> Iterable[tuple[str, Path]]:
def find_epic_games(
errors: ErrorList | None = None,
) -> Iterable[tuple[str, Path]]:
try:
with winreg.OpenKey(
winreg.HKEY_LOCAL_MACHINE,
@@ -30,15 +34,23 @@ def find_epic_games() -> Iterable[tuple[str, Path]]:
manifest_file_data["AppName"],
Path(manifest_file_data["InstallLocation"]),
)
except (json.JSONDecodeError, KeyError):
except (json.JSONDecodeError, KeyError) as e:
error_message = (
f'Unable to parse Epic Games manifest file: "{manifest_file_path}"\n'
" Try to run the launcher recreate it."
)
print(
"Unable to parse Epic Games manifest file",
manifest_file_path,
error_message,
e,
file=sys.stderr,
)
if errors is not None:
errors.append((error_message, e))
def find_legendary_games(config_path: str | None = None) -> Iterable[tuple[str, Path]]:
def find_legendary_games(
config_path: str | None = None, errors: ErrorList | None = None
) -> Iterable[tuple[str, Path]]:
# Based on legendary source:
# https://github.com/derrod/legendary/blob/master/legendary/lfs/lgndry.py
if config_path := config_path or os.environ.get("XDG_CONFIG_HOME"):
@@ -53,21 +65,33 @@ def find_legendary_games(config_path: str | None = None) -> Iterable[tuple[str,
installed_games = json.load(installed_file)
for game in installed_games.values():
yield game["app_name"], Path(game["install_path"])
except (json.JSONDecodeError, AttributeError, KeyError):
except (json.JSONDecodeError, AttributeError, KeyError) as e:
error_message = (
f'Unable to parse installed games from Legendary/Heroic launcher: "{installed_path}"\n'
" Try to run the launcher to recrated the file."
)
print(
"Unable to parse installed games from Legendary",
installed_path,
error_message,
e,
file=sys.stderr,
)
if errors is not None:
errors.append((error_message, e))
def find_heroic_games():
return find_legendary_games(os.path.expandvars(r"%AppData%\heroic\legendaryConfig"))
def find_heroic_games(errors: ErrorList | None = None):
return find_legendary_games(
os.path.expandvars(r"%AppData%\heroic\legendaryConfig"), errors
)
def find_games() -> dict[str, Path]:
def find_games(errors: ErrorList | None = None) -> dict[str, Path]:
return dict(
itertools.chain(find_epic_games(), find_legendary_games(), find_heroic_games())
itertools.chain(
find_epic_games(errors=errors),
find_legendary_games(errors=errors),
find_heroic_games(errors=errors),
)
)
+2
View File
@@ -111,6 +111,8 @@ class TS4ModDataChecker(ModDataChecker):
ValidationResult.FIXABLE,
lambda: tree.move(entry, innerPath),
)
case _:
pass
return walkReturn
tree.walk(fixOrValidateEntry)