import functools import json from . import errors class CacheFileBase: def __init__(self, path, *args, **kwargs): self.path = path try: self.open_file = path.open(*args, **kwargs) except OSError as error: self._translate_error(error, 'init') def _translate_error(self, error, when): for orig_type, mapped_type in self.ERRORS_MAP: if isinstance(error, orig_type): raise mapped_type(self.path) from error raise error def __enter__(self): return self.open_file def __exit__(self, exc_type, exc_value, exc_tb): try: self.open_file.close() except OSError as error: self._translate_error(error, 'exit') class CacheBase: ConfigurationError = errors.CacheConfigurationError def __init__(self, dir_path, **kwargs): self.dir_path = dir_path try: self.CacheFile = kwargs.pop('file_class') except KeyError: pass self.fn_patterns = {} self.setup(**kwargs) def setup(self, **kwargs): for method_name, pattern in kwargs.items(): try: is_api_method = getattr(self, method_name).is_api_method except AttributeError: is_api_method = False if not is_api_method: raise errors.CacheConfigurationError(method_name) self.fn_patterns[method_name] = pattern def _wrap_api_method(orig_func): @functools.wraps(orig_func) def api_method_wrapper(self, *args, **kwargs): try: fn_pattern = self.fn_patterns[orig_func.__name__] except KeyError: raise self.ConfigurationError(orig_func.__name__) from None pattern_kwargs = orig_func(self, *args, **kwargs) path = self.dir_path / fn_pattern.format(**pattern_kwargs) return self.open(path) api_method_wrapper.is_api_method = True return api_method_wrapper @_wrap_api_method def historical(self, date, base): return {'date': date.isoformat(), 'base': base} class WriteCacheFile(CacheFileBase): ERRORS_MAP = [] class CacheWriter(CacheBase): CacheFile = WriteCacheFile def open(self, path): return self.CacheFile(path, 'w') def write_json(self, cache_file, thing): json.dump(thing, cache_file, indent=2) def save_rate(self, rate): with self.historical(rate.timestamp.date(), rate.base) as cache_file: self.write_json(cache_file, rate.serialize())