Source code for smif.data_layer.model_loader

"""ModelLoader reads python modules as specified at runtime, loading and instantiating
objects.
"""
import importlib
import logging
import os


[docs]class ModelLoader(object): """Load Model from config Examples -------- Call :py:meth:`ModelLoader.load` to create, load and return a :class:`Model` object. >>> loader = ModelLoader() >>> sector_model = loader.load(sector_model_config) >>> conversion_model = loader.load(conversion_model_config) """ def __init__(self): self.logger = logging.getLogger(__name__)
[docs] def load(self, config): """Loads the model class specified by the config, returns an instance of that class using the Model.from_dict method. Arguments --------- config : dict The model configuration data. Must include: - name (name for smif internal use) - path (absolute path to python module file) - classname (name of Model implementation class) - anything required by the Model.from_dict classmethod Returns ------- :class:`~smif.model.Model` """ klass = self.load_model_class( config["name"], config["path"], config["classname"] ) if not hasattr(klass, "from_dict"): msg = ( "Model '{}' does not have a ``from_dict`` method and " "cannot be loaded from config" ) raise KeyError(msg.format(config["name"])) model_instance = klass.from_dict(config) if model_instance: return model_instance else: raise ValueError("Model not initialised from configuration data")
[docs] def load_model_class(self, model_name, model_path, classname): """Dynamically load model class Arguments --------- model_name : str The name used internally to identify the SectorModel model_path : str The path to the python module which contains the SectorModel implementation classname : str The name of the class of the SectorModel implementation Returns ------- class The SectorModel implementation """ if not os.path.exists(model_path): msg = "Cannot find '{}' for the '{}' model".format(model_path, model_name) raise FileNotFoundError(msg) msg = "Importing model %s as class %s from module at %s" self.logger.info(msg, model_name, classname, model_path) spec = importlib.util.spec_from_file_location(model_name, model_path) module = importlib.util.module_from_spec(spec) spec.loader.exec_module(module) klass = module.__dict__[classname] return klass