diff --git a/tests/test_leadership.py b/tests/test_leadership.py index e70a110..229d0fd 100644 --- a/tests/test_leadership.py +++ b/tests/test_leadership.py @@ -788,6 +788,19 @@ def test_values_with_leader_and_followers_leader_pop(): # assert not list_sessions() +def test_values_with_leader_and_followers_leader_pop_default_value(): + ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", default=["192.168.230.145", "192.168.230.146"], multi=True, properties=('notunique',)) + netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", default_multi="255.255.255.0", multi=True) + interface1 = Leadership('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0]) + od1 = OptionDescription('toto', '', [interface1]) + cfg = Config(od1) + cfg.property.read_write() + cfg.option('ip_admin_eth0.ip_admin_eth0').value.pop(0) + compare(cfg.value.exportation(), {'ip_admin_eth0.ip_admin_eth0': {None: [['192.168.230.146'], 'user']}}) + assert cfg.option('ip_admin_eth0.ip_admin_eth0').value.get() == ["192.168.230.146"] + assert cfg.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get() == '255.255.255.0' + + def test_follower_unique(): ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True) netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True, properties=('unique',)) diff --git a/tests/test_option_callback.py b/tests/test_option_callback.py index da37b60..f54c186 100644 --- a/tests/test_option_callback.py +++ b/tests/test_option_callback.py @@ -945,7 +945,7 @@ def test_consistency_leader_and_followers_leader_mandatory_transitive(): try: cfg.option('val1.val2', 0).value.get() except PropertiesOptionError as error: - assert str(error) == str(_('cannot access to {0} {1} because has {2} {3}').format('option', '"val2"', _('property'), '"disabled"')) + assert str(error) == str(_('cannot access to {0} {1} at index "{2}" because has {3} {4}').format('option', '"val2"', 0, _('property'), '"disabled"')) else: raise Exception('must raises') assert list(cfg.value.mandatory()) == [] diff --git a/tiramisu/api.py b/tiramisu/api.py index 2da429b..03e744f 100644 --- a/tiramisu/api.py +++ b/tiramisu/api.py @@ -271,9 +271,18 @@ class _TiramisuOptionWalk: class _TiramisuOptionOptionDescription: """Manage option""" + _validate_properties = False - @option_type(["optiondescription", "option", "with_or_without_index", "symlink", "allow_dynoption"]) + @option_type( + [ + "optiondescription", + "option", + "with_or_without_index", + "symlink", + "allow_dynoption", + ] + ) def get(self): """Get Tiramisu option""" return self._subconfig.option @@ -291,11 +300,14 @@ class _TiramisuOptionOptionDescription: @option_type(["optiondescription", "option", "with_or_without_index", "symlink"]) def description( self, + with_quote: bool = False, uncalculated: bool = False, ): """Get option description""" if not uncalculated: - return self._subconfig.option.impl_get_display_name(self._subconfig) + return self._subconfig.option.impl_get_display_name( + self._subconfig, with_quote=with_quote + ) return self._subconfig.option._get_information( self._subconfig, "doc", @@ -354,7 +366,7 @@ class _TiramisuOptionOptionDescription: if option.impl_is_optiondescription(): return "optiondescription" if only_self and option.impl_is_symlinkoption(): - return 'symlink' + return "symlink" return option.get_type() @option_type(["option", "symlink", "with_or_without_index"]) @@ -808,11 +820,7 @@ class TiramisuOptionValue(CommonTiramisuOption, _TiramisuODGet): and option.impl_is_leader() and len(value) < self._subconfig.parent.get_length_leadership() ): - raise LeadershipError( - _("cannot reduce length of the leader {}" "").format( - option.impl_get_display_name(self._subconfig, with_quote=True) - ) - ) + raise LeadershipError(self._subconfig, "leadership-reduce") values = self._config_bag.context.get_values() return values.set_value(self._subconfig, value) diff --git a/tiramisu/autolib.py b/tiramisu/autolib.py index 3a448cf..f31b5c5 100644 --- a/tiramisu/autolib.py +++ b/tiramisu/autolib.py @@ -22,7 +22,15 @@ from typing import Any, Optional, Union, Callable, Dict, List from itertools import chain import weakref -from .error import PropertiesOptionError, ConfigError, LeadershipError, ValueWarning, CancelParam, display_list, errors +from .error import ( + PropertiesOptionError, + ConfigError, + LeadershipError, + ValueWarning, + CancelParam, + display_list, + errors, +) from .i18n import _ from .setting import undefined, ConfigBag from .function import FUNCTION_WAITING_FOR_DICT, FUNCTION_WAITING_FOR_ERROR @@ -149,11 +157,15 @@ class ParamDynOption(ParamOption): ) if not isinstance(identifiers, list): raise Exception( - _("identifiers in ParamDynOption must be a list, not {0}").format(identifiers) + _("identifiers in ParamDynOption must be a list, not {0}").format( + identifiers + ) ) if not isinstance(optional, bool): raise Exception( - _("optional in ParamDynOption must be a boolean, not {0}").format(optional) + _("optional in ParamDynOption must be a boolean, not {0}").format( + optional + ) ) self.identifiers = identifiers self.optional = optional @@ -204,7 +216,9 @@ class ParamInformation(Param): def set_option(self, option: "Option" = None) -> None: if not hasattr(self, "self_option"): - raise ConfigError(_("cannot add option in information after creating config")) + raise ConfigError( + _("cannot add option in information after creating config") + ) if self.option: raise ConfigError(_("cannot redefine option in information")) if not option.impl_is_optiondescription(): @@ -464,7 +478,9 @@ def manager_callback( ["configerror"], config_bag.context.get_settings(), ) - errors.raise_carry_out_calculation_error(subconfig, _("unable to get value for calculating {0}, {1}"), err) + errors.raise_carry_out_calculation_error( + subconfig, _("unable to get value for calculating {0}, {1}"), err + ) return value def get_option_bag( @@ -496,7 +512,12 @@ def manager_callback( # raise PropertiesOptionError (which is catched) because must not add value None in carry_out_calculation if param.notraisepropertyerror or param.raisepropertyerror: raise err from err - errors.raise_carry_out_calculation_error(subconfig, _("unable to carry out a calculation for {0}, {1}"), err, option=option) + errors.raise_carry_out_calculation_error( + subconfig, + _("unable to carry out a calculation for {0}, {1}"), + err, + option=option, + ) except ValueError as err: display_name = option.impl_get_display_name(subconfig, with_quote=True) raise ValueError( @@ -512,7 +533,12 @@ def manager_callback( ["configerror"], config_bag.context.get_settings(), ) - errors.raise_carry_out_calculation_error(subconfig, _("unable to get value for calculating {0}, {1}"), err, option=option) + errors.raise_carry_out_calculation_error( + subconfig, + _("unable to get value for calculating {0}, {1}"), + err, + option=option, + ) return subsubconfig if isinstance(param, ParamValue): @@ -532,7 +558,13 @@ def manager_callback( search_name = search_option.impl_get_display_name( None, with_quote=True ) - errors.raise_carry_out_calculation_error(subconfig, _("cannot find information for {0}, {1} is a dynamic option"), None, option=option, extra_keys=[search_name]) + errors.raise_carry_out_calculation_error( + subconfig, + _("cannot find information for {0}, {1} is a dynamic option"), + None, + option=option, + extra_keys=[search_name], + ) else: isubconfig = get_option_bag( config_bag, @@ -551,7 +583,12 @@ def manager_callback( param.default_value, ) except ValueError as err: - errors.raise_carry_out_calculation_error(subconfig, _("unable to get value for calculating {0}, {1}"), err, option=option) + errors.raise_carry_out_calculation_error( + subconfig, + _("unable to get value for calculating {0}, {1}"), + err, + option=option, + ) if isinstance(param, ParamIndex): return index @@ -561,7 +598,14 @@ def manager_callback( not option.impl_is_optiondescription() or not option.impl_is_dynoptiondescription() ): - errors.raise_carry_out_calculation_error(subconfig, _("option {0} is not a dynoptiondescription or in a dynoptiondescription"), None, option=option) + errors.raise_carry_out_calculation_error( + subconfig, + _( + "option {0} is not a dynoptiondescription or in a dynoptiondescription" + ), + None, + option=option, + ) if subconfig.identifiers is None: # if uncalculated return @@ -637,18 +681,36 @@ def manager_callback( ) except AttributeError as err: if parent.path: - child_path = parent.path + '.' + name + child_path = parent.path + "." + name else: child_path = name if param.optional: - raise CancelParam(callbk_option.impl_getpath(), child_path) + raise CancelParam( + callbk_option.impl_getpath(), child_path + ) identifiers = doption.get_identifiers(parent) if not identifiers: - errors.raise_carry_out_calculation_error(subconfig, _('cannot calculate arguments for {0}, {1} with identifier "{2}", there is no identifiers'), err, extra_keys=[identifier]) + errors.raise_carry_out_calculation_error( + subconfig, + _( + 'cannot calculate arguments for {0}, {1} with identifier "{2}", there is no identifiers' + ), + err, + extra_keys=[identifier], + ) else: - identifiers_list = display_list(identifiers, add_quote=True) - errors.raise_carry_out_calculation_error(subconfig, _('cannot calculate arguments for {0}, {1} with identifier "{2}", list of valid identifiers: {3}'), err, extra_keys=[identifier, identifiers_list]) + identifiers_list = display_list( + identifiers, add_quote=True + ) + errors.raise_carry_out_calculation_error( + subconfig, + _( + 'cannot calculate arguments for {0}, {1} with identifier "{2}", list of valid identifiers: {3}' + ), + err, + extra_keys=[identifier, identifiers_list], + ) new_parents.append( parent.get_child( doption, @@ -752,7 +814,12 @@ def carry_out_calculation( and option.impl_is_follower() and index is None ): - errors.raise_carry_out_calculation_error(subconfig, _("the follower {0} must have index in carry_out_calculation!"), None, option=option) + errors.raise_carry_out_calculation_error( + subconfig, + _("the follower {0} must have index in carry_out_calculation!"), + None, + option=option, + ) def fake_items(iterator): return ((None, i) for i in iterator) @@ -822,33 +889,14 @@ def carry_out_calculation( and option.impl_is_follower() and not option.impl_is_submulti() ): - if args or kwargs: - raise LeadershipError( - _( - 'the "{}" function with positional arguments "{}" ' - 'and keyword arguments "{}" must not return ' - 'a list ("{}") for the follower option {}' - "" - ).format( - callback.__name__, - args, - kwargs, - ret, - option.impl_get_display_name(subconfig, with_quote=True), - ) - ) - else: - raise LeadershipError( - _( - 'the "{}" function must not return a list ("{}") ' - "for the follower option {}" - "" - ).format( - callback.__name__, - ret, - option.impl_get_display_name(subconfig, with_quote=True), - ) - ) + raise LeadershipError( + subconfig, + "leadership-follower-callback-list", + callback=callback.__name__, + args=args, + kwargs=kwargs, + ret=ret, + ) return ret @@ -884,11 +932,14 @@ def calculate( 'unexpected error "{1}" in function "{2}" with arguments "{3}" and "{4}" ' "for option {0}" ) - extra_keys = [callback.__name__, - args, - kwargs, - ] + extra_keys = [ + callback.__name__, + args, + kwargs, + ] else: msg = _('unexpected error "{1}" in function "{2}" for option {0}') extra_keys = [callback.__name__] - errors.raise_carry_out_calculation_error(subconfig, msg, error, extra_keys=extra_keys) + errors.raise_carry_out_calculation_error( + subconfig, msg, error, extra_keys=extra_keys + ) diff --git a/tiramisu/config.py b/tiramisu/config.py index 54dbe56..219609b 100644 --- a/tiramisu/config.py +++ b/tiramisu/config.py @@ -228,7 +228,7 @@ class SubConfig: *, true_path: Optional[str] = None, # for python 3.9 properties: Union[list[str], undefined] = undefined, - properties = undefined, + properties=undefined, validate_properties: bool = True, ) -> None: self.index = index @@ -417,13 +417,7 @@ class SubConfig: length = self.get_length_leadership() if index >= length: raise LeadershipError( - _( - 'index "{0}" is greater than the leadership length "{1}" for option {2}' - ).format( - index, - length, - option.impl_get_display_name(subsubconfig, with_quote=True), - ) + subsubconfig, "leadership-greater", index=index, length=length ) return subsubconfig @@ -869,9 +863,10 @@ class _Config(CCache): subconfig, with_quote=True ) raise LeadershipError( - _( - "the follower option {0} has greater length ({1}) than the leader length ({2})" - ).format(option_name, follower_len, length) + subconfig, + "leadership-follower-greater", + index=follower_len, + length=length, ) self.get_settings().validate_mandatory( subconfig, diff --git a/tiramisu/error.py b/tiramisu/error.py index 76c0933..3be49d1 100644 --- a/tiramisu/error.py +++ b/tiramisu/error.py @@ -18,6 +18,23 @@ import weakref from .i18n import _ +from typing import Literal, Union + + +TiramisuErrorCode = Literal[ + "option-dynamic", + "option-not-found", + "property-frozen", + "property-error", + "property-mandatory", + "leadership-group_type", + "leadership-wrong_property", + "leadership-force_default_on_freeze", + "leadership-greater", + "leadership-follower-greater", + "leadership-follower-callback-list", +] + def display_list( lst, @@ -69,6 +86,8 @@ class PropertiesOptionError(AttributeError): orig_opt=None, help_properties=None, ): + if orig_opt: + raise Exception("a la") if opt_type: self._opt_type = opt_type self._name = name @@ -87,10 +106,23 @@ class PropertiesOptionError(AttributeError): self.help_properties = help_properties self._settings = settings self.msg = None + if not self.help_properties: + self.help_properties = self.proptype + properties = list(self.help_properties) + if properties == ["frozen"]: + self.code = "property-frozen" + elif properties == ["mandatory"]: + self.code = "property-mandatory" + else: + self.code = "property-error" super().__init__(None) - def set_orig_opt(self, opt): - self._orig_opt = opt + def display_properties(self, force_property=False, add_quote=True): + if force_property: + properties = self.proptype + else: + properties = self.help_properties + return display_list(list(properties), add_quote=add_quote) def __str__(self): # this part is a bit slow, so only execute when display @@ -98,47 +130,81 @@ class PropertiesOptionError(AttributeError): return self.msg if self._settings is None: return "error" - if self.help_properties: - properties = list(self.help_properties) - else: - properties = list(self.proptype) - only_one = len(properties) == 1 - properties_msg = display_list(properties, add_quote=True) - if only_one: - prop_msg = _("property") - else: - prop_msg = _("properties") - if properties == ["frozen"]: - if self._orig_opt: - msg = _('cannot modify the {0} {1} because "{2}" has {3} {4}') - else: - msg = _("cannot modify the {0} {1} because has {2} {3}") - elif properties == ["mandatory"]: - if self._orig_opt: - msg = _("cannot access to {0} {1} because \"{2}\" hasn't value") - else: - msg = _("{0} {1} is mandatory but hasn't value") - else: - if self._orig_opt: - msg = _('cannot access to {0} {1} because "{2}" has {3} {4}') - else: - msg = _("cannot access to {0} {1} because has {2} {3}") + arguments = [self._opt_type] if self._orig_opt: - # FIXME _orig_opt ? - self.msg = msg.format( - self._opt_type, - self._orig_opt.impl_get_display_name(subconfig, with_quote=True), - self._name, - prop_msg, - properties_msg, + arguments.append( + self._orig_opt.impl_get_display_name(subconfig, with_quote=True) ) + arguments.append(self._name) + index = self._subconfig.index + if index is not None: + arguments.append(index) + if self.code == "property-frozen": + if index is not None: + if self._orig_opt: + msg = _( + 'cannot modify the {0} {1} at index "{2}" because {3} is frozen' + ) + else: + msg = _( + 'cannot modify the {0} {1} at index "{2}" because is frozen' + ) + else: + if self._orig_opt: + msg = _("cannot modify the {0} {1} because {2} is frozen") + else: + msg = _("cannot modify the {0} {1} because is frozen") + elif self.code == "property-mandatory": + if index is not None: + if self._orig_opt: + msg = _( + 'cannot access to {0} {1} at index "{2}" because {2} hasn\'t value' + ) + else: + msg = _('{0} {1} at index "{2}" is mandatory but hasn\'t value') + else: + if self._orig_opt: + msg = _("cannot access to {0} {1} because {2} hasn't value") + else: + msg = _("{0} {1} is mandatory but hasn't value") else: - self.msg = msg.format(self._opt_type, self._name, prop_msg, properties_msg) + if index is not None: + if self._orig_opt: + msg = _( + 'cannot access to {0} {1} at index "{2}" because {3} has {4} {5}' + ) + else: + msg = _( + 'cannot access to {0} {1} at index "{2}" because has {3} {4}' + ) + else: + if self._orig_opt: + msg = _("cannot access to {0} {1} because {2} has {3} {4}") + else: + msg = _("cannot access to {0} {1} because has {2} {3}") + only_one = len(self.help_properties) == 1 + if only_one: + arguments.append(_("property")) + else: + arguments.append(_("properties")) + arguments.append(self.display_properties()) + self.msg = msg.format(*arguments) del self._opt_type, self._name del self._settings, self._orig_opt return self.msg +class AttributeOptionError(AttributeError): + def __init__(self, path: str, code: TiramisuErrorCode) -> None: + self.path = path + self.code = code + + def __str__(self) -> str: + if self.code == "option-dynamic": + return _('cannot access to "{0}" it\'s a dynamic option').format(self.path) + return _('"{0}" is not an option').format(self.path) + + # ____________________________________________________________ # Exceptions for a Config class ConfigError(Exception): @@ -163,8 +229,74 @@ class ConflictError(Exception): # ____________________________________________________________ # miscellaneous exceptions class LeadershipError(Exception): - "problem with a leadership's value length" - pass + def __init__( + self, + subconfig: Union[str, "SubConfig"], + code, + *, + prop=None, + index=None, + length=None, + callback=None, + args=None, + kwargs=None, + ret=None, + ): + if isinstance(subconfig, str): + self.path = self.display_name = subconfig + else: + self.path = subconfig.path + option = subconfig.option + self.display_name = option.impl_get_display_name(subconfig, with_quote=True) + self.code = code + if prop: + self.prop = prop + if index: + self.index = index + if length: + self.length = length + if callback: + self.callback = callback + if args: + self.args = args + if kwargs: + self.kwargs = kwargs + if ret: + self.ret = ret + + def __str__(self): + if self.code == "leadership-group_type": + return _('cannot set "group_type" attribute for the Leadership {0}').format( + self.display_name + ) + if self.code == "leadership-wrong_property": + return _('the leader {0} cannot have "{1}" property').format( + self.display_name, self.prop + ) + if self.code == "leadership-force_default_on_freeze": + return _( + 'the leader {0} cannot have "force_default_on_freeze" or "force_metaconfig_on_freeze" property without "frozen"' + ).format(self.display_name) + if self.code == "leadership-reduce": + return _("cannot reduce length of the leader {0}").format(self.display_name) + if self.code == "leadership-greater": + return _( + 'index "{0}" is greater than the leadership length "{1}" for option {2}' + ).format(self.index, self.length, self.display_name) + if self.code == "leadership-follower-greater": + return _( + "the follower option {0} has greater length ({1}) than the leader length ({2})" + ).format(self.display_name, self.index, self.length) + if self.code == "leadership-follower-callback-list": + if self.args or self.kwargs: + return _( + 'the "{0}" function with positional arguments "{1}" and keyword arguments "{2}" must not return a list ("{3}") for the follower option {4}' + ).format( + self.callback, self.args, self.kwargs, self.ret, self.display_name + ) + return _( + 'the "{0}" function must not return a list ("{1}") for the follower option {2}' + ).format(self.callback, self.ret, self.display_name) class ConstError(TypeError): @@ -186,7 +318,9 @@ class _CommonError: try: msg = self.prefix except AttributeError: - self.prefix = self.tmpl.format(self.val, _(self.display_type), self.name, self.index) + self.prefix = self.tmpl.format( + self.val, _(self.display_type), self.name, self.index + ) msg = self.prefix if self.err_msg: if msg: @@ -203,12 +337,16 @@ class ValueWarning(_CommonError, UserWarning): def __init__(self, **kwargs): if ValueWarning.tmpl is None: - if kwargs.get('index') is None: - ValueWarning.tmpl = _('attention, "{0}" could be an invalid {1} for {2}') + if kwargs.get("index") is None: + ValueWarning.tmpl = _( + 'attention, "{0}" could be an invalid {1} for {2}' + ) else: - ValueWarning.tmpl = _('attention, "{0}" could be an invalid {1} for {2} at index "{3}"') - if list(kwargs) == ['msg']: - self.msg = kwargs['msg'] + ValueWarning.tmpl = _( + 'attention, "{0}" could be an invalid {1} for {2} at index "{3}"' + ) + if list(kwargs) == ["msg"]: + self.msg = kwargs["msg"] else: super().__init__(**kwargs) self.msg = None @@ -224,7 +362,7 @@ class ValueOptionError(_CommonError, ValueError): def __init__(self, **kwargs): if ValueOptionError.tmpl is None: - if kwargs.get('index') is None: + if kwargs.get("index") is None: self.tmpl = _('"{0}" is an invalid {1} for {2}') else: self.tmpl = _('"{0}" is an invalid {1} for {2} at index "{3}"') @@ -258,12 +396,12 @@ class CancelParam(Exception): class Errors: @staticmethod - def raise_carry_out_calculation_error(subconfig, message, original_error, option=None, extra_keys=[]): + def raise_carry_out_calculation_error( + subconfig, message, original_error, option=None, extra_keys=[] + ): if option is None: option = subconfig.option - display_name = option.impl_get_display_name( - subconfig, with_quote=True - ) + display_name = option.impl_get_display_name(subconfig, with_quote=True) if original_error: raise ConfigError( message.format(display_name, original_error, *extra_keys) diff --git a/tiramisu/option/domainnameoption.py b/tiramisu/option/domainnameoption.py index b08895b..1c25df0 100644 --- a/tiramisu/option/domainnameoption.py +++ b/tiramisu/option/domainnameoption.py @@ -176,9 +176,7 @@ class DomainnameOption(StrOption): try: socket.gethostbyname(value) except socket.gaierror as err: - raise ValueError( - _("DNS resolution failed").format(value) - ) from err + raise ValueError(_("DNS resolution failed").format(value)) from err except Exception as err: raise ValueError( _("error resolving DNS: {1}").format(value, err) diff --git a/tiramisu/option/filenameoption.py b/tiramisu/option/filenameoption.py index ac9189a..5db0875 100644 --- a/tiramisu/option/filenameoption.py +++ b/tiramisu/option/filenameoption.py @@ -74,9 +74,12 @@ class FilenameOption(StrOption): if not found and "directory" in types and file.is_dir(): found = True if not found: - translated_types = [{"file": _("file"), "directory": _("directory")}.get(typ) for typ in types] + translated_types = [ + {"file": _("file"), "directory": _("directory")}.get(typ) + for typ in types + ] raise ValueError( - _('cannot find this {0}').format( + _("cannot find this {0}").format( display_list(translated_types, separator="or"), value ) ) diff --git a/tiramisu/option/intoption.py b/tiramisu/option/intoption.py index 5c8a4fc..514e11d 100644 --- a/tiramisu/option/intoption.py +++ b/tiramisu/option/intoption.py @@ -43,7 +43,7 @@ class IntOption(Option): value: int, ) -> None: if not isinstance(value, int): - raise ValueError(_('which is not an integer')) + raise ValueError(_("which is not an integer")) def second_level_validation(self, value, warnings_only): min_number = self.impl_get_extra("min_number") diff --git a/tiramisu/option/leadership.py b/tiramisu/option/leadership.py index 829eb3f..1a4b11e 100644 --- a/tiramisu/option/leadership.py +++ b/tiramisu/option/leadership.py @@ -51,9 +51,7 @@ class Leadership(OptionDescription): **kwargs, ) -> None: if "group_type" in kwargs: - raise LeadershipError( - _('cannot set "group_type" attribute for a Leadership') - ) + raise LeadershipError(name, "leadership-group_type") super().__init__( name, doc, @@ -85,9 +83,7 @@ class Leadership(OptionDescription): if prop not in ALLOWED_LEADER_PROPERTIES and not isinstance( prop, Calculation ): - raise LeadershipError( - _('leader cannot have "{}" property').format(prop) - ) + raise LeadershipError(name, "leadership-wrong_property", prop=prop) def _check_child_is_valid( self, diff --git a/tiramisu/option/option.py b/tiramisu/option/option.py index b8e9b75..e7ed6e1 100644 --- a/tiramisu/option/option.py +++ b/tiramisu/option/option.py @@ -259,7 +259,7 @@ class Option(BaseOption): *, check_error: bool = True, loaded: bool = False, - self_properties: frozenset=frozenset(), + self_properties: frozenset = frozenset(), ) -> bool: """Return True if value is really valid If not validate or invalid return it returns False @@ -269,8 +269,11 @@ class Option(BaseOption): config_properties = subconfig.config_bag.properties self_properties = subconfig.properties else: - config_properties = {'validator'} - if "validator" not in config_properties or "validator" not in self_properties: + config_properties = {"validator"} + if ( + "validator" not in config_properties + or "validator" not in self_properties + ): return False if subconfig: force_index = subconfig.index @@ -443,11 +446,21 @@ class Option(BaseOption): or "demoting_error_warning" not in subconfig.config_bag.properties ): raise ValueOptionError( - subconfig=subconfig, val=val, display_type=_(self.get_type()), opt=self, err_msg=str(err), index=err_index + subconfig=subconfig, + val=val, + display_type=_(self.get_type()), + opt=self, + err_msg=str(err), + index=err_index, ) from err warnings.warn_explicit( ValueErrorWarning( - subconfig=subconfig, val=val, display_type=_(self.get_type()), opt=self, err_msg=str(err), index=err_index + subconfig=subconfig, + val=val, + display_type=_(self.get_type()), + opt=self, + err_msg=str(err), + index=err_index, ), ValueErrorWarning, self.__class__.__name__, diff --git a/tiramisu/option/optiondescription.py b/tiramisu/option/optiondescription.py index c086050..b67c5e2 100644 --- a/tiramisu/option/optiondescription.py +++ b/tiramisu/option/optiondescription.py @@ -29,7 +29,7 @@ from ..setting import ConfigBag, groups, undefined, owners, Undefined from .baseoption import BaseOption # from .syndynoption import SubDynOptionDescription, SynDynOptionDescription -from ..error import ConfigError, ConflictError +from ..error import ConfigError, ConflictError, AttributeOptionError class CacheOptionDescription(BaseOption): @@ -242,12 +242,10 @@ class OptionDescriptionWalk(CacheOptionDescription): ] # pylint: disable=no-member if option.impl_is_dynoptiondescription() and not allow_dynoption: if parent.path: - path = parent.path + '.' + name + path = parent.path + "." + name else: path = name - raise AttributeError( - _('cannot access to "{0}" it\'s a dynamic option').format(path) - ) + raise AttributeOptionError(path, "option-dynamic") return option def get_child( @@ -279,14 +277,10 @@ class OptionDescriptionWalk(CacheOptionDescription): return child return identifier, child if parent.path is None: - raise AttributeError( - _('cannot find "{0}"').format(name) - ) - raise AttributeError( - _('cannot find "{0}" in "{1}"').format( - name, parent.path - ) - ) + path = name + else: + path = parent.path + "." + name + raise AttributeOptionError(path, "option-not-found") def get_children(self) -> List[BaseOption]: """get children""" diff --git a/tiramisu/option/stroption.py b/tiramisu/option/stroption.py index b8a9a22..ce68bcc 100644 --- a/tiramisu/option/stroption.py +++ b/tiramisu/option/stroption.py @@ -38,7 +38,7 @@ class StrOption(Option): ) -> None: """validation""" if not isinstance(value, str): - raise ValueError(_('which is not a string')) + raise ValueError(_("which is not a string")) class RegexpOption(StrOption): diff --git a/tiramisu/option/urloption.py b/tiramisu/option/urloption.py index 41636af..f8ad82a 100644 --- a/tiramisu/option/urloption.py +++ b/tiramisu/option/urloption.py @@ -56,23 +56,23 @@ class URLOption(StrOption): # pylint: disable=too-many-arguments,too-many-locals,redefined-builtin extra = {} extra["_domainname"] = DomainnameOption( - name, - doc, - allow_ip=allow_ip, - type=type, - allow_without_dot=allow_without_dot, - _extra=extra, - ) - extra["_port"] = PortOption( - name, - doc, - allow_range=allow_range, - allow_zero=allow_zero, - allow_wellknown=allow_wellknown, - allow_registred=allow_registred, - allow_private=allow_private, - _extra=extra, - ) + name, + doc, + allow_ip=allow_ip, + type=type, + allow_without_dot=allow_without_dot, + _extra=extra, + ) + extra["_port"] = PortOption( + name, + doc, + allow_range=allow_range, + allow_zero=allow_zero, + allow_wellknown=allow_wellknown, + allow_registred=allow_registred, + allow_private=allow_private, + _extra=extra, + ) super().__init__( name, doc, diff --git a/tiramisu/setting.py b/tiramisu/setting.py index d69a3a1..1c163b8 100644 --- a/tiramisu/setting.py +++ b/tiramisu/setting.py @@ -476,7 +476,7 @@ class Settings: and new_prop not in ALLOWED_LEADER_PROPERTIES ): raise LeadershipError( - _('leader cannot have "{new_prop}" property') + subconfig, "leadership-wrong_property", prop=new_prop ) props.add(new_prop) props -= self.getpermissives(subconfig) @@ -564,19 +564,15 @@ class Settings: not_allowed_properties = properties - ALLOWED_LEADER_PROPERTIES if not_allowed_properties: raise LeadershipError( - _('leader cannot have "{0}" property').format( - display_list(not_allowed_properties) - ) + subconfig, + "leadership-wrong_property", + prop=display_list(not_allowed_properties), ) if ( "force_default_on_freeze" in properties or "force_metaconfig_on_freeze" in properties ) and "frozen" not in properties: - raise LeadershipError( - _( - 'a leader ({0}) cannot have "force_default_on_freeze" or "force_metaconfig_on_freeze" property without "frozen"' - ).format(opt.impl_get_display_name()) - ) + raise LeadershipError(subconfig, "leadership-force_default_on_freeze") self._properties.setdefault(subconfig.path, {})[subconfig.index] = properties # values too because of follower values could have a PropertiesOptionError has value subconfig.config_bag.context.reset_cache(subconfig) diff --git a/tiramisu/value.py b/tiramisu/value.py index 26cc612..9ded876 100644 --- a/tiramisu/value.py +++ b/tiramisu/value.py @@ -295,9 +295,9 @@ class Values: owners.forced, ) validator = ( - "validator" in setting_properties and - "validator" in self_properties and - "demoting_error_warning" not in setting_properties + "validator" in setting_properties + and "validator" in self_properties + and "demoting_error_warning" not in setting_properties ) if validator and not has_calculation: cache = subconfig.config_bag.context.get_values_cache() @@ -306,7 +306,11 @@ class Values: value, validated=validator, ) - elif "validator" in setting_properties and "validator" in self_properties and has_calculation: + elif ( + "validator" in setting_properties + and "validator" in self_properties + and has_calculation + ): cache = subconfig.config_bag.context.get_values_cache() cache.delcache(subconfig.path) @@ -592,7 +596,12 @@ class Values: self_properties = subconfig.properties context = config_bag.context setting_properties = config_bag.properties - if validate and hasvalue and "validator" in setting_properties and "validator" in self_properties: + if ( + validate + and hasvalue + and "validator" in setting_properties + and "validator" in self_properties + ): fake_context = context.gen_fake_context() fake_config_bag = config_bag.copy() fake_config_bag.remove_validation()