import ast from argparse import Namespace from collections import defaultdict from configparser import ConfigParser from pathlib import Path from lib.utils.model_io import ModelParameters def is_jsonable(x): import json try: json.dumps(x) return True except TypeError: return False class Config(ConfigParser): # TODO: Do this programmatically; This did not work: # Initialize Default Sections # for section in self.default_sections: # self.__setattr__(section, property(lambda x :x._get_namespace_for_section(section)) @property def main(self): return self._get_namespace_for_section('main') @property def model(self): return self._get_namespace_for_section('model') @property def train(self): return self._get_namespace_for_section('train') @property def data(self): return self._get_namespace_for_section('data') @property def project(self): return self._get_namespace_for_section('project') ################################################### @property def model_paramters(self): return ModelParameters(self.model, self.train, self.data) @property def tags(self, ): return [f'{key}: {val}' for key, val in self.serializable.items()] @property def serializable(self): return {f'{section}_{key}': val for section, params in self._sections.items() for key, val in params.items() if is_jsonable(val)} @property def as_dict(self): return self._sections def _get_namespace_for_section(self, item): return Namespace(**{key: self.get(item, key) for key in self[item]}) def __init__(self, **kwargs): super(Config, self).__init__(**kwargs) pass @classmethod def read_namespace(cls, namespace: Namespace): space_dict = defaultdict(dict) for key in namespace.__dict__: section, *attr_name = key.split('_') attr_name = '_'.join(attr_name) value = str(namespace.__getattribute__(key)) space_dict[section][attr_name] = value new_config = cls() new_config.read_dict(space_dict) return new_config def get(self, *args, **kwargs): item = super(Config, self).get(*args, **kwargs) try: return ast.literal_eval(item) except SyntaxError: return item except ValueError: return item def write(self, filepath, **kwargs): path = Path(filepath, exist_ok=True) path.parent.mkdir(parents=True, exist_ok=True) with path.open('w') as configfile: super().write(configfile) return True