from abc import abstractmethod from logging import Logger from pathlib import Path from typing import ( Any, Final, Iterable, Iterator, Protocol, Sequence, TypeVar, overload, ) from numpy.typing import NDArray _T = TypeVar("_T") class ProgressHandler(Protocol): @overload def wrap(self, values: Sequence[_T]) -> Iterator[_T]: ... @overload def wrap(self, values: Iterable[_T], total: int) -> Iterator[_T]: ... class FileHandler: @abstractmethod def create( self, filename: str, content: bytes, text: bool = False ) -> Path | None: ... def image(self, filename: str, image: NDArray[Any]): import imageio.v3 as iio from pygifsicle import optimize # type: ignore data = iio.imwrite("", image, extension=Path(filename).suffix) # type: ignore path = self.create(filename, data, False) assert path is not None optimize(path, options=["--no-warnings"]) class BaseSolver: def __init__( self, logger: Logger, verbose: bool, year: int, day: int, progress: ProgressHandler, files: FileHandler | None = None, ): self.logger: Final = logger self.verbose: Final = verbose self.year: Final = year self.day: Final = day self.progress: Final = progress self.files: Final = files @abstractmethod def solve(self, input: str) -> Iterator[Any] | None: ...