From 87a43193602deb0f9b3e2286ca2e96d6ec442c70 Mon Sep 17 00:00:00 2001 From: GeoffreyCoulaud Date: Fri, 7 Jul 2023 18:06:07 +0200 Subject: [PATCH] Store improvements - Store games by source - Added convenience dunder methods (contains, iter, len, getitem) - Added store.get - Changed `enable_in_pipeline` for `toggle_in_pipeline` --- src/details_window.py | 5 ++-- src/main.py | 2 +- src/preferences.py | 3 +-- src/store/store.py | 58 ++++++++++++++++++++++++++++++++++++------- src/window.py | 2 +- 5 files changed, 55 insertions(+), 15 deletions(-) diff --git a/src/details_window.py b/src/details_window.py index 3b7ba4f..addebf3 100644 --- a/src/details_window.py +++ b/src/details_window.py @@ -155,9 +155,10 @@ class DetailsWindow(Adw.Window): return # Increment the number after the game id (eg. imported_1, imported_2) + source_id = "imported" numbers = [0] game_id: str - for game_id in shared.store.games: + for game_id in shared.source_games[source_id]: prefix = "imported_" if not game_id.startswith(prefix): continue @@ -168,7 +169,7 @@ class DetailsWindow(Adw.Window): { "game_id": f"imported_{game_number}", "hidden": False, - "source": "imported", + "source": source_id, "added": int(time()), } ) diff --git a/src/main.py b/src/main.py index 21fdfe0..e7c7553 100644 --- a/src/main.py +++ b/src/main.py @@ -93,7 +93,7 @@ class CartridgesApplication(Adw.Application): shared.store.add_manager(SteamAPIManager()) shared.store.add_manager(OnlineCoverManager()) shared.store.add_manager(SGDBManager()) - shared.store.enable_manager_in_pipelines(FileManager) + shared.store.toggle_manager_in_pipelines(FileManager, True) # Create actions self.create_actions( diff --git a/src/preferences.py b/src/preferences.py index 2feec84..9e9be4d 100644 --- a/src/preferences.py +++ b/src/preferences.py @@ -214,10 +214,9 @@ class PreferencesWindow(Adw.PreferencesWindow): self.toast.dismiss() def remove_all_games(self, *_args): - for game in shared.store.games.values(): + for game in shared.store: if not game.removed: self.removed_games.add(game) - game.removed = True game.save() game.update() diff --git a/src/store/store.py b/src/store/store.py index d56a746..9da9ef0 100644 --- a/src/store/store.py +++ b/src/store/store.py @@ -18,6 +18,7 @@ # SPDX-License-Identifier: GPL-3.0-or-later import logging +from typing import MutableMapping, Generator, Any from src import shared from src.game import Game @@ -31,24 +32,59 @@ class Store: managers: dict[type[Manager], Manager] pipeline_managers: set[Manager] pipelines: dict[str, Pipeline] - games: dict[str, Game] + source_games: MutableMapping[str, MutableMapping[str, Game]] def __init__(self) -> None: self.managers = {} self.pipeline_managers = set() self.pipelines = {} - self.games = {} + self.source_games = {} + + def __contains__(self, obj: object) -> bool: + """Check if the game is present in the store with the `in` keyword""" + if not isinstance(obj, Game): + return False + if not (source_mapping := self.source_games.get(obj.source)): + return False + return obj.game_id in source_mapping + + def __iter__(self) -> Generator[Game, None, None]: + """Iterate through the games in the store with `for ... in`""" + for _source_id, games_mapping in self.source_games.items(): + for _game_id, game in games_mapping.items(): + yield game + + def __len__(self) -> int: + """Get the number of games in the store with the `len` builtin""" + return sum(len(source_mapping) for source_mapping in self.source_games) + + def __getitem__(self, game_id: str) -> Game: + """Get a game by its id with `store["game_id_goes_here"]`""" + for game in iter(self): + if game.game_id == game_id: + return game + raise KeyError("Game not found in store") + + def get(self, game_id: str, default: Any = None) -> Game | Any: + """Get a game by its ID, with a fallback if not found""" + try: + game = self[game_id] + return game + except KeyError: + return default def add_manager(self, manager: Manager, in_pipeline=True): """Add a manager to the store""" manager_type = type(manager) self.managers[manager_type] = manager - if in_pipeline: - self.enable_manager_in_pipelines(manager_type) + self.toggle_manager_in_pipelines(manager_type, in_pipeline) - def enable_manager_in_pipelines(self, manager_type: type[Manager]): - """Make a manager run in new pipelines""" - self.pipeline_managers.add(self.managers[manager_type]) + def toggle_manager_in_pipelines(self, manager_type: type[Manager], enable: bool): + """Change if a manager should run in new pipelines""" + if enable: + self.pipeline_managers.add(self.managers[manager_type]) + else: + self.pipeline_managers.discard(self.managers[manager_type]) def cleanup_game(self, game: Game) -> None: """Remove a game's files""" @@ -74,7 +110,7 @@ class Store: return None # Handle game duplicates - stored_game = self.games.get(game.game_id) + stored_game = self.get(game.game_id) if not stored_game: # New game, do as normal logging.debug("New store game %s (%s)", game.name, game.game_id) @@ -96,11 +132,15 @@ class Store: for signal in manager.signals: game.connect(signal, manager.execute_resilient_manager_logic) + # Add the game to the store + if not game.source in self.source_games: + self.source_games[game.source] = {} + self.source_games[game.source][game.game_id] = game + # Run the pipeline for the game if not run_pipeline: return None pipeline = Pipeline(game, additional_data, self.pipeline_managers) - self.games[game.game_id] = game self.pipelines[game.game_id] = pipeline pipeline.advance() return pipeline diff --git a/src/window.py b/src/window.py index a3d1df4..16e3588 100644 --- a/src/window.py +++ b/src/window.py @@ -117,7 +117,7 @@ class CartridgesWindow(Adw.ApplicationWindow): def set_library_child(self): child, hidden_child = self.notice_empty, self.hidden_notice_empty - for game in shared.store.games.values(): + for game in shared.store: if game.removed or game.blacklisted: continue if game.hidden: