config: code cleaning

This commit is contained in:
Benjamin Renard 2023-01-06 18:16:46 +01:00
parent 7efacf04e4
commit 55782df47c

View file

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# pylint: disable=too-many-lines
""" Configuration & options parser """ """ Configuration & options parser """
@ -136,14 +137,17 @@ class BaseOption: # pylint: disable=too-many-instance-attributes
@property @property
def parser_dest(self): def parser_dest(self):
""" Get option name in arguments parser options """ """ Get option name in arguments parser options """
return '{0}_{1}'.format(self.section.name, self.name) return f'{self.section.name}_{self.name}'
@property @property
def parser_help(self): def parser_help(self):
""" Get option help message in arguments parser options """ """ Get option help message in arguments parser options """
if self.arg_help and self.default is not None: if self.arg_help and self.default is not None:
# pylint: disable=consider-using-f-string
return '{0} (Default: {1})'.format( return '{0} (Default: {1})'.format(
self.arg_help, re.sub(r'%([^%])', r'%%\1', str(self.default))) self.arg_help,
re.sub(r'%([^%])', r'%%\1', str(self._default_in_config))
)
if self.arg_help: if self.arg_help:
return self.arg_help return self.arg_help
return None return None
@ -153,9 +157,7 @@ class BaseOption: # pylint: disable=too-many-instance-attributes
""" Get option argument name in parser options """ """ Get option argument name in parser options """
return ( return (
self.arg if self.arg else self.arg if self.arg else
'--{0}-{1}'.format( f'--{self.section.name}-{self.name}'.lower().replace('_', '-')
self.section.name, self.name
).lower().replace('_', '-')
) )
def add_option_to_parser(self, section_opts): def add_option_to_parser(self, section_opts):
@ -292,6 +294,7 @@ class BooleanOption(BaseOption):
@property @property
def parser_argument_name(self): def parser_argument_name(self):
""" Get option argument name in parser options """ """ Get option argument name in parser options """
# pylint: disable=consider-using-f-string
return ( return (
self.arg if self.arg else self.arg if self.arg else
'--{0}-{1}-{2}'.format( '--{0}-{1}-{2}'.format(
@ -304,7 +307,7 @@ class BooleanOption(BaseOption):
def _ask_value(self, prompt=None, **kwargs): def _ask_value(self, prompt=None, **kwargs):
""" Ask to user to enter value of this option and return it """ """ Ask to user to enter value of this option and return it """
default_value = self.get() default_value = self.get()
prompt = "%s: " % self.name prompt = f'{self.name}: '
if default_value: if default_value:
prompt += '[Y/n] ' prompt += '[Y/n] '
else: else:
@ -413,12 +416,11 @@ class PasswordOption(StringOption):
value = keyring.get_password(service_name, username) value = keyring.get_password(service_name, username)
if value is None: if value is None:
# pylint: disable=consider-using-f-string
value = getpass( value = getpass(
'Please enter %s%s: ' % ( 'Please enter {0}{1}: '.format(
self.comment if self.comment else f'{self.section.name} {self.name}',
'%s %s' % (self.section.name, self.name), f' for {username}' if username != self.name else ''
(' for %s' % username)
if username != self.name else ''
) )
) )
keyring.set_password(service_name, username, value) keyring.set_password(service_name, username, value)
@ -445,11 +447,11 @@ class PasswordOption(StringOption):
print('# ' + self.comment) print('# ' + self.comment)
default_value = kwargs.pop('default_value', self.get()) default_value = kwargs.pop('default_value', self.get())
if not prompt: if not prompt:
prompt = '%s: ' % self.name prompt = f'{self.name}: '
if default_value is not None: if default_value is not None:
# Hide value only if it differed from default value # Hide value only if it differed from default value
if default_value == self.default: if default_value == self.default:
prompt += '[%s] ' % default_value prompt += f'[{default_value}] '
else: else:
prompt += '[secret defined, leave to empty to keep it as unchange] ' prompt += '[secret defined, leave to empty to keep it as unchange] '
value = getpass(prompt) value = getpass(prompt)
@ -466,8 +468,8 @@ class PasswordOption(StringOption):
default_use_keyring = (super().get() == self.keyring_value) default_use_keyring = (super().get() == self.keyring_value)
while use_keyring is None: while use_keyring is None:
prompt = ( prompt = (
'Do you want to use XDG keyring ? [%s] ' % 'Do you want to use XDG keyring ? '
('Y/n' if default_use_keyring else 'y/N') f"[{'Y/n' if default_use_keyring else 'y/N'}] "
) )
result = input(prompt).lower() result = input(prompt).lower()
if result == '': if result == '':
@ -488,7 +490,7 @@ class ConfigSection:
def __init__(self, config, name, comment=None, order=None): def __init__(self, config, name, comment=None, order=None):
self.config = config self.config = config
self.name = name self.name = name
self.options = dict() self.options = {}
self.comment = comment self.comment = comment
self.order = order if isinstance(order, int) else 10 self.order = order if isinstance(order, int) else 10
@ -500,7 +502,7 @@ class ConfigSection:
:param name: Option name :param name: Option name
:param **kwargs: Dict of raw option for type class :param **kwargs: Dict of raw option for type class
""" """
assert not self.defined(name), "Duplicated option %s" % name assert not self.defined(name), f'Duplicated option {name}'
self.options[name] = _type(self.config, self, name, **kwargs) self.options[name] = _type(self.config, self, name, **kwargs)
return self.options[name] return self.options[name]
@ -514,12 +516,12 @@ class ConfigSection:
def get(self, option): def get(self, option):
""" Get option value """ """ Get option value """
assert self.defined(option), "Option %s unknown" % option assert self.defined(option), f'Option {option} unknown'
return self.options[option].get() return self.options[option].get()
def set(self, option, value): def set(self, option, value):
""" Set option value """ """ Set option value """
assert self.defined(option), "Option %s unknown" % option assert self.defined(option), f'Option {option} unknown'
return self.options[option].set(value) return self.options[option].set(value)
def add_options_to_parser(self, parser): def add_options_to_parser(self, parser):
@ -530,16 +532,16 @@ class ConfigSection:
else self.name.capitalize() else self.name.capitalize()
) )
for option in self.options: for option in self.options: # pylint: disable=consider-using-dict-items
self.options[option].add_option_to_parser(section_opts) self.options[option].add_option_to_parser(section_opts)
def export_to_config(self): def export_to_config(self):
""" Export section and their options to configuration file """ """ Export section and their options to configuration file """
lines = [] lines = []
if self.comment: if self.comment:
lines.append('# %s' % self.comment) lines.append(f'# {self.comment}')
lines.append('[%s]' % self.name) lines.append(f'[{self.name}]')
for option in self.options: for option in self.options: # pylint: disable=consider-using-dict-items
lines.append(self.options[option].export_to_config()) lines.append(self.options[option].export_to_config())
return '\n'.join(lines) return '\n'.join(lines)
@ -555,9 +557,9 @@ class ConfigSection:
:rtype: bool of dict :rtype: bool of dict
""" """
if self.comment: if self.comment:
print('# %s' % self.comment) print(f'# {self.comment}')
print('[%s]\n' % self.name) print(f'[{self.name}]''\n')
result = dict() result = {}
error = False error = False
for name, option in self.options.items(): for name, option in self.options.items():
option_result = option.ask_value(set_it=set_it) option_result = option.ask_value(set_it=set_it)
@ -622,7 +624,7 @@ class Config: # pylint: disable=too-many-instance-attributes
The specified callback method will receive Config object as parameter. The specified callback method will receive Config object as parameter.
: param ** kwargs: Raw parameters dict pass to ConfigSection __init__() method : param ** kwargs: Raw parameters dict pass to ConfigSection __init__() method
""" """
assert name not in self.sections, "Duplicated section %s" % name assert name not in self.sections, f'Duplicated section {name}'
self.sections[name] = ConfigSection(self, name, **kwargs) self.sections[name] = ConfigSection(self, name, **kwargs)
if loaded_callback: if loaded_callback:
@ -644,7 +646,7 @@ class Config: # pylint: disable=too-many-instance-attributes
""" Get option value """ """ Get option value """
assert self.config_parser or self.options, 'Unconfigured options parser' assert self.config_parser or self.options, 'Unconfigured options parser'
assert self.defined( assert self.defined(
section, option), 'Unknown option %s.%s' % (section, option) section, option), f'Unknown option {section}.{option}'
value = self.sections[section].get(option) value = self.sections[section].get(option)
log.debug('get(%s, %s): %s (%s)', section, option, value, type(value)) log.debug('get(%s, %s): %s (%s)', section, option, value, type(value))
return value return value
@ -664,7 +666,7 @@ class Config: # pylint: disable=too-many-instance-attributes
""" Set option value """ """ Set option value """
assert self.config_parser, 'Unconfigured options parser' assert self.config_parser, 'Unconfigured options parser'
assert self.defined( assert self.defined(
section, option), 'Unknown option %s.%s' % (section, option) section, option), f'Unknown option {section}.{option}'
self.sections[section].set(option, value) self.sections[section].set(option, value)
def load_file(self, filepath, execute_callback=True): def load_file(self, filepath, execute_callback=True):
@ -734,7 +736,11 @@ class Config: # pylint: disable=too-many-instance-attributes
'Configuration directory "%s" does not exist (or not writable)', dirpath) 'Configuration directory "%s" does not exist (or not writable)', dirpath)
return False return False
lines = ['#\n# %s configuration\n#\n' % self.appname] lines = [
'#\n'
f'# {self.appname} configuration'
'\n#\n'
]
for section_name in self._ordered_section_names: for section_name in self._ordered_section_names:
lines.append('') lines.append('')
@ -769,9 +775,15 @@ class Config: # pylint: disable=too-many-instance-attributes
formatter_class=RawWrappedTextHelpFormatter, formatter_class=RawWrappedTextHelpFormatter,
**kwargs) **kwargs)
config_file_help = 'Configuration file to use (default: %s)' % self.config_filepath config_file_help = (
f'Configuration file to use (default: {self.config_filepath})'
)
if self.config_file_env_variable: if self.config_file_env_variable:
config_file_help += '\n\nYou also could set %s environment variable to specify your configuration file path.' % self.config_file_env_variable config_file_help += (
'\n\nYou also could set '
f'{self.config_file_env_variable} environment variable to '
'specify your configuration file path.'
)
self.options_parser.add_argument( self.options_parser.add_argument(
'-c', '-c',
'--config', '--config',
@ -854,7 +866,7 @@ class Config: # pylint: disable=too-many-instance-attributes
# Load configuration file # Load configuration file
if os.path.isfile(options.config) and not self.load_file(options.config, execute_callback=False): if os.path.isfile(options.config) and not self.load_file(options.config, execute_callback=False):
parser.error( parser.error(
'Failed to load configuration from file %s' % options.config f'Failed to load configuration from file {options.config}'
) )
if options.save and not already_saved: if options.save and not already_saved:
@ -907,7 +919,7 @@ class Config: # pylint: disable=too-many-instance-attributes
# On set it mode, ensure configuration file parser is initialized # On set it mode, ensure configuration file parser is initialized
if set_it and not self.config_parser: if set_it and not self.config_parser:
self.config_parser = ConfigParser() self.config_parser = ConfigParser()
result = dict() result = {}
error = False error = False
for name, section in self.sections.items(): for name, section in self.sections.items():
section_result = section.ask_values(set_it=set_it) section_result = section.ask_values(set_it=set_it)
@ -960,14 +972,14 @@ class Config: # pylint: disable=too-many-instance-attributes
argv, create=False, execute_callback=False) argv, create=False, execute_callback=False)
if os.path.exists(options.config) and not options.overwrite: if os.path.exists(options.config) and not options.overwrite:
print('Configuration file %s already exists' % options.config) print(f'Configuration file {options.config} already exists')
sys.exit(1) sys.exit(1)
if options.interactive: if options.interactive:
self.ask_values(set_it=True) self.ask_values(set_it=True)
if self.save(options.config): if self.save(options.config):
print('Configuration file %s created.' % options.config) print(f'Configuration file {options.config} created.')
if options.validate: if options.validate:
print('Validate your configuration...') print('Validate your configuration...')
try: try:
@ -976,14 +988,15 @@ class Config: # pylint: disable=too-many-instance-attributes
else: else:
print('Error(s) occurred validating your configuration. See logs for details.') print('Error(s) occurred validating your configuration. See logs for details.')
sys.exit(1) sys.exit(1)
except Exception: except Exception: # pylint: disable=broad-except
print( print(
'Exception occurred validating your configuration: %s\n\nSee logs for details.' % 'Exception occurred validating your configuration:\n'
traceback.format_exc()) f'{traceback.format_exc()}'
'\n\nSee logs for details.'
)
sys.exit(2) sys.exit(2)
else: else:
print('Error occured creating configuration file %s' % print(f'Error occured creating configuration file {options.config}')
options.config)
sys.exit(1) sys.exit(1)
sys.exit(0) sys.exit(0)
@ -1006,8 +1019,8 @@ class Config: # pylint: disable=too-many-instance-attributes
return os.environ.get(self.config_file_env_variable) return os.environ.get(self.config_file_env_variable)
return os.path.join( return os.path.join(
self.config_dir, self.config_dir,
("%s.ini" % self.shortname) if self.shortname f'{self.shortname}.ini' if self.shortname
else "config.ini" else 'config.ini'
) )
@ -1044,7 +1057,7 @@ class ConfigurableObject:
**kwargs): **kwargs):
for key, value in kwargs.items(): for key, value in kwargs.items():
assert key in self._defaults, "Unknown %s option" % key assert key in self._defaults, f'Unknown {key} option'
self._kwargs[key] = value self._kwargs[key] = value
if options: if options:
@ -1054,7 +1067,7 @@ class ConfigurableObject:
elif self._config_name: elif self._config_name:
self._options_prefix = self._config_name + '_' self._options_prefix = self._config_name + '_'
else: else:
raise Exception('No configuration name defined for %s' % __name__) raise Exception(f'No configuration name defined for {__name__}')
if config: if config:
self._config = config self._config = config
@ -1063,7 +1076,7 @@ class ConfigurableObject:
elif self._config_name: elif self._config_name:
self._config_section = self._config_name self._config_section = self._config_name
else: else:
raise Exception('No configuration name defined for %s' % __name__) raise Exception(f'No configuration name defined for {__name__}')
def _get_option(self, option, default=None, required=False): def _get_option(self, option, default=None, required=False):
""" Retreive option value """ """ Retreive option value """
@ -1076,7 +1089,7 @@ class ConfigurableObject:
if self._config and self._config.defined(self._config_section, option): if self._config and self._config.defined(self._config_section, option):
return self._config.get(self._config_section, option) return self._config.get(self._config_section, option)
assert not required, "Options %s not defined" % option assert not required, f'Options {option} not defined'
return default if default is not None else self._defaults.get(option) return default if default is not None else self._defaults.get(option)