Compare commits

...

3 commits

Author SHA1 Message Date
Benjamin Renard
3a43b8d07d Config.parse_arguments_options(): add hardcoded_options argument
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-01-10 10:52:26 +01:00
Benjamin Renard
56162452ac config: if option value was previously set, ignore from options value 2023-01-10 10:50:48 +01:00
Benjamin Renard
5fefc1ed84 Config: make the configparser always defined to allow to set options at any moment 2023-01-10 10:48:57 +01:00

View file

@ -43,6 +43,7 @@ class BaseOption: # pylint: disable=too-many-instance-attributes
self.arg = arg self.arg = arg
self.short_arg = short_arg self.short_arg = short_arg
self.arg_help = arg_help if arg_help else comment self.arg_help = arg_help if arg_help else comment
self._set = False
@property @property
def _isset_in_options(self): def _isset_in_options(self):
@ -70,7 +71,7 @@ class BaseOption: # pylint: disable=too-many-instance-attributes
def _isset_in_config_file(self): def _isset_in_config_file(self):
""" Check if option is defined in the loaded configuration file """ """ Check if option is defined in the loaded configuration file """
return ( return (
self.config.config_parser self.config.config_filepath
and self.config.config_parser.has_option(self.section.name, self.name) and self.config.config_parser.has_option(self.section.name, self.name)
) )
@ -93,20 +94,17 @@ class BaseOption: # pylint: disable=too-many-instance-attributes
def get(self): def get(self):
""" Get option value from options, config or default """ """ Get option value from options, config or default """
if self._isset_in_options: if self._isset_in_options and not self._set:
return self._from_options return self._from_options
if self._isset_in_config_file: if self._isset_in_config_file:
return self._from_config return self._from_config
return self.default return self.default
def set(self, value): def set(self, value):
""" Set option value to config file """ """ Set option value to config file and options """
assert self.config.config_parser or (self.config.options and not self.no_arg), (
"Can't set option value: configuration file not configured, not options (or no argument)")
if value == '': if value == '':
value = None value = None
if self.config.config_parser:
if value == self.default or value is None: if value == self.default or value is None:
# Remove option from config (is section exists) # Remove option from config (is section exists)
if self.config.config_parser.has_section(self.section.name): if self.config.config_parser.has_section(self.section.name):
@ -121,8 +119,7 @@ class BaseOption: # pylint: disable=too-many-instance-attributes
self.section.name, self.name, self.to_config(value) self.section.name, self.name, self.to_config(value)
) )
if self.config.options and not self.no_arg: self._set = True
setattr(self.config.options, self.parser_dest, value)
@property @property
def parser_action(self): def parser_action(self):
@ -622,6 +619,7 @@ class Config: # pylint: disable=too-many-instance-attributes
self._filepath = None self._filepath = None
self.config_file_env_variable = config_file_env_variable self.config_file_env_variable = config_file_env_variable
self.default_config_dirpath = default_config_dirpath self.default_config_dirpath = default_config_dirpath
self._init_config_parser()
def add_section(self, name, loaded_callback=None, **kwargs): def add_section(self, name, loaded_callback=None, **kwargs):
""" """
@ -638,7 +636,7 @@ class Config: # pylint: disable=too-many-instance-attributes
if loaded_callback: if loaded_callback:
self._loaded_callbacks.append(loaded_callback) self._loaded_callbacks.append(loaded_callback)
# If configuration is already loaded, execute callback immediatly # If configuration is already loaded, execute callback immediatly
if self.config_parser or self.options: if self._filepath or self.options:
self._loaded() self._loaded()
return self.sections[name] return self.sections[name]
@ -652,7 +650,6 @@ class Config: # pylint: disable=too-many-instance-attributes
def get(self, section, option): def get(self, section, option):
""" Get option value """ """ Get option value """
assert self.config_parser or self.options, 'Unconfigured options parser'
assert self.defined( assert self.defined(
section, option), f'Unknown option {section}.{option}' section, option), f'Unknown option {section}.{option}'
value = self.sections[section].get(option) value = self.sections[section].get(option)
@ -666,21 +663,24 @@ class Config: # pylint: disable=too-many-instance-attributes
return default return default
def __getitem__(self, key): def __getitem__(self, key):
assert self.config_parser or self.options, 'Unconfigured options parser'
assert key in self.sections, f'Unknown section {key}' assert key in self.sections, f'Unknown section {key}'
return ConfigSectionAsDictWrapper(self.sections[key]) return ConfigSectionAsDictWrapper(self.sections[key])
def set(self, section, option, value): def set(self, section, option, value):
""" Set option value """ """ Set option value """
assert self.config_parser, 'Unconfigured options parser'
assert self.defined( assert self.defined(
section, option), f'Unknown option {section}.{option}' section, option), f'Unknown option {section}.{option}'
self._init_config_parser()
self.sections[section].set(option, value) self.sections[section].set(option, value)
def _init_config_parser(self, force=False):
""" Initialize ConfigParser object """
if not self.config_parser or force:
self.config_parser = ConfigParser(defaults={'hash': '#'})
def load_file(self, filepath, execute_callback=True): def load_file(self, filepath, execute_callback=True):
""" Read configuration file """ """ Read configuration file """
self._init_config_parser(force=True)
self.config_parser = ConfigParser(defaults={'hash': '#'})
self._filepath = filepath self._filepath = filepath
# Checking access of configuration file # Checking access of configuration file
@ -693,7 +693,7 @@ class Config: # pylint: disable=too-many-instance-attributes
try: try:
self.config_parser.read(filepath, encoding=self.encoding) self.config_parser.read(filepath, encoding=self.encoding)
except Exception: # pylint: disable=broad-except except Exception: # pylint: disable=broad-except
self.config_parser = None self._init_config_parser(force=True)
log.exception('Failed to read configuration file %s', filepath) log.exception('Failed to read configuration file %s', filepath)
return False return False
@ -847,7 +847,8 @@ class Config: # pylint: disable=too-many-instance-attributes
return self.options_parser return self.options_parser
def parse_arguments_options(self, argv=None, parser=None, create=True, ask_values=True, def parse_arguments_options(self, argv=None, parser=None, create=True, ask_values=True,
exit_after_created=True, execute_callback=True): exit_after_created=True, execute_callback=True,
hardcoded_options=None):
""" """
Parse arguments options Parse arguments options
@ -862,6 +863,11 @@ class Config: # pylint: disable=too-many-instance-attributes
creation (default: True) creation (default: True)
:param execute_callback: Sections's loaded callbacks will be executed only if True :param execute_callback: Sections's loaded callbacks will be executed only if True
(default: True) (default: True)
:param hardcoded_options: Optional hard-coded options to set after loading arguments
and configuration file. These options are passed using an
list of tuple of 3 elements: the section and the option
names and the value.
[('section1', 'option1', value), ...]
""" """
parser = parser if parser else self.get_arguments_parser() parser = parser if parser else self.get_arguments_parser()
argcomplete.autocomplete(parser) argcomplete.autocomplete(parser)
@ -899,6 +905,17 @@ class Config: # pylint: disable=too-many-instance-attributes
elif options.verbose: elif options.verbose:
logging.getLogger().setLevel(logging.INFO) logging.getLogger().setLevel(logging.INFO)
if hardcoded_options:
assert isinstance(hardcoded_options, list), (
'hardcoded_options must be a list of tuple of 3 elements: '
'the section and the option names and the value.')
for opt_info in hardcoded_options:
assert isinstance(opt_info, tuple) and len(opt_info) == 3, (
'Invalid hard-coded option value: it must be a tuple of 3 '
'elements: the section and the option names and the value.'
)
self.set(*opt_info)
if self.get('console', 'enabled'): if self.get('console', 'enabled'):
stdout_console_handler = logging.StreamHandler( stdout_console_handler = logging.StreamHandler(
sys.stderr if self.get('console', 'force_stderr') sys.stderr if self.get('console', 'force_stderr')
@ -953,9 +970,6 @@ class Config: # pylint: disable=too-many-instance-attributes
section and their options value. section and their options value.
:rtype: bool of dict :rtype: bool of dict
""" """
# On set it mode, ensure configuration file parser is initialized
if set_it and not self.config_parser:
self.config_parser = ConfigParser()
result = {} result = {}
error = False error = False
for name, section in self.sections.items(): for name, section in self.sections.items():