ÿØÿàJFIFÿþ ÿÛC       ÿÛC ÿÀÿÄÿÄ"#QrÿÄÿÄ&1!A"2qQaáÿÚ ?Øy,æ/3JæÝ¹È߲؋5êXw²±ÉyˆR”¾I0ó2—PI¾IÌÚiMö¯–þrìN&"KgX:Šíµ•nTJnLK„…@!‰-ý ùúmë;ºgµŒ&ó±hw’¯Õ@”Ü— 9ñ-ë.²1<yà‚¹ïQÐU„ہ?.’¦èûbß±©Ö«Âw*VŒ) `$‰bØÔŸ’ëXÖ-ËTÜíGÚ3ð«g Ÿ§¯—Jx„–’U/ÂÅv_s(Hÿ@TñJÑãõçn­‚!ÈgfbÓc­:él[ðQe 9ÀPLbÃãCµm[5¿ç'ªjglå‡Ûí_§Úõl-;"PkÞÞÁQâ¼_Ñ^¢SŸx?"¸¦ùY騐ÒOÈ q’`~~ÚtËU¹CڒêV  I1Áß_ÿÙimport functools import logging import pickle from asyncio import iscoroutinefunction from typing import Union, Callable logger = logging.getLogger(__name__) def _dump(path, obj): # separate function to mock in tests with open(path, "wb") as w: pickle.dump(obj, w) def serialize_attr(*, path: str, attr: str): """ Make decorator to serialize an object or object's attribute :param path: path to file to serialize into :param attr: attribute name to serialize """ def decorator(f): @functools.wraps(f) def wrapper(self, *args, **kwargs): result = f(self, *args, **kwargs) obj = getattr(self, attr) logger.debug("Write %r to %r", obj, path) _dump(path, obj) return result @functools.wraps(f) async def async_wrapper(self, *args, **kwargs): result = await f(self, *args, **kwargs) obj = getattr(self, attr) logger.debug("Write %r to %r", obj, path) _dump(path, obj) return result if iscoroutinefunction(f): return async_wrapper return wrapper return decorator def unserialize(*, path: str, fallback: Union[Callable, object] = None): """ Restore an object from file :param path: path to read from :param fallback: return or call it if unserialization fails :return: """ try: with open(path, "rb") as r: return pickle.load(r) except FileNotFoundError: logger.warning("Can't find %s to unserialize", path) except Exception as e: logger.error("Unserialize failed with %r. Returning an fallback", e) return fallback() if callable(fallback) else fallback