confighelper: add annotations

Signed-off-by:  Eric Callahan <arksine.code@gmail.com>
This commit is contained in:
Arksine 2021-05-11 18:12:08 -04:00
parent ca69a10838
commit 420ba065da
1 changed files with 67 additions and 22 deletions

View File

@ -3,19 +3,46 @@
# Copyright (C) 2020 Eric Callahan <arksine.code@gmail.com> # Copyright (C) 2020 Eric Callahan <arksine.code@gmail.com>
# #
# This file may be distributed under the terms of the GNU GPLv3 license # This file may be distributed under the terms of the GNU GPLv3 license
from __future__ import annotations
import configparser import configparser
import os import os
import logging import logging
from utils import SentinelClass
# Annotation imports
from typing import (
TYPE_CHECKING,
Any,
Callable,
Type,
IO,
TypeVar,
Union,
Dict,
List,
)
if TYPE_CHECKING:
from argparse import Namespace
from moonraker import Server
_T = TypeVar("_T")
ConfigVal = Union[None, int, float, bool, str]
SENTINEL = SentinelClass.get_instance()
class ConfigError(Exception): class ConfigError(Exception):
pass pass
class Sentinel:
pass
class ConfigHelper: class ConfigHelper:
error = ConfigError error = ConfigError
def __init__(self, server, config, section, orig_sects, parsed={}): def __init__(self,
server: Server,
config: configparser.ConfigParser,
section: str,
orig_sects: List[str],
parsed: Dict[str, Dict[str, ConfigVal]] = {}
) -> None:
self.server = server self.server = server
self.config = config self.config = config
self.section = section self.section = section
@ -26,38 +53,42 @@ class ConfigHelper:
self.sections = config.sections self.sections = config.sections
self.has_section = config.has_section self.has_section = config.has_section
def get_server(self): def get_server(self) -> Server:
return self.server return self.server
def __getitem__(self, key): def __getitem__(self, key: str) -> ConfigHelper:
return self.getsection(key) return self.getsection(key)
def __contains__(self, key): def __contains__(self, key: str) -> bool:
return key in self.config return key in self.config
def get_name(self): def get_name(self) -> str:
return self.section return self.section
def get_options(self): def get_options(self) -> Dict[str, str]:
return dict(self.config[self.section]) return dict(self.config[self.section])
def get_prefix_sections(self, prefix): def get_prefix_sections(self, prefix: str) -> List[str]:
return [s for s in self.sections() if s.startswith(prefix)] return [s for s in self.sections() if s.startswith(prefix)]
def getsection(self, section): def getsection(self, section: str) -> ConfigHelper:
if section not in self.config: if section not in self.config:
raise ConfigError(f"No section [{section}] in config") raise ConfigError(f"No section [{section}] in config")
return ConfigHelper(self.server, self.config, section, return ConfigHelper(self.server, self.config, section,
self.orig_sections, self.parsed) self.orig_sections, self.parsed)
def _get_option(self, func, option, default): def _get_option(self,
func: Callable[..., Any],
option: str,
default: Union[SentinelClass, _T]
) -> _T:
try: try:
val = func(option, default) val = func(option, default)
except Exception: except Exception:
raise ConfigError( raise ConfigError(
f"Error parsing option ({option}) from " f"Error parsing option ({option}) from "
f"section [{self.section}]") f"section [{self.section}]")
if val == Sentinel: if isinstance(val, SentinelClass):
raise ConfigError( raise ConfigError(
f"No option found ({option}) in section [{self.section}]") f"No option found ({option}) in section [{self.section}]")
if self.section in self.orig_sections: if self.section in self.orig_sections:
@ -65,23 +96,35 @@ class ConfigHelper:
self.parsed[self.section][option] = val self.parsed[self.section][option] = val
return val return val
def get(self, option, default=Sentinel): def get(self,
option: str,
default: Union[SentinelClass, _T] = SENTINEL
) -> Union[str, _T]:
return self._get_option( return self._get_option(
self.config[self.section].get, option, default) self.config[self.section].get, option, default)
def getint(self, option, default=Sentinel): def getint(self,
option: str,
default: Union[SentinelClass, _T] = SENTINEL
) -> Union[int, _T]:
return self._get_option( return self._get_option(
self.config[self.section].getint, option, default) self.config[self.section].getint, option, default)
def getboolean(self, option, default=Sentinel): def getboolean(self,
option: str,
default: Union[SentinelClass, _T] = SENTINEL
) -> Union[bool, _T]:
return self._get_option( return self._get_option(
self.config[self.section].getboolean, option, default) self.config[self.section].getboolean, option, default)
def getfloat(self, option, default=Sentinel): def getfloat(self,
option: str,
default: Union[SentinelClass, _T] = SENTINEL
) -> Union[float, _T]:
return self._get_option( return self._get_option(
self.config[self.section].getfloat, option, default) self.config[self.section].getfloat, option, default)
def read_supplemental_config(self, file_name): def read_supplemental_config(self, file_name: str) -> None:
cfg_file_path = os.path.normpath(os.path.expanduser(file_name)) cfg_file_path = os.path.normpath(os.path.expanduser(file_name))
if not os.path.isfile(cfg_file_path): if not os.path.isfile(cfg_file_path):
raise ConfigError( raise ConfigError(
@ -91,13 +134,13 @@ class ConfigHelper:
except Exception: except Exception:
raise ConfigError(f"Error Reading Config: '{cfg_file_path}'") raise ConfigError(f"Error Reading Config: '{cfg_file_path}'")
def write_config(self, file_obj): def write_config(self, file_obj: IO[str]) -> None:
self.config.write(file_obj) self.config.write(file_obj)
def get_parsed_config(self): def get_parsed_config(self) -> Dict[str, Dict[str, ConfigVal]]:
return dict(self.parsed) return dict(self.parsed)
def validate_config(self): def validate_config(self) -> None:
for sect in self.orig_sections: for sect in self.orig_sections:
if sect not in self.parsed: if sect not in self.parsed:
logging.warn( logging.warn(
@ -112,8 +155,10 @@ class ConfigHelper:
f"[{sect}]. In the future this will result in a " f"[{sect}]. In the future this will result in a "
"startup error.") "startup error.")
def get_configuration(server, system_args): def get_configuration(server: Server,
cfg_file_path = os.path.normpath(os.path.expanduser( system_args: Namespace
) -> ConfigHelper:
cfg_file_path: str = os.path.normpath(os.path.expanduser(
system_args.configfile)) system_args.configfile))
if not os.path.isfile(cfg_file_path): if not os.path.isfile(cfg_file_path):
raise ConfigError( raise ConfigError(