better unique support
This commit is contained in:
parent
973b81d339
commit
ce297ed804
1 changed files with 42 additions and 41 deletions
|
@ -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,7 +122,8 @@ class Option(BaseOption):
|
|||
None,
|
||||
undefined)
|
||||
try:
|
||||
self._validate(value,
|
||||
self.validate(value)
|
||||
self.validate_with_option(value,
|
||||
option_bag)
|
||||
except ValueError as err:
|
||||
str_err = 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):
|
||||
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(_('invalid value "{}", this value is already in "{}"'
|
||||
'').format(val,
|
||||
self.impl_get_display_name()))
|
||||
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,13 +312,13 @@ 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,
|
||||
self.second_level_validation(_value,
|
||||
is_warnings_only)
|
||||
except ValueError as err:
|
||||
if is_warnings_only:
|
||||
|
@ -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,7 +399,12 @@ class Option(BaseOption):
|
|||
raise ValueError(_('default value not allowed if option "{0}" '
|
||||
'is calculated').format(self.impl_getname()))
|
||||
|
||||
def _second_level_validation(self,
|
||||
def validate_with_option(self,
|
||||
value: Any,
|
||||
option_bag: OptionBag) -> None:
|
||||
pass
|
||||
|
||||
def second_level_validation(self,
|
||||
value: Any,
|
||||
warnings_only: bool) -> None:
|
||||
pass
|
||||
|
|
Loading…
Reference in a new issue