Options parsing
This commit is contained in:
parent
2ec5e8b29b
commit
95a3df8bed
@ -1,8 +1,15 @@
|
|||||||
import os
|
import os
|
||||||
import logging
|
import logging
|
||||||
|
import sys
|
||||||
from rich.logging import RichHandler
|
from rich.logging import RichHandler
|
||||||
from rich.traceback import install
|
from rich.traceback import install
|
||||||
import configparser
|
import configparser
|
||||||
|
import inflect
|
||||||
|
|
||||||
|
|
||||||
|
# Exit codes
|
||||||
|
# 1: Config file invalid, it has no sections
|
||||||
|
# 2: Config file invalid, sections must define at least CONST.CFG_MANDATORY
|
||||||
|
|
||||||
|
|
||||||
class CONST(object):
|
class CONST(object):
|
||||||
@ -57,7 +64,87 @@ class ConfigParser(
|
|||||||
return super().options(section)
|
return super().options(section)
|
||||||
|
|
||||||
|
|
||||||
|
p = inflect.engine()
|
||||||
|
|
||||||
ini_defaults = []
|
ini_defaults = []
|
||||||
internal_defaults = {default["key"]: default["value"] for default in CONST.CFG_KNOWN_DEFAULTS}
|
internal_defaults = {default["key"]: default["value"] for default in CONST.CFG_KNOWN_DEFAULTS}
|
||||||
config = ConfigParser(defaults=internal_defaults)
|
config = ConfigParser(defaults=internal_defaults)
|
||||||
config.read(CONST.CFG_DEFAULT_FILENAME)
|
config.read(CONST.CFG_DEFAULT_FILENAME)
|
||||||
|
|
||||||
|
|
||||||
|
def print_section_header(
|
||||||
|
header: str) -> str:
|
||||||
|
return f"Loading config section '[{header}]' ..."
|
||||||
|
|
||||||
|
|
||||||
|
def validate_default_section(
|
||||||
|
config_obj: configparser.ConfigParser()) -> None:
|
||||||
|
log.debug(f"Loading config from file '{CONST.CFG_DEFAULT_ABS_PATH}' ...")
|
||||||
|
if not config_obj.sections():
|
||||||
|
log.error(f"No config sections found in '{CONST.CFG_DEFAULT_ABS_PATH}'. Exiting 1 ...")
|
||||||
|
sys.exit(1)
|
||||||
|
if config.defaults():
|
||||||
|
log.debug(f"Symbol legend:\n"
|
||||||
|
f"* Global default from section '[{config_obj.default_section}]'\n"
|
||||||
|
f"~ Local option, doesn't exist in '[{config_obj.default_section}]'\n"
|
||||||
|
f"+ Local override of a value from '[{config_obj.default_section}]'\n"
|
||||||
|
f"= Local override, same value as in '[{config_obj.default_section}]'")
|
||||||
|
log.debug(print_section_header(config_obj.default_section))
|
||||||
|
for default in config_obj.defaults():
|
||||||
|
ini_defaults.append({default: config_obj[config_obj.default_section][default]})
|
||||||
|
log.debug(f"* {default} = {config_obj[config_obj.default_section][default]}")
|
||||||
|
else:
|
||||||
|
log.debug(f"No defaults defined")
|
||||||
|
|
||||||
|
|
||||||
|
def config_has_valid_section(
|
||||||
|
config_obj: configparser.ConfigParser()) -> bool:
|
||||||
|
has_valid_section = False
|
||||||
|
for config_obj_section in config_obj.sections():
|
||||||
|
if set(CONST.CFG_MANDATORY).issubset(config_obj.options(config_obj_section)):
|
||||||
|
has_valid_section = True
|
||||||
|
break
|
||||||
|
return has_valid_section
|
||||||
|
|
||||||
|
|
||||||
|
def is_default(
|
||||||
|
config_key: str) -> bool:
|
||||||
|
return any(config_key in ini_default for ini_default in ini_defaults)
|
||||||
|
|
||||||
|
|
||||||
|
def is_same_as_default(
|
||||||
|
config_kv_pair: dict) -> bool:
|
||||||
|
return config_kv_pair in ini_defaults
|
||||||
|
|
||||||
|
|
||||||
|
def validate_config_sections(
|
||||||
|
config_obj: configparser.ConfigParser()) -> None:
|
||||||
|
for this_section in config_obj.sections():
|
||||||
|
log.debug(print_section_header(this_section))
|
||||||
|
if not set(CONST.CFG_MANDATORY).issubset(config_obj.options(this_section, no_defaults=True)):
|
||||||
|
log.warning(f"Config section '[{this_section}]' does not have all mandatory options "
|
||||||
|
f"{CONST.CFG_MANDATORY} set, skipping section ...")
|
||||||
|
config_obj.remove_section(this_section)
|
||||||
|
else:
|
||||||
|
for key in config_obj.options(this_section, no_defaults=True):
|
||||||
|
kv_prefix = "~"
|
||||||
|
if is_default(key):
|
||||||
|
kv_prefix = "+"
|
||||||
|
if is_same_as_default({key: config_obj[this_section][key]}):
|
||||||
|
kv_prefix = "="
|
||||||
|
log.debug(f"{kv_prefix} {key} = {config_obj[this_section][key]}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
validate_default_section(config)
|
||||||
|
if config_has_valid_section(config):
|
||||||
|
validate_config_sections(config)
|
||||||
|
else:
|
||||||
|
log.error(f"No valid config section found. A valid config section has at least the mandatory "
|
||||||
|
f"""{p.plural("option", len(CONST.CFG_MANDATORY))} """
|
||||||
|
f"{CONST.CFG_MANDATORY} set. Exiting 1 ...")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
log.debug(f"Iterating over config sections ...")
|
||||||
|
for section in config.sections():
|
||||||
|
log.debug(f"Processing section '[{section}]' ...")
|
||||||
|
@ -1 +1,2 @@
|
|||||||
rich
|
rich
|
||||||
|
inflect
|
@ -6,6 +6,8 @@
|
|||||||
#
|
#
|
||||||
commonmark==0.9.1
|
commonmark==0.9.1
|
||||||
# via rich
|
# via rich
|
||||||
|
inflect==5.4.0
|
||||||
|
# via -r requirements.in
|
||||||
pygments==2.11.2
|
pygments==2.11.2
|
||||||
# via rich
|
# via rich
|
||||||
rich==12.0.0
|
rich==12.0.0
|
||||||
|
Loading…
x
Reference in New Issue
Block a user