""" Implements loading and providing the configuration of the radar instance. Usage should be straight-forward: >>> from . import _config >>> config = _config.load() >>> config.locations ['New York City', 'Jersey City'] An example configuration file looks like this: [Storage] db = .waterspout/db.json [Locations] New York City Jersey City [Windy] key = [Web] port = 80 """ import configparser import dataclasses import typing @dataclasses.dataclass class Config: key: str locations: typing.List[str] db: str port: int class ConfigError(Exception): "Raised when configuration could not be loaded or was malformed." def load(pathname: str="radar.conf") -> Config: "Loads configuration from a file at *pathname*. May raise ConfigError when content does not meet expectations." config = configparser.ConfigParser(allow_no_value=True) config.read(pathname) raw = {} errors = [] def _load_key(section, name, target=None, type=None, default=None, required=False): target = target or name try: value = config[section][name] if type: value = type(value) raw[target] = value except (KeyError, ValueError): if default: raw[target] = default if required: errors.append(f"Config is missing required field: {pathname}: {section}: {name}") _load_key("Storage", "db", default="radar.json") _load_key("Windy", "key", required=True) _load_key("Web", "port", type=int) try: raw["locations"] = list(config["Locations"]) except KeyError: errors.append(f"Config is missing Locations: {pathname}") if errors: raise ConfigError(*errors) return Config(**raw)