from abc import ABC, abstractmethod from pathlib import Path import time from typing import Generic, TypeVar, override import pickle K = TypeVar("K") V = TypeVar("V") class Cacheable(ABC): @abstractmethod def dump_cache(self, path: Path): pass @abstractmethod def load_cache(self, path: Path): pass class TTLCache(Generic[K, V], Cacheable): def __init__(self, ttl_seconds: int = 3600) -> None: self.ttl: int = ttl_seconds self.__cache: dict[K, tuple[V, float]] = {} def get(self, key: K) -> V | None: if key in self.__cache: value, timestamp = self.__cache[key] if time.time() - timestamp < self.ttl: return value else: del self.__cache[key] return None def set(self, key: K, value: V) -> None: self.__cache[key] = (value, time.time()) def clear(self) -> None: self.__cache.clear() @override def dump_cache(self, path: Path) -> None: path.parent.mkdir(parents=True, exist_ok=True) with open(path, 'wb') as f: pickle.dump(self.__cache, f) @override def load_cache(self, path: Path): if path.exists(): with open(path, 'rb') as f: self.__cache = pickle.load(f)