From ce297ed804853cf0a00df1e38f73547457b4537a Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Wed, 20 Nov 2019 08:26:41 +0100 Subject: [PATCH] better unique support --- tiramisu/option/option.py | 83 ++++++++++++++++++++------------------- 1 file changed, 42 insertions(+), 41 deletions(-) diff --git a/tiramisu/option/option.py b/tiramisu/option/option.py index cee2a17..313d8f3 100644 --- a/tiramisu/option/option.py +++ b/tiramisu/option/option.py @@ -42,10 +42,8 @@ class Option(BaseOption): """ __slots__ = ('_extra', '_warnings_only', - '_allow_empty_list', # multi '_multi', - '_unique', # value '_default', '_default_multi', @@ -63,12 +61,10 @@ class Option(BaseOption): default: Any=undefined, default_multi: Any=None, multi: bool=False, - unique: bool=undefined, validators: Optional[List[Calculation]]=None, properties: Optional[List[str]]=None, warnings_only: bool=False, - extra: Optional[Dict]=None, - allow_empty_list: bool=undefined) -> None: + extra: Optional[Dict]=None): _setattr = object.__setattr__ if not multi and default_multi is not None: raise ValueError(_("default_multi is set whereas multi is False" @@ -114,14 +110,8 @@ class Option(BaseOption): self._validators = tuple(validators) if extra is not None and extra != {}: _setattr(self, '_extra', extra) - if unique != undefined and not isinstance(unique, bool): - raise ValueError(_('unique must be a boolean, not "{}"').format(unique)) - if not is_multi and unique is True: - raise ValueError(_('unique must be set only with multi value')) if warnings_only is True: _setattr(self, '_warnings_only', warnings_only) - if allow_empty_list is not undefined: - _setattr(self, '_allow_empty_list', allow_empty_list) if is_multi and default_multi is not None: def test_multi_value(value): if isinstance(value, Calculation): @@ -132,8 +122,9 @@ class Option(BaseOption): None, undefined) try: - self._validate(value, - option_bag) + self.validate(value) + self.validate_with_option(value, + option_bag) except ValueError as err: str_err = str(err) if not str_err: @@ -157,8 +148,6 @@ class Option(BaseOption): else: test_multi_value(default_multi) _setattr(self, '_default_multi', default_multi) - if unique is not undefined: - _setattr(self, '_unique', unique) option_bag = OptionBag() option_bag.set_option(self, undefined, @@ -166,6 +155,9 @@ class Option(BaseOption): undefined) self.impl_validate(default, option_bag) + self.impl_validate(default, + option_bag, + check_error=False) self.value_dependencies(default) if (is_multi and default != []) or \ (not is_multi and default is not None): @@ -201,12 +193,6 @@ class Option(BaseOption): def impl_is_submulti(self) -> bool: return getattr(self, '_multi', 1) == 2 - def impl_is_unique(self) -> bool: - return getattr(self, '_unique', False) - - def impl_allow_empty_list(self) -> Union[Undefined, bool]: - return getattr(self, '_allow_empty_list', undefined) - def impl_is_dynsymlinkoption(self) -> bool: return False @@ -267,15 +253,16 @@ class Option(BaseOption): return - def _is_not_unique(value): + def _is_not_unique(value, option_bag): # if set(value) has not same length than value - if check_error and self.impl_is_unique() and \ - len(set(value)) != len(value): - for idx, val in enumerate(value): - if val in value[idx+1:]: - raise ValueError(_('invalid value "{}", this value is already in "{}"' - '').format(val, - self.impl_get_display_name())) + if config_bag is not undefined and check_error and \ + 'unique' in option_bag.properties: + lvalue = [val for val in value if val is not None] + if len(set(lvalue)) != len(lvalue): + for idx, val in enumerate(value): + if val in value[idx+1:]: + raise ValueError(_('the value "{}" is not unique' + '').format(val)) def calculation_validator(val, _index): @@ -303,9 +290,17 @@ class Option(BaseOption): '{0}'.format(err), _index), ValueWarning, - self.__class__.__name__, 0) + self.__class__.__name__, 306) else: raise err + except ValueWarning as warn: + warnings.warn_explicit(ValueWarning(val, + self._display_name, + self, + '{0}'.format(warn), + _index), + ValueWarning, + self.__class__.__name__, 316) def do_validation(_value, _index): @@ -317,14 +312,14 @@ class Option(BaseOption): if _value is not None: if check_error: # option validation - self._validate(_value, - option_bag, - option_bag.ori_option) + self.validate(_value) + self.validate_with_option(_value, + option_bag) if ((check_error and not is_warnings_only) or (not check_error and is_warnings_only)): try: - self._second_level_validation(_value, - is_warnings_only) + self.second_level_validation(_value, + is_warnings_only) except ValueError as err: if is_warnings_only: warnings.warn_explicit(ValueWarning(_value, @@ -347,7 +342,7 @@ class Option(BaseOption): if self.impl_is_submulti(): if not isinstance(value, list): raise ValueError(_('which must be a list')) - _is_not_unique(value) + _is_not_unique(value, option_bag) for val in value: do_validation(val, force_index) @@ -360,7 +355,7 @@ class Option(BaseOption): raise ValueError(_('which must be a list')) elif self.impl_is_submulti(): for err_index, lval in enumerate(value): - _is_not_unique(lval) + _is_not_unique(lval, option_bag) if isinstance(lval, Calculation): continue if not isinstance(lval, list): @@ -370,7 +365,8 @@ class Option(BaseOption): do_validation(val, err_index) else: - _is_not_unique(value) + _is_not_unique(value, option_bag) + # FIXME subtimal, not several time is whole=True! for err_index, val in enumerate(value): do_validation(val, err_index) @@ -403,9 +399,14 @@ class Option(BaseOption): raise ValueError(_('default value not allowed if option "{0}" ' 'is calculated').format(self.impl_getname())) - def _second_level_validation(self, - value: Any, - warnings_only: bool) -> None: + def validate_with_option(self, + value: Any, + option_bag: OptionBag) -> None: + pass + + def second_level_validation(self, + value: Any, + warnings_only: bool) -> None: pass def impl_is_leader(self):