🎨 SourceIterator can yield addtitional data

SourceIterator-s can yield a game and a tuple of additional data.
This data will be passed to the Store, Pipeline and Managers.
This commit is contained in:
GeoffreyCoulaud
2023-06-07 14:01:06 +02:00
parent 7eef050a64
commit 98f02da36c
12 changed files with 68 additions and 37 deletions

View File

@@ -3,9 +3,9 @@ import logging
from gi.repository import Adw, Gio, Gtk
from src import shared
from src.game import Game
from src.utils.task import Task
from src.store.pipeline import Pipeline
from src.store.managers.manager import Manager
from src.importer.sources.source import Source
@@ -92,6 +92,7 @@ class Importer:
def source_task_thread_func(self, _task, _obj, data, _cancellable):
"""Source import task code"""
source: Source
source, *_rest = data
# Early exit if not installed
@@ -107,20 +108,35 @@ class Importer:
while True:
# Handle exceptions raised when iterating
try:
game = next(iterator)
iteration_result = next(iterator)
except StopIteration:
break
except Exception as exception: # pylint: disable=broad-exception-caught
logging.exception(
msg=f"Exception in source {source.id}",
exc_info=exception,
"Exception in source %s", source.id, exc_info=exception
)
continue
if game is None:
# Handle the result depending on its type
if isinstance(iteration_result, Game):
game = iteration_result
additional_data = tuple()
elif isinstance(iteration_result, tuple):
game, additional_data = iteration_result
elif iteration_result is None:
continue
else:
# Warn source implementers that an invalid type was produced
# Should not happen on production code
logging.warn(
"%s produced an invalid iteration return type %s",
source.id,
type(iteration_result),
)
continue
# Register game
pipeline: Pipeline = shared.store.add_game(game)
pipeline: Pipeline = shared.store.add_game(game, additional_data)
if pipeline is not None:
logging.info("Imported %s (%s)", game.name, game.game_id)
pipeline.connect("advanced", self.pipeline_advanced_callback)

View File

@@ -48,12 +48,9 @@ class ItchSourceIterator(SourceIterator):
"game_id": self.source.game_id_format.format(game_id=row[0]),
"executable": self.source.executable_format.format(cave_id=row[4]),
}
yield Game(values, allow_side_effects=False)
# TODO pass image URIs to the pipeline somehow
# - Add a reserved field to the Game object
# - Reconstruct those from the pipeline (we already have them)
# - Pass game and additional data to the pipeline separately (requires deep changes)
additional_data = (row[3], row[2])
game = Game(values, allow_side_effects=False)
yield (game, additional_data)
class ItchSource(Source):

View File

@@ -3,12 +3,15 @@ from abc import abstractmethod
from collections.abc import Iterable, Iterator
from functools import wraps
from pathlib import Path
from typing import Generator, Optional
from typing import Generator, Any
from src import shared
from src.game import Game
from src.utils.decorators import replaced_by_path
# Type of the data returned by iterating on a Source
SourceIterationResult = None | Game | tuple[Game, tuple[Any]]
class SourceIterator(Iterator):
"""Data producer for a source of games"""
@@ -24,11 +27,11 @@ class SourceIterator(Iterator):
def __iter__(self) -> "SourceIterator":
return self
def __next__(self) -> Optional[Game]:
def __next__(self) -> SourceIterationResult:
return next(self.generator)
@abstractmethod
def generator_builder(self) -> Generator[Optional[Game], None, None]:
def generator_builder(self) -> Generator[SourceIterationResult, None, None]:
"""
Method that returns a generator that produces games
* Should be implemented as a generator method
@@ -49,7 +52,6 @@ class Source(Iterable):
def __init__(self) -> None:
super().__init__()
self.available_on = set()
@property
def full_name(self) -> str: