from dataclasses import dataclass import eaapi class Model: def __init__(self, gamecode: str, dest: str, spec: str, rev: str, datecode: str): self._gamecode = gamecode self._dest = dest self._spec = spec self._rev = rev self._datecode = datecode @classmethod def from_model_str(cls, model: str) -> "Model": return cls(*eaapi.parse_model(model)) @property def gamecode(self): return self._gamecode @property def dest(self): return self._dest @property def spec(self): return self._spec @property def rev(self): return self._rev @property def datecode(self): return int(self._datecode) @property def year(self): return int(self._datecode[:4]) @property def month(self): return int(self._datecode[4:6]) @property def day(self): return int(self._datecode[6:8]) @property def minor(self): return int(self._datecode[8:10]) def __hash__(self): return hash(str(self)) def __eq__(self, other): if not isinstance(other, Model): return False return str(other) == str(self) def __str__(self): return f"{self.gamecode}:{self.dest}:{self.spec}:{self.rev}:{self.datecode}" def __repr__(self): return f"" @dataclass class DatecodeMatcher: year: int | None = None month: int | None = None day: int | None = None minor: int | None = None @classmethod def from_str(cls, datecode: str): if len(datecode) != 10 or not datecode.isdigit(): raise ValueError("Not a valid datecode") return cls( int(datecode[0:4]), int(datecode[4:6]), int(datecode[6:8]), int(datecode[8:10]) ) def _num_filters(self): num = 0 if self.year is not None: num += 1 if self.month is not None: num += 1 if self.day is not None: num += 1 if self.minor is not None: num += 1 return num def __lt__(self, other): if self._num_filters() < other._num_filters(): return False if self.minor is None and other.minor is not None: return False if self.day is None and other.day is not None: return False if self.month is None and other.month is not None: return False if self.year is None and other.year is not None: return False return True def __hash__(self): return hash(str(self)) def __str__(self): year = self.year if self.year is not None else "----" month = self.month if self.month is not None else "--" day = self.day if self.day is not None else "--" minor = self.minor if self.minor is not None else "--" return f"{year:04}{month:02}{day:02}{minor:02}" def matches(self, model): if self.year is not None and model.year != self.year: return False if self.month is not None and model.month != self.month: return False if self.day is not None and model.day != self.day: return False if self.minor is not None and model.minor != self.minor: return False return True @dataclass class ModelMatcher: gamecode: str | None = None dest: str | None = None spec: str | None = None rev: str | None = None datecode: list[DatecodeMatcher] | DatecodeMatcher | None = None def _num_filters(self): num = 0 if self.gamecode is not None: num += 1 if self.dest is not None: num += 1 if self.spec is not None: num += 1 if self.rev is not None: num += 1 if isinstance(self.datecode, list): num += sum(i._num_filters() for i in self.datecode) elif self.datecode is not None: num += self.datecode._num_filters() return num def __lt__(self, other): if self._num_filters() < other._num_filters(): return False if self.datecode is None and other.datecode is not None: return False if self.rev is None and other.rev is not None: return False if self.spec is None and other.spec is not None: return False if self.dest is None and other.dest is not None: return False if self.gamecode is None and other.gamecode is not None: return False return True def __hash__(self): return hash(str(self)) def __str__(self): gamecode = self.gamecode if self.gamecode is not None else "---" dest = self.dest if self.dest is not None else "-" spec = self.spec if self.spec is not None else "-" rev = self.rev if self.rev is not None else "-" datecode = self.datecode if self.datecode is not None else "-" * 10 if isinstance(self.datecode, list): datecode = "/".join(str(i) for i in self.datecode) if not datecode: datecode = "-" * 10 return f"{gamecode:3}:{dest}:{spec}:{rev}:{datecode}" def matches(self, model): if self.gamecode is not None and model.gamecode != self.gamecode: return False if self.dest is not None and model.dest != self.dest: return False if self.spec is not None and model.spec != self.spec: return False if self.rev is not None and model.rev != self.rev: return False if isinstance(self.datecode, list): return any(i.matches(model) for i in self.datecode) if self.datecode is not None: return self.datecode.matches(model) return True