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',
|
__slots__ = ('_extra',
|
||||||
'_warnings_only',
|
'_warnings_only',
|
||||||
'_allow_empty_list',
|
|
||||||
# multi
|
# multi
|
||||||
'_multi',
|
'_multi',
|
||||||
'_unique',
|
|
||||||
# value
|
# value
|
||||||
'_default',
|
'_default',
|
||||||
'_default_multi',
|
'_default_multi',
|
||||||
|
@ -63,12 +61,10 @@ class Option(BaseOption):
|
||||||
default: Any=undefined,
|
default: Any=undefined,
|
||||||
default_multi: Any=None,
|
default_multi: Any=None,
|
||||||
multi: bool=False,
|
multi: bool=False,
|
||||||
unique: bool=undefined,
|
|
||||||
validators: Optional[List[Calculation]]=None,
|
validators: Optional[List[Calculation]]=None,
|
||||||
properties: Optional[List[str]]=None,
|
properties: Optional[List[str]]=None,
|
||||||
warnings_only: bool=False,
|
warnings_only: bool=False,
|
||||||
extra: Optional[Dict]=None,
|
extra: Optional[Dict]=None):
|
||||||
allow_empty_list: bool=undefined) -> None:
|
|
||||||
_setattr = object.__setattr__
|
_setattr = object.__setattr__
|
||||||
if not multi and default_multi is not None:
|
if not multi and default_multi is not None:
|
||||||
raise ValueError(_("default_multi is set whereas multi is False"
|
raise ValueError(_("default_multi is set whereas multi is False"
|
||||||
|
@ -114,14 +110,8 @@ class Option(BaseOption):
|
||||||
self._validators = tuple(validators)
|
self._validators = tuple(validators)
|
||||||
if extra is not None and extra != {}:
|
if extra is not None and extra != {}:
|
||||||
_setattr(self, '_extra', 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:
|
if warnings_only is True:
|
||||||
_setattr(self, '_warnings_only', warnings_only)
|
_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:
|
if is_multi and default_multi is not None:
|
||||||
def test_multi_value(value):
|
def test_multi_value(value):
|
||||||
if isinstance(value, Calculation):
|
if isinstance(value, Calculation):
|
||||||
|
@ -132,7 +122,8 @@ class Option(BaseOption):
|
||||||
None,
|
None,
|
||||||
undefined)
|
undefined)
|
||||||
try:
|
try:
|
||||||
self._validate(value,
|
self.validate(value)
|
||||||
|
self.validate_with_option(value,
|
||||||
option_bag)
|
option_bag)
|
||||||
except ValueError as err:
|
except ValueError as err:
|
||||||
str_err = str(err)
|
str_err = str(err)
|
||||||
|
@ -157,8 +148,6 @@ class Option(BaseOption):
|
||||||
else:
|
else:
|
||||||
test_multi_value(default_multi)
|
test_multi_value(default_multi)
|
||||||
_setattr(self, '_default_multi', default_multi)
|
_setattr(self, '_default_multi', default_multi)
|
||||||
if unique is not undefined:
|
|
||||||
_setattr(self, '_unique', unique)
|
|
||||||
option_bag = OptionBag()
|
option_bag = OptionBag()
|
||||||
option_bag.set_option(self,
|
option_bag.set_option(self,
|
||||||
undefined,
|
undefined,
|
||||||
|
@ -166,6 +155,9 @@ class Option(BaseOption):
|
||||||
undefined)
|
undefined)
|
||||||
self.impl_validate(default,
|
self.impl_validate(default,
|
||||||
option_bag)
|
option_bag)
|
||||||
|
self.impl_validate(default,
|
||||||
|
option_bag,
|
||||||
|
check_error=False)
|
||||||
self.value_dependencies(default)
|
self.value_dependencies(default)
|
||||||
if (is_multi and default != []) or \
|
if (is_multi and default != []) or \
|
||||||
(not is_multi and default is not None):
|
(not is_multi and default is not None):
|
||||||
|
@ -201,12 +193,6 @@ class Option(BaseOption):
|
||||||
def impl_is_submulti(self) -> bool:
|
def impl_is_submulti(self) -> bool:
|
||||||
return getattr(self, '_multi', 1) == 2
|
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:
|
def impl_is_dynsymlinkoption(self) -> bool:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -267,15 +253,16 @@ class Option(BaseOption):
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
def _is_not_unique(value):
|
def _is_not_unique(value, option_bag):
|
||||||
# if set(value) has not same length than value
|
# if set(value) has not same length than value
|
||||||
if check_error and self.impl_is_unique() and \
|
if config_bag is not undefined and check_error and \
|
||||||
len(set(value)) != len(value):
|
'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):
|
for idx, val in enumerate(value):
|
||||||
if val in value[idx+1:]:
|
if val in value[idx+1:]:
|
||||||
raise ValueError(_('invalid value "{}", this value is already in "{}"'
|
raise ValueError(_('the value "{}" is not unique'
|
||||||
'').format(val,
|
'').format(val))
|
||||||
self.impl_get_display_name()))
|
|
||||||
|
|
||||||
def calculation_validator(val,
|
def calculation_validator(val,
|
||||||
_index):
|
_index):
|
||||||
|
@ -303,9 +290,17 @@ class Option(BaseOption):
|
||||||
'{0}'.format(err),
|
'{0}'.format(err),
|
||||||
_index),
|
_index),
|
||||||
ValueWarning,
|
ValueWarning,
|
||||||
self.__class__.__name__, 0)
|
self.__class__.__name__, 306)
|
||||||
else:
|
else:
|
||||||
raise err
|
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,
|
def do_validation(_value,
|
||||||
_index):
|
_index):
|
||||||
|
@ -317,13 +312,13 @@ class Option(BaseOption):
|
||||||
if _value is not None:
|
if _value is not None:
|
||||||
if check_error:
|
if check_error:
|
||||||
# option validation
|
# option validation
|
||||||
self._validate(_value,
|
self.validate(_value)
|
||||||
option_bag,
|
self.validate_with_option(_value,
|
||||||
option_bag.ori_option)
|
option_bag)
|
||||||
if ((check_error and not is_warnings_only) or
|
if ((check_error and not is_warnings_only) or
|
||||||
(not check_error and is_warnings_only)):
|
(not check_error and is_warnings_only)):
|
||||||
try:
|
try:
|
||||||
self._second_level_validation(_value,
|
self.second_level_validation(_value,
|
||||||
is_warnings_only)
|
is_warnings_only)
|
||||||
except ValueError as err:
|
except ValueError as err:
|
||||||
if is_warnings_only:
|
if is_warnings_only:
|
||||||
|
@ -347,7 +342,7 @@ class Option(BaseOption):
|
||||||
if self.impl_is_submulti():
|
if self.impl_is_submulti():
|
||||||
if not isinstance(value, list):
|
if not isinstance(value, list):
|
||||||
raise ValueError(_('which must be a list'))
|
raise ValueError(_('which must be a list'))
|
||||||
_is_not_unique(value)
|
_is_not_unique(value, option_bag)
|
||||||
for val in value:
|
for val in value:
|
||||||
do_validation(val,
|
do_validation(val,
|
||||||
force_index)
|
force_index)
|
||||||
|
@ -360,7 +355,7 @@ class Option(BaseOption):
|
||||||
raise ValueError(_('which must be a list'))
|
raise ValueError(_('which must be a list'))
|
||||||
elif self.impl_is_submulti():
|
elif self.impl_is_submulti():
|
||||||
for err_index, lval in enumerate(value):
|
for err_index, lval in enumerate(value):
|
||||||
_is_not_unique(lval)
|
_is_not_unique(lval, option_bag)
|
||||||
if isinstance(lval, Calculation):
|
if isinstance(lval, Calculation):
|
||||||
continue
|
continue
|
||||||
if not isinstance(lval, list):
|
if not isinstance(lval, list):
|
||||||
|
@ -370,7 +365,8 @@ class Option(BaseOption):
|
||||||
do_validation(val,
|
do_validation(val,
|
||||||
err_index)
|
err_index)
|
||||||
else:
|
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):
|
for err_index, val in enumerate(value):
|
||||||
do_validation(val,
|
do_validation(val,
|
||||||
err_index)
|
err_index)
|
||||||
|
@ -403,7 +399,12 @@ class Option(BaseOption):
|
||||||
raise ValueError(_('default value not allowed if option "{0}" '
|
raise ValueError(_('default value not allowed if option "{0}" '
|
||||||
'is calculated').format(self.impl_getname()))
|
'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,
|
value: Any,
|
||||||
warnings_only: bool) -> None:
|
warnings_only: bool) -> None:
|
||||||
pass
|
pass
|
||||||
|
|
Loading…
Reference in a new issue