Source code for deepdish.util.saveable

from __future__ import division, print_function, absolute_import
from deepdish import io

_ERR_STR = "Must override load_from_dict for Saveable interface"


[docs]class Saveable(object): """ Key-value coding interface for classes. Generally, this is an interface that make it possible to access instance members through keys (strings), instead of through named variables. What this interface enables, is to save and load an instance of the class to file. This is done by encoding it into a dictionary, or decoding it from a dictionary. The dictionary is then saved/loaded using `deepdish.io.save`. """ @classmethod
[docs] def load(cls, path): """ Loads an instance of the class from a file. Parameters ---------- path : str Path to an HDF5 file. Examples -------- This is an abstract data type, but let us say that ``Foo`` inherits from ``Saveable``. To construct an object of this class from a file, we do: >>> foo = Foo.load('foo.h5') #doctest: +SKIP """ if path is None: return cls.load_from_dict({}) else: d = io.load(path) return cls.load_from_dict(d)
[docs] def save(self, path): """ Saves an instance of the class using `deepdish.io.save`. Parameters ---------- path : str Output path to HDF5 file. """ io.save(path, self.save_to_dict())
@classmethod
[docs] def load_from_dict(cls, d): """ Overload this function in your subclass. It takes a dictionary and should return a constructed object. When overloading, you have to decorate this function with ``@classmethod``. Parameters ---------- d : dict Dictionary representation of an instance of your class. Returns ------- obj : object Returns an object that has been constructed based on the dictionary. """ raise NotImplementedError(_ERR_STR)
[docs] def save_to_dict(self): """ Overload this function in your subclass. It should return a dictionary representation of the current instance. If you member variables that are objects, it is best to convert them to dictionaries before they are entered into your dictionary hierarchy. Returns ------- d : dict Returns a dictionary representation of the current instance. """ raise NotImplementedError(_ERR_STR)
[docs]class NamedRegistry(object): """ This class provides a named hierarchy of classes, where each class is associated with a string name. """ REGISTRY = {} @property def name(self): """Returns the name of the registry entry.""" # Automatically overloaded by 'register' return "noname" @classmethod
[docs] def register(cls, name): """Decorator to register a class.""" def register_decorator(reg_cls): def name_func(self): return name reg_cls.name = property(name_func) assert issubclass(reg_cls, cls), \ "Must be subclass matching your NamedRegistry class" cls.REGISTRY[name] = reg_cls return reg_cls return register_decorator
@classmethod
[docs] def getclass(cls, name): """ Returns the class object given its name. """ return cls.REGISTRY[name]
@classmethod
[docs] def construct(cls, name, *args, **kwargs): """ Constructs an instance of an object given its name. """ return cls.REGISTRY[name](*args, **kwargs)
@classmethod def registry(cls): return cls.REGISTRY @classmethod
[docs] def root(cls, reg_cls): """ Decorate your base class with this, to create a new registry for it """ reg_cls.REGISTRY = {} return reg_cls
[docs]class SaveableRegistry(Saveable, NamedRegistry): """ This combines the features of :class:`deepdish.util.Saveable` and :class:`deepdish.util.NamedRegistry`. See also -------- Saveable, NamedRegistry """ @classmethod def load(cls, path): if path is None: return cls.load_from_dict({}) else: d = io.load(path) # Check class type class_name = d.get('name') if class_name is not None: return cls.getclass(class_name).load_from_dict(d) else: return cls.load_from_dict(d) def save(self, path): d = self.save_to_dict() d['name'] = self.name io.save(path, d)