3 from abc import ABC, abstractmethod
13 logger = logging.getLogger(__name__)
16 class Persistent(ABC):
26 class persistent_autoload_singleton(Persistent):
27 def __init__(self, filename: str, *, max_age_sec: int = 0):
28 self.filename = filename
29 self.max_age_sec = max_age_sec
32 def __call__(self, cls):
34 def _load(*args, **kwargs):
36 # If class has already been loaded, act like a singleton
37 # and return a reference to the one and only instance in
39 if self.instance is not None:
41 f'Returning already instantiated singleton instance of {cls.__name__}.'
46 assert self.instance is None
48 f'Instantiating {cls.__name__} directly.'
50 self.instance = cls(*args, **kwargs)
52 # On program exit, save state to disk.
53 atexit.register(self.save)
54 assert self.instance is not None
58 def load(self) -> bool:
60 file_utils.does_file_exist(self.filename)
62 self.max_age_sec == 0 or
63 file_utils.get_file_mtime_age_seconds(self.filename) <= self.max_age_sec
67 f'Attempting to load from file {self.filename}'
70 with open(self.filename, 'rb') as f:
71 self.instance = dill.load(f)
78 def save(self) -> bool:
79 if self.instance is not None:
81 f'Attempting to save {type(self.instance).__name__} to file {self.filename}'
84 with open(self.filename, 'wb') as f:
85 dill.dump(self.instance, f, dill.HIGHEST_PROTOCOL)