fix: better permissive support
This commit is contained in:
parent
7761758096
commit
7ae1b48f4a
3 changed files with 179 additions and 123 deletions
|
@ -21,7 +21,7 @@ from functools import wraps
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
|
|
||||||
|
|
||||||
from .error import ConfigError, LeadershipError, ValueErrorWarning
|
from .error import ConfigError, LeadershipError, ValueErrorWarning, PropertiesOptionError
|
||||||
from .i18n import _
|
from .i18n import _
|
||||||
from .setting import ConfigBag, owners, groups, undefined, \
|
from .setting import ConfigBag, owners, groups, undefined, \
|
||||||
FORBIDDEN_SET_PROPERTIES, SPECIAL_PROPERTIES, \
|
FORBIDDEN_SET_PROPERTIES, SPECIAL_PROPERTIES, \
|
||||||
|
@ -92,12 +92,13 @@ class CommonTiramisu(TiramisuHelp):
|
||||||
_allow_dynoption = False
|
_allow_dynoption = False
|
||||||
|
|
||||||
def _set_subconfig(self) -> None:
|
def _set_subconfig(self) -> None:
|
||||||
self._subconfig = self._config_bag.context.get_sub_config(self._config_bag,
|
if not self._subconfig:
|
||||||
self._path,
|
self._subconfig = self._config_bag.context.get_sub_config(self._config_bag,
|
||||||
self._index,
|
self._path,
|
||||||
validate_properties=False,
|
self._index,
|
||||||
allow_dynoption=self._allow_dynoption,
|
validate_properties=False,
|
||||||
)
|
allow_dynoption=self._allow_dynoption,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def option_type(typ):
|
def option_type(typ):
|
||||||
|
@ -119,6 +120,7 @@ def option_type(typ):
|
||||||
)]
|
)]
|
||||||
kwargs['is_group'] = True
|
kwargs['is_group'] = True
|
||||||
return func(self, options_bag, *args[1:], **kwargs)
|
return func(self, options_bag, *args[1:], **kwargs)
|
||||||
|
self._set_subconfig()
|
||||||
option = self._subconfig.option
|
option = self._subconfig.option
|
||||||
error_type = None
|
error_type = None
|
||||||
if 'dynamic' in types:
|
if 'dynamic' in types:
|
||||||
|
@ -194,6 +196,7 @@ class CommonTiramisuOption(CommonTiramisu):
|
||||||
self._path = path
|
self._path = path
|
||||||
self._index = index
|
self._index = index
|
||||||
self._config_bag = config_bag
|
self._config_bag = config_bag
|
||||||
|
self._subconfig = None
|
||||||
self._set_subconfig()
|
self._set_subconfig()
|
||||||
|
|
||||||
|
|
||||||
|
@ -292,6 +295,11 @@ class _TiramisuOptionOptionDescription:
|
||||||
return 'optiondescription'
|
return 'optiondescription'
|
||||||
return option.get_type()
|
return option.get_type()
|
||||||
|
|
||||||
|
@option_type(['option', 'symlink', 'with_or_without_index'])
|
||||||
|
def extra(self, extra):
|
||||||
|
"""Get de option extra"""
|
||||||
|
return self._subconfig.option.impl_get_extra(extra)
|
||||||
|
|
||||||
@option_type(['option', 'optiondescription', 'symlink', 'with_or_without_index'])
|
@option_type(['option', 'optiondescription', 'symlink', 'with_or_without_index'])
|
||||||
def isdynamic(self,
|
def isdynamic(self,
|
||||||
*,
|
*,
|
||||||
|
@ -342,19 +350,19 @@ class _TiramisuOptionOptionDescription:
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
@option_type(['dynamic', 'with_or_without_index'])
|
@option_type(['dynamic', 'with_or_without_index'])
|
||||||
def suffixes(self,
|
def identifiers(self,
|
||||||
only_self: bool=False,
|
only_self: bool=False,
|
||||||
uncalculated: bool=False,
|
uncalculated: bool=False,
|
||||||
):
|
):
|
||||||
"""Get suffixes for dynamic option"""
|
"""Get identifiers for dynamic option"""
|
||||||
if not only_self:
|
if not only_self:
|
||||||
return self._subconfig.suffixes
|
return self._subconfig.identifiers
|
||||||
if not self._subconfig.option.impl_is_optiondescription() or \
|
if not self._subconfig.option.impl_is_optiondescription() or \
|
||||||
not self._subconfig.option.impl_is_dynoptiondescription():
|
not self._subconfig.option.impl_is_dynoptiondescription():
|
||||||
raise ConfigError(_(f'the option {self._subconfig.path} is not a dynamic option, cannot get suffixes with only_self parameter to True'))
|
raise ConfigError(_(f'the option {self._subconfig.path} is not a dynamic option, cannot get identifiers with only_self parameter to True'))
|
||||||
return self._subconfig.option.get_suffixes(self._subconfig.parent,
|
return self._subconfig.option.get_identifiers(self._subconfig.parent,
|
||||||
uncalculated=uncalculated,
|
uncalculated=uncalculated,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class _TiramisuOptionOption(_TiramisuOptionOptionDescription):
|
class _TiramisuOptionOption(_TiramisuOptionOptionDescription):
|
||||||
|
@ -571,6 +579,7 @@ class TiramisuOptionPermissive(CommonTiramisuOption):
|
||||||
class TiramisuOptionInformation(CommonTiramisuOption):
|
class TiramisuOptionInformation(CommonTiramisuOption):
|
||||||
"""Manage option's informations"""
|
"""Manage option's informations"""
|
||||||
_validate_properties = False
|
_validate_properties = False
|
||||||
|
_allow_dynoption = True
|
||||||
|
|
||||||
@option_type(['option', 'optiondescription', 'with_or_without_index', 'symlink'])
|
@option_type(['option', 'optiondescription', 'with_or_without_index', 'symlink'])
|
||||||
def get(self,
|
def get(self,
|
||||||
|
@ -670,8 +679,8 @@ class TiramisuOptionValue(CommonTiramisuOption, _TiramisuODGet):
|
||||||
option = self._subconfig.option
|
option = self._subconfig.option
|
||||||
if not isinstance(value, Calculation) and option.impl_is_leader() and \
|
if not isinstance(value, Calculation) and option.impl_is_leader() and \
|
||||||
len(value) < self._subconfig.parent.get_length_leadership():
|
len(value) < self._subconfig.parent.get_length_leadership():
|
||||||
raise LeadershipError(_('cannot reduce length of the leader "{}"'
|
raise LeadershipError(_('cannot reduce length of the leader {}'
|
||||||
'').format(option.impl_get_display_name(self._subconfig)))
|
'').format(option.impl_get_display_name(self._subconfig, with_quote=True)))
|
||||||
values = self._config_bag.context.get_values()
|
values = self._config_bag.context.get_values()
|
||||||
return values.set_value(self._subconfig,
|
return values.set_value(self._subconfig,
|
||||||
value
|
value
|
||||||
|
@ -753,6 +762,32 @@ class TiramisuOptionValue(CommonTiramisuOption, _TiramisuODGet):
|
||||||
"""Length for a leadership"""
|
"""Length for a leadership"""
|
||||||
return self._subconfig.parent.get_length_leadership()
|
return self._subconfig.parent.get_length_leadership()
|
||||||
|
|
||||||
|
def mandatory(self):
|
||||||
|
"""Return path of options with mandatory property without any value"""
|
||||||
|
subconfig = self._subconfig
|
||||||
|
if subconfig.option.impl_is_optiondescription():
|
||||||
|
ori_config_bag = self._subconfig.config_bag
|
||||||
|
config_bag = ori_config_bag.copy()
|
||||||
|
config_bag.properties -= {'mandatory', 'empty', 'warnings'}
|
||||||
|
config_bag.set_permissive()
|
||||||
|
self._subconfig.config_bag = config_bag
|
||||||
|
options = []
|
||||||
|
for subconfig in self._config_bag.context.walk(self._subconfig,
|
||||||
|
only_mandatory=True,
|
||||||
|
):
|
||||||
|
options.append(TiramisuOption(subconfig.path,
|
||||||
|
subconfig.index,
|
||||||
|
ori_config_bag,
|
||||||
|
subconfig=subconfig,
|
||||||
|
))
|
||||||
|
self._subconfig.config_bag = ori_config_bag
|
||||||
|
return options
|
||||||
|
try:
|
||||||
|
self._config_bag.context.walk_valid_value(self._subconfig, only_mandatory=True)
|
||||||
|
except PropertiesOptionError as err:
|
||||||
|
return err.proptype == ['mandatory'] or err.proptype == ['empty']
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def _registers(_registers: Dict[str, type],
|
def _registers(_registers: Dict[str, type],
|
||||||
prefix: str,
|
prefix: str,
|
||||||
|
@ -808,10 +843,7 @@ class TiramisuOption(CommonTiramisu,
|
||||||
self._index = index
|
self._index = index
|
||||||
self._config_bag = config_bag
|
self._config_bag = config_bag
|
||||||
self._allow_dynoption = allow_dynoption
|
self._allow_dynoption = allow_dynoption
|
||||||
if subconfig is None:
|
self._subconfig = subconfig
|
||||||
self._set_subconfig()
|
|
||||||
else:
|
|
||||||
self._subconfig = subconfig
|
|
||||||
if not self._registers:
|
if not self._registers:
|
||||||
_registers(self._registers, 'TiramisuOption')
|
_registers(self._registers, 'TiramisuOption')
|
||||||
|
|
||||||
|
@ -831,6 +863,7 @@ class TiramisuOption(CommonTiramisu,
|
||||||
raise ConfigError(_(f'please specify a valid sub function ({self.__class__.__name__}.{subfunc}) for {self._path}'))
|
raise ConfigError(_(f'please specify a valid sub function ({self.__class__.__name__}.{subfunc}) for {self._path}'))
|
||||||
#
|
#
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
|
self._set_subconfig()
|
||||||
for sub_subconfig in self._subconfig.get_children(True):
|
for sub_subconfig in self._subconfig.get_children(True):
|
||||||
yield TiramisuOption(sub_subconfig.path,
|
yield TiramisuOption(sub_subconfig.path,
|
||||||
sub_subconfig.index,
|
sub_subconfig.index,
|
||||||
|
@ -841,6 +874,7 @@ class TiramisuOption(CommonTiramisu,
|
||||||
@option_type('optiondescription')
|
@option_type('optiondescription')
|
||||||
def group_type(self):
|
def group_type(self):
|
||||||
"""Get type for an optiondescription (only for optiondescription)"""
|
"""Get type for an optiondescription (only for optiondescription)"""
|
||||||
|
self._set_subconfig()
|
||||||
return self._subconfig.option.impl_get_group_type()
|
return self._subconfig.option.impl_get_group_type()
|
||||||
|
|
||||||
@option_type('optiondescription')
|
@option_type('optiondescription')
|
||||||
|
@ -850,6 +884,7 @@ class TiramisuOption(CommonTiramisu,
|
||||||
uncalculated: bool=False,
|
uncalculated: bool=False,
|
||||||
):
|
):
|
||||||
"""List options inside an option description (by default list only option)"""
|
"""List options inside an option description (by default list only option)"""
|
||||||
|
self._set_subconfig()
|
||||||
return self._list(self._subconfig,
|
return self._list(self._subconfig,
|
||||||
validate_properties,
|
validate_properties,
|
||||||
uncalculated=uncalculated,
|
uncalculated=uncalculated,
|
||||||
|
@ -1335,12 +1370,15 @@ class TiramisuContextOption(TiramisuConfig, _TiramisuOptionWalk):
|
||||||
return 'optiondescription'
|
return 'optiondescription'
|
||||||
|
|
||||||
def list(self,
|
def list(self,
|
||||||
|
*,
|
||||||
validate_properties: bool=True,
|
validate_properties: bool=True,
|
||||||
|
uncalculated: bool=False,
|
||||||
):
|
):
|
||||||
"""List options (by default list only option)"""
|
"""List options (by default list only option)"""
|
||||||
root = self._config_bag.context.get_root(self._config_bag)
|
root = self._config_bag.context.get_root(self._config_bag)
|
||||||
return self._list(root,
|
return self._list(root,
|
||||||
validate_properties,
|
validate_properties,
|
||||||
|
uncalculated=uncalculated,
|
||||||
)
|
)
|
||||||
|
|
||||||
def _load_dict(self,
|
def _load_dict(self,
|
||||||
|
|
|
@ -115,12 +115,12 @@ class ParamOption(Param):
|
||||||
|
|
||||||
|
|
||||||
class ParamDynOption(ParamOption):
|
class ParamDynOption(ParamOption):
|
||||||
__slots__ = ('suffixes',
|
__slots__ = ('identifiers',
|
||||||
'optional',
|
'optional',
|
||||||
)
|
)
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
option: 'Option',
|
option: 'Option',
|
||||||
suffixes: list[str],
|
identifiers: list[str],
|
||||||
notraisepropertyerror: bool=False,
|
notraisepropertyerror: bool=False,
|
||||||
raisepropertyerror: bool=False,
|
raisepropertyerror: bool=False,
|
||||||
optional: bool=False,
|
optional: bool=False,
|
||||||
|
@ -129,7 +129,11 @@ class ParamDynOption(ParamOption):
|
||||||
notraisepropertyerror,
|
notraisepropertyerror,
|
||||||
raisepropertyerror,
|
raisepropertyerror,
|
||||||
)
|
)
|
||||||
self.suffixes = suffixes
|
if not isinstance(identifiers, list):
|
||||||
|
raise Exception(f'identifiers in ParamDynOption must be a list, not {identifiers}')
|
||||||
|
if not isinstance(optional, bool):
|
||||||
|
raise Exception(f'optional in ParamDynOption must be a boolean, not {optional}')
|
||||||
|
self.identifiers = identifiers
|
||||||
self.optional = optional
|
self.optional = optional
|
||||||
|
|
||||||
|
|
||||||
|
@ -212,12 +216,12 @@ class ParamIndex(Param):
|
||||||
__slots__ = tuple()
|
__slots__ = tuple()
|
||||||
|
|
||||||
|
|
||||||
class ParamSuffix(Param):
|
class ParamIdentifier(Param):
|
||||||
__slots__ = ('suffix_index',)
|
__slots__ = ('identifier_index',)
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
suffix_index: int=-1,
|
identifier_index: int=-1,
|
||||||
) -> None:
|
) -> None:
|
||||||
self.suffix_index = suffix_index
|
self.identifier_index = identifier_index
|
||||||
|
|
||||||
|
|
||||||
class Calculation:
|
class Calculation:
|
||||||
|
@ -345,7 +349,7 @@ def manager_callback(callback: Callable,
|
||||||
properties=undefined,
|
properties=undefined,
|
||||||
):
|
):
|
||||||
option = subconfig.option
|
option = subconfig.option
|
||||||
if option.impl_is_follower() and apply_index is False:
|
if option.impl_is_follower() and (subconfig.index is None or apply_index is False):
|
||||||
value = []
|
value = []
|
||||||
for idx in range(subconfig.parent.get_length_leadership()):
|
for idx in range(subconfig.parent.get_length_leadership()):
|
||||||
subconfig = get_option_bag(config_bag,
|
subconfig = get_option_bag(config_bag,
|
||||||
|
@ -374,10 +378,11 @@ def manager_callback(callback: Callable,
|
||||||
# raise PropertiesOptionError (which is catched) because must not add value None in carry_out_calculation
|
# raise PropertiesOptionError (which is catched) because must not add value None in carry_out_calculation
|
||||||
if isinstance(param, ParamSelfOption) or param.notraisepropertyerror or param.raisepropertyerror:
|
if isinstance(param, ParamSelfOption) or param.notraisepropertyerror or param.raisepropertyerror:
|
||||||
raise err from err
|
raise err from err
|
||||||
raise ConfigError(_('unable to carry out a calculation for "{}", {}').format(display_name, err)) from err
|
display_name = subconfig.option.impl_get_display_name(subconfig, with_quote=True)
|
||||||
|
raise ConfigError(_('unable to carry out a calculation for {}, {}').format(display_name, err)) from err
|
||||||
except ValueError as err:
|
except ValueError as err:
|
||||||
display_name = subconfig.option.impl_get_display_name(subconfig)
|
display_name = subconfig.option.impl_get_display_name(subconfig, with_quote=True)
|
||||||
raise ValueError(_('the option "{0}" is used in a calculation but is invalid ({1})').format(display_name, err)) from err
|
raise ValueError(_('the option {0} is used in a calculation but is invalid ({1})').format(display_name, err)) from err
|
||||||
except AttributeError as err:
|
except AttributeError as err:
|
||||||
if isinstance(param, ParamDynOption) and param.optional:
|
if isinstance(param, ParamDynOption) and param.optional:
|
||||||
# cannot acces, simulate a propertyerror
|
# cannot acces, simulate a propertyerror
|
||||||
|
@ -385,8 +390,8 @@ def manager_callback(callback: Callable,
|
||||||
['configerror'],
|
['configerror'],
|
||||||
config_bag.context.get_settings(),
|
config_bag.context.get_settings(),
|
||||||
)
|
)
|
||||||
display_name = subconfig.option.impl_get_display_name(subconfig)
|
display_name = subconfig.option.impl_get_display_name(subconfig, with_quote=True)
|
||||||
raise ConfigError(_(f'unable to get value for calculating "{display_name}", {err}')) from err
|
raise ConfigError(_(f'unable to get value for calculating {display_name}, {err}')) from err
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def get_option_bag(config_bag,
|
def get_option_bag(config_bag,
|
||||||
|
@ -398,16 +403,13 @@ def manager_callback(callback: Callable,
|
||||||
properties=undefined,
|
properties=undefined,
|
||||||
):
|
):
|
||||||
# don't validate if option is option that we tried to validate
|
# don't validate if option is option that we tried to validate
|
||||||
config_bag = config_bag.copy()
|
|
||||||
if for_settings:
|
if for_settings:
|
||||||
config_bag.properties = config_bag.properties - {'warnings'}
|
config_bag.properties = config_bag.properties - {'warnings'}
|
||||||
config_bag.set_permissive()
|
|
||||||
if not for_settings:
|
if not for_settings:
|
||||||
config_bag.properties -= {'warnings'}
|
config_bag.properties -= {'warnings'}
|
||||||
if self_calc:
|
if self_calc:
|
||||||
config_bag.unrestraint()
|
config_bag.unrestraint()
|
||||||
config_bag.remove_validation()
|
config_bag.remove_validation()
|
||||||
# root = config_bag.context.get_root(config_bag)
|
|
||||||
try:
|
try:
|
||||||
subsubconfig = config_bag.context.get_sub_config(config_bag,
|
subsubconfig = config_bag.context.get_sub_config(config_bag,
|
||||||
opt.impl_getpath(),
|
opt.impl_getpath(),
|
||||||
|
@ -419,10 +421,11 @@ def manager_callback(callback: Callable,
|
||||||
# raise PropertiesOptionError (which is catched) because must not add value None in carry_out_calculation
|
# raise PropertiesOptionError (which is catched) because must not add value None in carry_out_calculation
|
||||||
if param.notraisepropertyerror or param.raisepropertyerror:
|
if param.notraisepropertyerror or param.raisepropertyerror:
|
||||||
raise err from err
|
raise err from err
|
||||||
display_name = option.impl_get_display_name(subconfig)
|
display_name = option.impl_get_display_name(subconfig, with_quote=True)
|
||||||
raise ConfigError(_('unable to carry out a calculation for "{}", {}').format(display_name, err)) from err
|
raise ConfigError(_('unable to carry out a calculation for {}, {}').format(display_name, err)) from err
|
||||||
except ValueError as err:
|
except ValueError as err:
|
||||||
raise ValueError(_('the option "{0}" is used in a calculation but is invalid ({1})').format(option.impl_get_display_name(subconfig), err)) from err
|
display_name = option.impl_get_display_name(subconfig, with_quote=True)
|
||||||
|
raise ValueError(_('the option {0} is used in a calculation but is invalid ({1})').format(display_name, err)) from err
|
||||||
except AttributeError as err:
|
except AttributeError as err:
|
||||||
if isinstance(param, ParamDynOption) and param.optional:
|
if isinstance(param, ParamDynOption) and param.optional:
|
||||||
# cannot acces, simulate a propertyerror
|
# cannot acces, simulate a propertyerror
|
||||||
|
@ -430,8 +433,8 @@ def manager_callback(callback: Callable,
|
||||||
['configerror'],
|
['configerror'],
|
||||||
config_bag.context.get_settings(),
|
config_bag.context.get_settings(),
|
||||||
)
|
)
|
||||||
display_name = option.impl_get_display_name(subconfig)
|
display_name = option.impl_get_display_name(subconfig, with_quote=True)
|
||||||
raise ConfigError(_(f'unable to get value for calculating "{display_name}", {err}')) from err
|
raise ConfigError(_(f'unable to get value for calculating {display_name}, {err}')) from err
|
||||||
return subsubconfig
|
return subsubconfig
|
||||||
|
|
||||||
if isinstance(param, ParamValue):
|
if isinstance(param, ParamValue):
|
||||||
|
@ -447,7 +450,9 @@ def manager_callback(callback: Callable,
|
||||||
true_path=subconfig.path,
|
true_path=subconfig.path,
|
||||||
)
|
)
|
||||||
if isinstance(isubconfig, list):
|
if isinstance(isubconfig, list):
|
||||||
raise ConfigError(f'cannot find information for "{option.impl_get_display_name(subconfig)}", "{search_option.impl_get_display_name(None)}" is a dynamic option')
|
display_name = option.impl_get_display_name(subconfig, with_quote=True)
|
||||||
|
search_name = search_option.impl_get_display_name(None, with_quote=True)
|
||||||
|
raise ConfigError(f'cannot find information for {display_name}, {search_name} is a dynamic option')
|
||||||
else:
|
else:
|
||||||
isubconfig = get_option_bag(config_bag,
|
isubconfig = get_option_bag(config_bag,
|
||||||
param.option,
|
param.option,
|
||||||
|
@ -464,17 +469,17 @@ def manager_callback(callback: Callable,
|
||||||
param.default_value,
|
param.default_value,
|
||||||
)
|
)
|
||||||
except ValueError as err:
|
except ValueError as err:
|
||||||
display_name = option.impl_get_display_name(subconfig)
|
display_name = option.impl_get_display_name(subconfig, with_quote=True)
|
||||||
raise ConfigError(_(f'unable to get value for calculating "{display_name}", {err}')) from err
|
raise ConfigError(_(f'unable to get value for calculating {display_name}, {err}')) from err
|
||||||
|
|
||||||
if isinstance(param, ParamIndex):
|
if isinstance(param, ParamIndex):
|
||||||
return index
|
return index
|
||||||
|
|
||||||
if isinstance(param, ParamSuffix):
|
if isinstance(param, ParamIdentifier):
|
||||||
if not option.issubdyn() and (not option.impl_is_optiondescription() or not option.impl_is_dynoptiondescription()):
|
if not option.issubdyn() and (not option.impl_is_optiondescription() or not option.impl_is_dynoptiondescription()):
|
||||||
display_name = subconfig.option.impl_get_display_name(subconfig)
|
display_name = subconfig.option.impl_get_display_name(subconfig, with_quote=True)
|
||||||
raise ConfigError(_(f'option "{display_name}" is not a dynoptiondescription or in a dynoptiondescription'))
|
raise ConfigError(_(f'option {display_name} is not a dynoptiondescription or in a dynoptiondescription'))
|
||||||
return subconfig.suffixes[param.suffix_index]
|
return subconfig.identifiers[param.identifier_index]
|
||||||
|
|
||||||
if isinstance(param, ParamSelfOption):
|
if isinstance(param, ParamSelfOption):
|
||||||
value = calc_self(param,
|
value = calc_self(param,
|
||||||
|
@ -490,7 +495,6 @@ def manager_callback(callback: Callable,
|
||||||
|
|
||||||
if isinstance(param, ParamOption):
|
if isinstance(param, ParamOption):
|
||||||
callbk_option = param.option
|
callbk_option = param.option
|
||||||
config_bag = subconfig.config_bag
|
|
||||||
if index is not None and callbk_option.impl_get_leadership() and \
|
if index is not None and callbk_option.impl_get_leadership() and \
|
||||||
callbk_option.impl_get_leadership().in_same_leadership(option):
|
callbk_option.impl_get_leadership().in_same_leadership(option):
|
||||||
if not callbk_option.impl_is_follower():
|
if not callbk_option.impl_is_follower():
|
||||||
|
@ -506,8 +510,7 @@ def manager_callback(callback: Callable,
|
||||||
with_index = False
|
with_index = False
|
||||||
if callbk_option.issubdyn():
|
if callbk_option.issubdyn():
|
||||||
if isinstance(param, ParamDynOption):
|
if isinstance(param, ParamDynOption):
|
||||||
#callbk_option = callbk_option.to_sub_dyoption(param.suffixes)
|
identifiers = param.identifiers.copy()
|
||||||
suffixes = param.suffixes.copy()
|
|
||||||
paths = callbk_option.impl_getpath().split('.')
|
paths = callbk_option.impl_getpath().split('.')
|
||||||
parents = [config_bag.context.get_root(config_bag)]
|
parents = [config_bag.context.get_root(config_bag)]
|
||||||
subconfigs_is_a_list = False
|
subconfigs_is_a_list = False
|
||||||
|
@ -520,9 +523,18 @@ def manager_callback(callback: Callable,
|
||||||
allow_dynoption=True,
|
allow_dynoption=True,
|
||||||
)
|
)
|
||||||
if doption.impl_is_dynoptiondescription():
|
if doption.impl_is_dynoptiondescription():
|
||||||
if suffixes:
|
if not identifiers:
|
||||||
suffix = suffixes.pop(0)
|
identifier = None
|
||||||
name = doption.impl_getname(suffix)
|
else:
|
||||||
|
identifier = identifiers.pop(0)
|
||||||
|
if not identifier:
|
||||||
|
subconfigs_is_a_list = True
|
||||||
|
new_parents.extend(parent.dyn_to_subconfig(doption,
|
||||||
|
True,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
name = doption.impl_getname(identifier)
|
||||||
try:
|
try:
|
||||||
doption = parent.option.get_child(name,
|
doption = parent.option.get_child(name,
|
||||||
config_bag,
|
config_bag,
|
||||||
|
@ -534,14 +546,8 @@ def manager_callback(callback: Callable,
|
||||||
None,
|
None,
|
||||||
True,
|
True,
|
||||||
name=name,
|
name=name,
|
||||||
suffix=suffix,
|
identifier=identifier,
|
||||||
))
|
))
|
||||||
else:
|
|
||||||
subconfigs_is_a_list = True
|
|
||||||
new_parents.extend(parent.dyn_to_subconfig(doption,
|
|
||||||
True,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
new_parents.append(parent.get_child(doption,
|
new_parents.append(parent.get_child(doption,
|
||||||
None,
|
None,
|
||||||
|
@ -625,11 +631,13 @@ def carry_out_calculation(subconfig: 'SubConfig',
|
||||||
Values could have multiple values only when key is ''."""
|
Values could have multiple values only when key is ''."""
|
||||||
option = subconfig.option
|
option = subconfig.option
|
||||||
if not option.impl_is_optiondescription() and option.impl_is_follower() and index is None:
|
if not option.impl_is_optiondescription() and option.impl_is_follower() and index is None:
|
||||||
raise ConfigError(f'the follower "{option.impl_get_display_name(subconfig)}" must have index in carry_out_calculation!')
|
raise ConfigError(f'the follower {option.impl_get_display_name(subconfig, with_quote=True)} must have index in carry_out_calculation!')
|
||||||
def fake_items(iterator):
|
def fake_items(iterator):
|
||||||
return ((None, i) for i in iterator)
|
return ((None, i) for i in iterator)
|
||||||
args = []
|
args = []
|
||||||
kwargs = {}
|
kwargs = {}
|
||||||
|
config_bag = config_bag.copy()
|
||||||
|
config_bag.set_permissive()
|
||||||
if callback_params:
|
if callback_params:
|
||||||
for key, param in chain(fake_items(callback_params.args), callback_params.kwargs.items()):
|
for key, param in chain(fake_items(callback_params.args), callback_params.kwargs.items()):
|
||||||
try:
|
try:
|
||||||
|
@ -667,18 +675,18 @@ def carry_out_calculation(subconfig: 'SubConfig',
|
||||||
if args or kwargs:
|
if args or kwargs:
|
||||||
raise LeadershipError(_('the "{}" function with positional arguments "{}" '
|
raise LeadershipError(_('the "{}" function with positional arguments "{}" '
|
||||||
'and keyword arguments "{}" must not return '
|
'and keyword arguments "{}" must not return '
|
||||||
'a list ("{}") for the follower option "{}"'
|
'a list ("{}") for the follower option {}'
|
||||||
'').format(callback.__name__,
|
'').format(callback.__name__,
|
||||||
args,
|
args,
|
||||||
kwargs,
|
kwargs,
|
||||||
ret,
|
ret,
|
||||||
option.impl_get_display_name(subconfig)))
|
option.impl_get_display_name(subconfig, with_quote=True)))
|
||||||
else:
|
else:
|
||||||
raise LeadershipError(_('the "{}" function must not return a list ("{}") '
|
raise LeadershipError(_('the "{}" function must not return a list ("{}") '
|
||||||
'for the follower option "{}"'
|
'for the follower option {}'
|
||||||
'').format(callback.__name__,
|
'').format(callback.__name__,
|
||||||
ret,
|
ret,
|
||||||
option.impl_get_display_name(subconfig)))
|
option.impl_get_display_name(subconfig, with_quote=True)))
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
|
@ -702,22 +710,22 @@ def calculate(subconfig,
|
||||||
if allow_value_error:
|
if allow_value_error:
|
||||||
if force_value_warning:
|
if force_value_warning:
|
||||||
raise ValueWarning(str(err))
|
raise ValueWarning(str(err))
|
||||||
raise err
|
raise err from err
|
||||||
error = err
|
error = err
|
||||||
|
except ConfigError as err:
|
||||||
|
raise err from err
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
import traceback
|
|
||||||
traceback.print_exc()
|
|
||||||
error = err
|
error = err
|
||||||
if args or kwargs:
|
if args or kwargs:
|
||||||
msg = _('unexpected error "{0}" in function "{1}" with arguments "{3}" and "{4}" '
|
msg = _('unexpected error "{0}" in function "{1}" with arguments "{3}" and "{4}" '
|
||||||
'for option "{2}"').format(str(error),
|
'for option {2}').format(str(error),
|
||||||
callback.__name__,
|
callback.__name__,
|
||||||
subconfig.option.impl_get_display_name(subconfig),
|
subconfig.option.impl_get_display_name(subconfig, with_quote=True),
|
||||||
args,
|
args,
|
||||||
kwargs)
|
kwargs)
|
||||||
else:
|
else:
|
||||||
msg = _('unexpected error "{0}" in function "{1}" for option "{2}"'
|
msg = _('unexpected error "{0}" in function "{1}" for option {2}'
|
||||||
'').format(str(error),
|
'').format(str(error),
|
||||||
callback.__name__,
|
callback.__name__,
|
||||||
subconfig.option.impl_get_display_name(subconfig))
|
subconfig.option.impl_get_display_name(subconfig, with_quote=True))
|
||||||
raise ConfigError(msg) from error
|
raise ConfigError(msg) from error
|
||||||
|
|
|
@ -182,10 +182,11 @@ class SubConfig:
|
||||||
'index',
|
'index',
|
||||||
'path',
|
'path',
|
||||||
'true_path',
|
'true_path',
|
||||||
'properties',
|
'_properties',
|
||||||
|
'apply_requires',
|
||||||
'transitive_properties',
|
'transitive_properties',
|
||||||
'is_dynamic',
|
'is_dynamic',
|
||||||
'suffixes',
|
'identifiers',
|
||||||
'_length',
|
'_length',
|
||||||
)
|
)
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
|
@ -194,14 +195,14 @@ class SubConfig:
|
||||||
path: str,
|
path: str,
|
||||||
config_bag: ConfigBag,
|
config_bag: ConfigBag,
|
||||||
parent: Optional['SubConfig'],
|
parent: Optional['SubConfig'],
|
||||||
suffixes: Optional[list[str]],
|
identifiers: Optional[list[str]],
|
||||||
*,
|
*,
|
||||||
true_path: Optional[str]=None,
|
true_path: Optional[str]=None,
|
||||||
properties: Union[list[str], undefined]=undefined,
|
properties: Union[list[str], undefined]=undefined,
|
||||||
validate_properties: bool=True,
|
validate_properties: bool=True,
|
||||||
) -> None:
|
) -> None:
|
||||||
self.index = index
|
self.index = index
|
||||||
self.suffixes = suffixes
|
self.identifiers = identifiers
|
||||||
self.option = option
|
self.option = option
|
||||||
self.config_bag = config_bag
|
self.config_bag = config_bag
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
|
@ -210,38 +211,47 @@ class SubConfig:
|
||||||
if true_path is None:
|
if true_path is None:
|
||||||
true_path = path
|
true_path = path
|
||||||
is_follower = not option.impl_is_optiondescription() and option.impl_is_follower()
|
is_follower = not option.impl_is_optiondescription() and option.impl_is_follower()
|
||||||
apply_requires = not is_follower or index is not None
|
self.apply_requires = not is_follower or index is not None
|
||||||
self.true_path = true_path
|
self.true_path = true_path
|
||||||
settings = config_bag.context.get_settings()
|
|
||||||
if parent and parent.is_dynamic or self.option.impl_is_dynoptiondescription():
|
if parent and parent.is_dynamic or self.option.impl_is_dynoptiondescription():
|
||||||
self.is_dynamic = True
|
self.is_dynamic = True
|
||||||
else:
|
else:
|
||||||
self.is_dynamic = False
|
self.is_dynamic = False
|
||||||
if properties is undefined:
|
self._properties = properties
|
||||||
if path is None:
|
|
||||||
self.properties = frozenset()
|
|
||||||
else:
|
|
||||||
self.properties = frozenset()
|
|
||||||
if validate_properties:
|
|
||||||
self.properties = settings.getproperties(self,
|
|
||||||
apply_requires=False,
|
|
||||||
)
|
|
||||||
self.config_bag.context.get_settings().validate_properties(self)
|
|
||||||
self.properties = settings.getproperties(self,
|
|
||||||
apply_requires=apply_requires,
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
self.properties = properties
|
|
||||||
if validate_properties:
|
if validate_properties:
|
||||||
|
if self.path and self._properties is undefined:
|
||||||
|
settings = config_bag.context.get_settings()
|
||||||
|
self._properties = settings.getproperties(self,
|
||||||
|
apply_requires=False,
|
||||||
|
)
|
||||||
|
self.config_bag.context.get_settings().validate_properties(self)
|
||||||
|
self._properties = undefined
|
||||||
self.config_bag.context.get_settings().validate_properties(self)
|
self.config_bag.context.get_settings().validate_properties(self)
|
||||||
if apply_requires and self.option.impl_is_optiondescription():
|
if self.apply_requires and self.option.impl_is_optiondescription():
|
||||||
if self.path and self.properties is not None:
|
if self.path and self.properties is not None:
|
||||||
|
settings = config_bag.context.get_settings()
|
||||||
self.transitive_properties = settings.calc_transitive_properties(self,
|
self.transitive_properties = settings.calc_transitive_properties(self,
|
||||||
self.properties,
|
self.properties,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self.transitive_properties = frozenset()
|
self.transitive_properties = frozenset()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def properties(self):
|
||||||
|
if self._properties is undefined:
|
||||||
|
if self.path is None:
|
||||||
|
self._properties = frozenset()
|
||||||
|
else:
|
||||||
|
settings = self.config_bag.context.get_settings()
|
||||||
|
self._properties = frozenset()
|
||||||
|
self._properties = settings.getproperties(self,
|
||||||
|
apply_requires=self.apply_requires,
|
||||||
|
)
|
||||||
|
return self._properties
|
||||||
|
|
||||||
|
@properties.setter
|
||||||
|
def properties(self, properties):
|
||||||
|
self._properties = properties
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f'<SubConfig path={self.path}, index={self.index}>'
|
return f'<SubConfig path={self.path}, index={self.index}>'
|
||||||
|
@ -253,9 +263,9 @@ class SubConfig:
|
||||||
true_path: Optional[str]=None,
|
true_path: Optional[str]=None,
|
||||||
) -> List['SubConfig']:
|
) -> List['SubConfig']:
|
||||||
config_bag = self.config_bag
|
config_bag = self.config_bag
|
||||||
for suffix in child.get_suffixes(self):
|
for identifier in child.get_identifiers(self):
|
||||||
try:
|
try:
|
||||||
name = child.impl_getname(suffix)
|
name = child.impl_getname(identifier)
|
||||||
if not validate_properties:
|
if not validate_properties:
|
||||||
properties = None
|
properties = None
|
||||||
else:
|
else:
|
||||||
|
@ -263,7 +273,7 @@ class SubConfig:
|
||||||
yield self.get_child(child,
|
yield self.get_child(child,
|
||||||
None,
|
None,
|
||||||
validate_properties,
|
validate_properties,
|
||||||
suffix=suffix,
|
identifier=identifier,
|
||||||
name=name,
|
name=name,
|
||||||
properties=properties,
|
properties=properties,
|
||||||
true_path=true_path,
|
true_path=true_path,
|
||||||
|
@ -323,7 +333,7 @@ class SubConfig:
|
||||||
*,
|
*,
|
||||||
properties=undefined,
|
properties=undefined,
|
||||||
allow_dynoption: bool=False,
|
allow_dynoption: bool=False,
|
||||||
suffix: Optional[str]=None,
|
identifier: Optional[str]=None,
|
||||||
name: Optional[str]=None,
|
name: Optional[str]=None,
|
||||||
check_index: bool=True,
|
check_index: bool=True,
|
||||||
config_bag: ConfigBag=None,
|
config_bag: ConfigBag=None,
|
||||||
|
@ -338,19 +348,19 @@ class SubConfig:
|
||||||
path = self.get_path(name,
|
path = self.get_path(name,
|
||||||
option,
|
option,
|
||||||
)
|
)
|
||||||
if suffix is None:
|
if identifier is None:
|
||||||
suffixes = self.suffixes
|
identifiers = self.identifiers
|
||||||
else:
|
else:
|
||||||
if self.suffixes:
|
if self.identifiers:
|
||||||
suffixes = self.suffixes + [suffix]
|
identifiers = self.identifiers + [identifier]
|
||||||
else:
|
else:
|
||||||
suffixes = [suffix]
|
identifiers = [identifier]
|
||||||
subsubconfig = SubConfig(option,
|
subsubconfig = SubConfig(option,
|
||||||
index,
|
index,
|
||||||
path,
|
path,
|
||||||
self.config_bag,
|
self.config_bag,
|
||||||
self,
|
self,
|
||||||
suffixes,
|
identifiers,
|
||||||
properties=properties,
|
properties=properties,
|
||||||
validate_properties=validate_properties,
|
validate_properties=validate_properties,
|
||||||
true_path=true_path,
|
true_path=true_path,
|
||||||
|
@ -363,7 +373,7 @@ class SubConfig:
|
||||||
if index >= length:
|
if index >= length:
|
||||||
raise LeadershipError(_(f'index "{index}" is greater than the leadership '
|
raise LeadershipError(_(f'index "{index}" is greater than the leadership '
|
||||||
f'length "{length}" for option '
|
f'length "{length}" for option '
|
||||||
f'"{option.impl_get_display_name(subsubconfig)}"'))
|
f'{option.impl_get_display_name(subsubconfig, with_quote=True)}'))
|
||||||
return subsubconfig
|
return subsubconfig
|
||||||
|
|
||||||
def get_path(self,
|
def get_path(self,
|
||||||
|
@ -393,7 +403,7 @@ class SubConfig:
|
||||||
path,
|
path,
|
||||||
cconfig_bag,
|
cconfig_bag,
|
||||||
self,
|
self,
|
||||||
self.suffixes,
|
self.identifiers,
|
||||||
validate_properties=False,
|
validate_properties=False,
|
||||||
)
|
)
|
||||||
self._length = len(cconfig_bag.context.get_value(subconfig))
|
self._length = len(cconfig_bag.context.get_value(subconfig))
|
||||||
|
@ -587,10 +597,10 @@ class _Config(CCache):
|
||||||
raise AttributeError(_("no option found in config"
|
raise AttributeError(_("no option found in config"
|
||||||
" with these criteria"))
|
" with these criteria"))
|
||||||
|
|
||||||
def _walk_valid_value(self,
|
def walk_valid_value(self,
|
||||||
subconfig,
|
subconfig,
|
||||||
only_mandatory,
|
only_mandatory,
|
||||||
):
|
):
|
||||||
value = self.get_value(subconfig,
|
value = self.get_value(subconfig,
|
||||||
need_help=False,
|
need_help=False,
|
||||||
)
|
)
|
||||||
|
@ -649,19 +659,19 @@ class _Config(CCache):
|
||||||
option = subconfig.option.get_child(name,
|
option = subconfig.option.get_child(name,
|
||||||
config_bag,
|
config_bag,
|
||||||
subconfig,
|
subconfig,
|
||||||
with_suffix=True,
|
with_identifier=True,
|
||||||
allow_dynoption=allow_dynoption,
|
allow_dynoption=allow_dynoption,
|
||||||
)
|
)
|
||||||
if isinstance(option, tuple):
|
if isinstance(option, tuple):
|
||||||
suffix, option = option
|
identifier, option = option
|
||||||
else:
|
else:
|
||||||
suffix = None
|
identifier = None
|
||||||
subconfig = subconfig.get_child(option,
|
subconfig = subconfig.get_child(option,
|
||||||
index_,
|
index_,
|
||||||
validate_properties,
|
validate_properties,
|
||||||
properties=properties,
|
properties=properties,
|
||||||
name=name,
|
name=name,
|
||||||
suffix=suffix,
|
identifier=identifier,
|
||||||
true_path=true_path_,
|
true_path=true_path_,
|
||||||
)
|
)
|
||||||
return subconfig
|
return subconfig
|
||||||
|
@ -710,9 +720,9 @@ class _Config(CCache):
|
||||||
only_mandatory: bool,
|
only_mandatory: bool,
|
||||||
):
|
):
|
||||||
try:
|
try:
|
||||||
value = self._walk_valid_value(subconfig,
|
value = self.walk_valid_value(subconfig,
|
||||||
only_mandatory,
|
only_mandatory,
|
||||||
)
|
)
|
||||||
except PropertiesOptionError as err:
|
except PropertiesOptionError as err:
|
||||||
if err.proptype in (['mandatory'], ['empty']):
|
if err.proptype in (['mandatory'], ['empty']):
|
||||||
if only_mandatory:
|
if only_mandatory:
|
||||||
|
@ -764,8 +774,8 @@ class _Config(CCache):
|
||||||
length = subconfig.parent.get_length_leadership()
|
length = subconfig.parent.get_length_leadership()
|
||||||
follower_len = self.get_values().get_max_length(subconfig.path)
|
follower_len = self.get_values().get_max_length(subconfig.path)
|
||||||
if follower_len > length:
|
if follower_len > length:
|
||||||
option_name = subconfig.option.impl_get_display_name(subconfig)
|
option_name = subconfig.option.impl_get_display_name(subconfig, with_quote=True)
|
||||||
raise LeadershipError(_(f'the follower option "{option_name}" '
|
raise LeadershipError(_(f'the follower option {option_name} '
|
||||||
f'has greater length ({follower_len}) than the leader '
|
f'has greater length ({follower_len}) than the leader '
|
||||||
f'length ({length})'))
|
f'length ({length})'))
|
||||||
self.get_settings().validate_mandatory(subconfig,
|
self.get_settings().validate_mandatory(subconfig,
|
||||||
|
|
Loading…
Reference in a new issue