75 lines
2.2 KiB
Python
75 lines
2.2 KiB
Python
from collections.abc import Iterable
|
|
from typing import Any
|
|
from typing import Callable
|
|
from typing import Generic
|
|
from typing import Iterator
|
|
from typing import Protocol
|
|
from typing import TypeVar
|
|
|
|
|
|
# Type Support #####################################################################################
|
|
|
|
class HasGameId(Protocol):
|
|
|
|
@property
|
|
def gameId(self) -> str: ...
|
|
|
|
CatalogItem = TypeVar("CatalogItem", bound=HasGameId)
|
|
|
|
MapTarget = TypeVar("MapTarget")
|
|
|
|
|
|
# Class ############################################################################################
|
|
|
|
class Catalog(Generic[CatalogItem]):
|
|
|
|
def __init__(self, items:Iterable[CatalogItem]|None=None):
|
|
self._items:dict[str,CatalogItem] = {}
|
|
|
|
for item in (items or []):
|
|
self.add(item)
|
|
|
|
def __contains__(self, gameId:str) -> bool:
|
|
return gameId in self._items
|
|
|
|
def __delitem__(self, gameId:str):
|
|
del self._items[gameId]
|
|
|
|
def __eq__(self, other:Any) -> bool:
|
|
if type(self) != type(other): return False
|
|
if self._items != other._items: return False
|
|
return True
|
|
|
|
def __getitem__(self, gameId:str) -> CatalogItem:
|
|
return self._items[gameId]
|
|
|
|
def __iter__(self) -> Iterator[CatalogItem]:
|
|
for gameId in sorted([i.gameId for i in self._items.values()]):
|
|
yield self._items[gameId]
|
|
|
|
def __len__(self) -> int:
|
|
return len(self._items)
|
|
|
|
def __repr__(self) -> str:
|
|
return "".join(str(p) for p in [
|
|
self.__class__.__name__, "[",
|
|
", ".join(str(i) for i in self),
|
|
"]"
|
|
])
|
|
|
|
def add(self, item:CatalogItem) -> "Catalog[CatalogItem]":
|
|
if item.gameId in self._items:
|
|
raise Exception(f"Catalog already contains {item.gameId}")
|
|
|
|
self._items[item.gameId] = item
|
|
return self
|
|
|
|
def filter(self, isAllowed:Callable[[CatalogItem], bool]) -> Iterator[CatalogItem]:
|
|
for item in self:
|
|
if isAllowed(item):
|
|
yield item
|
|
|
|
def map(self, doTransform:Callable[[CatalogItem], MapTarget]) -> Iterator[MapTarget]:
|
|
for item in self:
|
|
yield doTransform(item)
|