Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
_config.py129 linesDownload Raw Back to testing
1import configparser2import dataclasses3from dataclasses import dataclass4from pathlib import Path5from typing import Callable6from typing import ClassVar7from typing import Optional8from typing import Union9 10from .helpers import make_path11 12 13class ConfigError(BaseException):14    pass15 16 17class MissingConfig(ConfigError):18    pass19 20 21class MissingConfigSection(ConfigError):22    pass23 24 25class MissingConfigItem(ConfigError):26    pass27 28 29class ConfigValueTypeError(ConfigError):30    pass31 32 33class _GetterDispatch:34    def __init__(self, initialdata, default_getter: Callable):35        self.default_getter = default_getter36        self.data = initialdata37 38    def get_fn_for_type(self, type_):39        return self.data.get(type_, self.default_getter)40 41    def get_typed_value(self, type_, name):42        get_fn = self.get_fn_for_type(type_)43        return get_fn(name)44 45 46def _parse_cfg_file(filespec: Union[Path, str]):47    cfg = configparser.ConfigParser()48    try:49        filepath = make_path(filespec, check_exists=True)50    except FileNotFoundError as e:51        raise MissingConfig(f"No config file found at {filespec}") from e52    else:53        with open(filepath, encoding="utf-8") as f:54            cfg.read_file(f)55        return cfg56 57 58def _build_getter(cfg_obj, cfg_section, method, converter=None):59    def caller(option, **kwargs):60        try:61            rv = getattr(cfg_obj, method)(cfg_section, option, **kwargs)62        except configparser.NoSectionError as nse:63            raise MissingConfigSection(64                f"No config section named {cfg_section}"65            ) from nse66        except configparser.NoOptionError as noe:67            raise MissingConfigItem(f"No config item for {option}") from noe68        except ValueError as ve:69            # ConfigParser.getboolean, .getint, .getfloat raise ValueError70            # on bad types71            raise ConfigValueTypeError(72                f"Wrong value type for {option}"73            ) from ve74        else:75            if converter:76                try:77                    rv = converter(rv)78                except Exception as e:79                    raise ConfigValueTypeError(80                        f"Wrong value type for {option}"81                    ) from e82            return rv83 84    return caller85 86 87def _build_getter_dispatch(cfg_obj, cfg_section, converters=None):88    converters = converters or {}89 90    default_getter = _build_getter(cfg_obj, cfg_section, "get")91 92    # support ConfigParser builtins93    getters = {94        int: _build_getter(cfg_obj, cfg_section, "getint"),95        bool: _build_getter(cfg_obj, cfg_section, "getboolean"),96        float: _build_getter(cfg_obj, cfg_section, "getfloat"),97        str: default_getter,98    }99 100    # use ConfigParser.get and convert value101    getters.update(102        {103            type_: _build_getter(104                cfg_obj, cfg_section, "get", converter=converter_fn105            )106            for type_, converter_fn in converters.items()107        }108    )109 110    return _GetterDispatch(getters, default_getter)111 112 113@dataclass114class ReadsCfg:115    section_header: ClassVar[str]116    converters: ClassVar[Optional[dict]] = None117 118    @classmethod119    def from_cfg_file(cls, filespec: Union[Path, str]):120        cfg = _parse_cfg_file(filespec)121        dispatch = _build_getter_dispatch(122            cfg, cls.section_header, converters=cls.converters123        )124        kwargs = {125            field.name: dispatch.get_typed_value(field.type, field.name)126            for field in dataclasses.fields(cls)127        }128        return cls(**kwargs)129