From 59ef593b3aa5db80bcfdd87ea74f73937b11064a Mon Sep 17 00:00:00 2001 From: Marko Mecina <marko.mecina@univie.ac.at> Date: Thu, 25 Aug 2022 14:06:29 +0200 Subject: [PATCH] confignator update (requires rebuild of module) - add option to disable full interpolation check for all options at init - add method to remove option from cfg section --- Tst/confignator/confignator/config.py | 81 +++++++++++++++++---------- 1 file changed, 51 insertions(+), 30 deletions(-) diff --git a/Tst/confignator/confignator/config.py b/Tst/confignator/confignator/config.py index bc12e3a..1a9e7a4 100755 --- a/Tst/confignator/confignator/config.py +++ b/Tst/confignator/confignator/config.py @@ -41,13 +41,7 @@ import os import logging import logging.handlers -# hardcoded stuff -# INFO: path to confignator_cfg, has to be "../build..." if started with pycharm and confignator is marked as root -# directory, otherwhise it has to be only "confignator.cfg". This is because normally the config file of the installed -# python confignator package would be used (".local/lib.../confignator"), but if marked as root in pycharm, it first -# searches for the config file in the confignator folder, where the cfg is in the given path... cfg = configparser.ConfigParser() -#confignator_cfg = os.path.join(os.path.dirname(__file__), '../build/lib/confignator/confignator.cfg') confignator_cfg = os.path.join(os.path.dirname(__file__), 'confignator.cfg') cfg.read(confignator_cfg) basic_config = cfg.get('confignator-paths', 'basic-cfg') @@ -148,7 +142,8 @@ module_logger.addHandler(hdlr=file_hdlr) # --------------------------------------------------------------------------------------------------- -def get_config(file_path: str = None, logger: logging.Logger = module_logger, load_basic_files: bool = None, load_denoted_files: bool = None): +def get_config(file_path: str = None, logger: logging.Logger = module_logger, load_basic_files: bool = None, + load_denoted_files: bool = None, check_interpolation: bool = True): """ Two use cases: @@ -162,6 +157,7 @@ def get_config(file_path: str = None, logger: logging.Logger = module_logger, lo :param logging.Logger logger: Logger passed as function argument :param bool load_basic_files: can be used to force to load the basic configuration files (confignator.cfg, egse.cfg) :param bool load_denoted_files: can be used to force to load the files listed in the section for config-files + :param bool check_interpolation: toggle checking of correct value interpolation :return: the parsed configuration :rtype: configparser.Config """ @@ -179,7 +175,8 @@ def get_config(file_path: str = None, logger: logging.Logger = module_logger, lo load_denoted = load_denoted_files try: - config = Config(file_path=file_path, logger=logger, load_basic_files=load_basic, load_denoted_files=load_denoted) + config = Config(file_path=file_path, logger=logger, load_basic_files=load_basic, load_denoted_files=load_denoted, + check_interpolation=check_interpolation) except Exception as exception: config = None logger.error('could not read the configuration file: {}'.format(file_path)) @@ -199,7 +196,7 @@ def get_option(section: str, option: str, logger: logging.Logger = module_logger :rtype: str """ try: - config = get_config(logger=logger) + config = get_config(logger=logger, check_interpolation=False) return config.get(section, option) except KeyError: logger.error('Confguration has no section {}'.format(section)) @@ -264,7 +261,8 @@ def save_option(section: str, option: str, value: str, logger: logging.Logger = class Config(configparser.ConfigParser): - def __init__(self, file_path, logger=module_logger, load_basic_files=True, load_denoted_files=True, *args, **kwargs): + def __init__(self, file_path, logger=module_logger, load_basic_files=True, load_denoted_files=True, + check_interpolation=True, *args, **kwargs): """ Init function of the derived ConfigParser class. If a file_path is provided, all configuration files are loaded. Does one or more of these files have a section 'config-files' all listed files are loaded too. @@ -297,7 +295,8 @@ class Config(configparser.ConfigParser): self.load_config_files_section() # test all interpolations in the values - self.test_all_options() + if check_interpolation: + self.test_all_options() @property def load_denoted_files(self): @@ -371,12 +370,12 @@ class Config(configparser.ConfigParser): self.get(s, o) except configparser.InterpolationError: if ignore_failures is False: - self.logger.info('failed interpolation of the option [{}][{}]'.format(s, o)) + self.logger.debug('failed interpolation of the option [{}][{}]'.format(s, o)) failed = True if failed is True: - self.logger.info('interpolation of options FAILED') + self.logger.warning('interpolation of options FAILED') if failed is False: - self.logger.info('interpolation of options was SUCCESSFUL') + self.logger.debug('interpolation of options was SUCCESSFUL') return failed def set_parameter(self, section, option, value): @@ -417,30 +416,51 @@ class Config(configparser.ConfigParser): :param str value: value which should be saved """ # find the file where the option is from - occourances = [] + occurrence = [] for file in self.files: - cfg = get_config(file_path=file, load_basic_files=False, load_denoted_files=False) - found = cfg.has_option(section=section, option=option) + tempcfg = get_config(file_path=file, load_basic_files=False, load_denoted_files=False, check_interpolation=False) + found = tempcfg.has_option(section=section, option=option) if found is True: - occourances.append(file) - if len(occourances) == 0: + occurrence.append(file) + if len(occurrence) == 0: self.logger.warning('No configuration files with the entry [{}[{}] found'.format(section, option)) # ToDo: should it be saved as a new section & option? In which file? self.logger.critical('# ToDo: should it be saved as a new section & option?') - elif len(occourances) > 1: - self.logger.error('Found the entry [{}][{}] in more than one configuration file. Saving not possible. Occourances in: {}'.format(section, option, occourances)) - elif len(occourances) == 1: + elif len(occurrence) > 1: + self.logger.error('Found the entry [{}][{}] in more than one configuration file. Saving not possible. Occurrences in: {}'.format(section, option, occurrence)) + elif len(occurrence) == 1: # load the config (only the specified file, no other) - cfg = get_config(file_path=occourances[0], load_basic_files=False, load_denoted_files=False) + tempcfg = get_config(file_path=occurrence[0], load_basic_files=False, load_denoted_files=False, check_interpolation=False) # set the option - cfg.set(section=section, option=option, value=value) + tempcfg.set(section=section, option=option, value=value) # check if this entry has valid interpolations - try: - get_option(section=section, option=option) # here the merged default config is used - except configparser.InterpolationError: - self.logger.error('The interpolation of the option [{}][{}] with the value [{}] failed.'.format(section, option, value)) + # try: + # get_option(section=section, option=option) # here the merged default config is used + # except configparser.InterpolationError: + # self.logger.error('The interpolation of the option [{}][{}] with the value [{}] failed.'.format(section, option, value)) # save the config - cfg.save_to_file() + tempcfg.save_to_file() + self.reload_config_files() + + def remove_option_from_file(self, section: str, option: str): + # find the file where the option is from + occurrence = [] + for file in self.files: + tempcfg = get_config(file_path=file, load_basic_files=False, load_denoted_files=False, + check_interpolation=False) + found = tempcfg.has_option(section=section, option=option) + if found is True: + occurrence.append(file) + if len(occurrence) == 0: + self.logger.warning('No configuration files with the entry [{}[{}] found'.format(section, option)) + else: + if len(occurrence) > 1: + self.logger.warning('Found the entry [{}][{}] in more than one configuration file: {}'.format(section, option, occurrence)) + for occ in occurrence: + tempcfg = get_config(file_path=occ, load_basic_files=False, load_denoted_files=False, check_interpolation=False) + tempcfg.remove_option(section, option) + tempcfg.save_to_file() + self.reload_config_files() def save_to_file(self, file_path: str = None) -> str: """ @@ -465,8 +485,9 @@ class Config(configparser.ConfigParser): for k in self.files: configfile.write('# {}\n'.format(k)) configfile.write('\n') + self.logger.info('A merged config was written to {}.'.format(file_path)) self.write(configfile) - self.logger.debug('successful saved the configuration in the file {}'.format(file_path)) + self.logger.debug('Successfully saved the configuration in the file {}'.format(file_path)) return file_path -- GitLab