refactor
This commit is contained in:
@ -32,7 +32,7 @@ if sys.version_info[0] >= 3: # pragma: no cover
|
||||
else:
|
||||
from inspect import getargspec
|
||||
|
||||
STATIC_TUPLE = tuple()
|
||||
STATIC_TUPLE = frozenset()
|
||||
|
||||
|
||||
submulti = 2
|
||||
@ -145,6 +145,8 @@ class Base(object):
|
||||
requires = undefined
|
||||
if properties is None:
|
||||
properties = tuple()
|
||||
if is_multi and 'empty' not in properties:
|
||||
properties = tuple(list(properties) + ['empty'])
|
||||
if not isinstance(properties, tuple):
|
||||
raise TypeError(_('invalid properties type {0} for {1},'
|
||||
' must be a tuple').format(
|
||||
@ -406,11 +408,15 @@ class BaseOption(Base):
|
||||
name = name.encode('utf8')
|
||||
return name
|
||||
|
||||
def reset_cache(self, opt, obj, type_, resetted_opts):
|
||||
def reset_cache(self,
|
||||
opt,
|
||||
path,
|
||||
obj,
|
||||
type_,
|
||||
resetted_opts):
|
||||
if opt in resetted_opts:
|
||||
return
|
||||
if not type_ == 'values' or not opt.impl_is_optiondescription():
|
||||
path = opt.impl_getpath(obj._getcontext())
|
||||
if type_ != 'permissives':
|
||||
obj._p_.delcache(path)
|
||||
if type_ in ['settings', 'permissives']:
|
||||
|
@ -21,6 +21,7 @@
|
||||
# ____________________________________________________________
|
||||
import warnings
|
||||
import sys
|
||||
import weakref
|
||||
|
||||
from .baseoption import OnlyOption, submulti, DynSymLinkOption, validate_callback, STATIC_TUPLE
|
||||
from ..i18n import _
|
||||
@ -146,9 +147,17 @@ class Option(OnlyOption):
|
||||
def impl_is_multi(self):
|
||||
return getattr(self, '_multi', 1) != 1
|
||||
|
||||
def _launch_consistency(self, current_opt, func, option, value, context,
|
||||
index, submulti_index, opts, warnings_only,
|
||||
transitive):
|
||||
def _launch_consistency(self,
|
||||
current_opt,
|
||||
func,
|
||||
option,
|
||||
value,
|
||||
context,
|
||||
index,
|
||||
opts,
|
||||
warnings_only,
|
||||
transitive,
|
||||
setting_properties):
|
||||
"""Launch consistency now
|
||||
|
||||
:param func: function name, this name should start with _cons_
|
||||
@ -174,7 +183,8 @@ class Option(OnlyOption):
|
||||
all_cons_vals = []
|
||||
all_cons_opts = []
|
||||
val_consistencies = True
|
||||
for opt in opts:
|
||||
for wopt in opts:
|
||||
opt = wopt()
|
||||
if (isinstance(opt, DynSymLinkOption) and option._dyn == opt._dyn) or \
|
||||
option == opt:
|
||||
# option is current option
|
||||
@ -195,7 +205,9 @@ class Option(OnlyOption):
|
||||
else:
|
||||
_index = index
|
||||
try:
|
||||
opt_value = context.getattr(path, validate=False,
|
||||
opt_value = context.getattr(path,
|
||||
setting_properties,
|
||||
validate=False,
|
||||
index=_index,
|
||||
force_permissive=True)
|
||||
except PropertiesOptionError as err:
|
||||
@ -254,7 +266,6 @@ class Option(OnlyOption):
|
||||
context=undefined,
|
||||
validate=True,
|
||||
force_index=None,
|
||||
force_submulti_index=None,
|
||||
current_opt=undefined,
|
||||
is_multi=None,
|
||||
display_error=True,
|
||||
@ -270,9 +281,6 @@ class Option(OnlyOption):
|
||||
:param force_index: if multi, value has to be a list
|
||||
not if force_index is not None
|
||||
:type force_index: integer
|
||||
:param force_submulti_index: if submulti, value has to be a list
|
||||
not if force_submulti_index is not None
|
||||
:type force_submulti_index: integer
|
||||
"""
|
||||
if not validate:
|
||||
return
|
||||
@ -287,10 +295,12 @@ class Option(OnlyOption):
|
||||
if display_error and self.impl_is_unique() and len(set(value)) != len(value):
|
||||
for idx, val in enumerate(value):
|
||||
if val in value[idx+1:]:
|
||||
return ValueError(_('invalid value "{}", this value is already in "{}"').format(
|
||||
val, self.impl_get_display_name()))
|
||||
return ValueError(_('invalid value "{}", this value is already in "{}"'
|
||||
'').format(val,
|
||||
self.impl_get_display_name()))
|
||||
|
||||
def calculation_validator(val, _index):
|
||||
def calculation_validator(val,
|
||||
_index):
|
||||
validator, validator_params = self.impl_get_validator()
|
||||
if validator is not None:
|
||||
if validator_params != {}:
|
||||
@ -316,9 +326,10 @@ class Option(OnlyOption):
|
||||
if isinstance(value, Exception):
|
||||
return value
|
||||
|
||||
def do_validation(_value, _index, submulti_index):
|
||||
def do_validation(_value,
|
||||
_index):
|
||||
if _value is None:
|
||||
error = warning = None
|
||||
error = None
|
||||
else:
|
||||
if display_error:
|
||||
# option validation
|
||||
@ -327,35 +338,41 @@ class Option(OnlyOption):
|
||||
current_opt)
|
||||
if err:
|
||||
if debug: # pragma: no cover
|
||||
log.debug('do_validation: value: {0}, index: {1}, '
|
||||
'submulti_index: {2}'.format(_value,
|
||||
_index,
|
||||
submulti_index),
|
||||
log.debug('do_validation: value: {0}, index: {1}:'
|
||||
' {2}'.format(_value,
|
||||
_index),
|
||||
exc_info=True)
|
||||
err_msg = '{0}'.format(err)
|
||||
if err_msg:
|
||||
msg = _('"{0}" is an invalid {1} for "{2}", {3}'
|
||||
'').format(_value, self._display_name,
|
||||
'').format(_value,
|
||||
self._display_name,
|
||||
self.impl_get_display_name(), err_msg)
|
||||
else:
|
||||
msg = _('"{0}" is an invalid {1} for "{2}"'
|
||||
'').format(_value, self._display_name,
|
||||
'').format(_value,
|
||||
self._display_name,
|
||||
self.impl_get_display_name())
|
||||
return ValueError(msg)
|
||||
error = None
|
||||
is_warnings_only = getattr(self, '_warnings_only', False)
|
||||
if ((display_error and not is_warnings_only) or
|
||||
(display_warnings and is_warnings_only)):
|
||||
error = calculation_validator(_value, _index)
|
||||
error = calculation_validator(_value,
|
||||
_index)
|
||||
if not error:
|
||||
error = self._second_level_validation(_value, is_warnings_only)
|
||||
error = self._second_level_validation(_value,
|
||||
is_warnings_only)
|
||||
if error:
|
||||
if debug: # pragma: no cover
|
||||
log.debug(_('do_validation for {0}: error in value').format(
|
||||
self.impl_getname()), exc_info=True)
|
||||
if is_warnings_only:
|
||||
msg = _('attention, "{0}" could be an invalid {1} for "{2}", {3}').format(
|
||||
_value, self._display_name, self.impl_get_display_name(), error)
|
||||
msg = _('attention, "{0}" could be an invalid {1} for "{2}", {3}'
|
||||
'').format(_value,
|
||||
self._display_name,
|
||||
self.impl_get_display_name(),
|
||||
error)
|
||||
warnings.warn_explicit(ValueWarning(msg, self),
|
||||
ValueWarning,
|
||||
self.__class__.__name__, 0)
|
||||
@ -367,9 +384,9 @@ class Option(OnlyOption):
|
||||
_value,
|
||||
context,
|
||||
_index,
|
||||
submulti_index,
|
||||
display_warnings,
|
||||
display_error)
|
||||
display_error,
|
||||
setting_properties)
|
||||
if isinstance(ret, ValueError):
|
||||
error = ret
|
||||
elif ret:
|
||||
@ -390,22 +407,22 @@ class Option(OnlyOption):
|
||||
is_multi = self.impl_is_multi()
|
||||
|
||||
if not is_multi:
|
||||
return do_validation(value, None, None)
|
||||
return do_validation(value, None)
|
||||
elif force_index is not None:
|
||||
if self.impl_is_submulti() and force_submulti_index is None:
|
||||
if self.impl_is_submulti():
|
||||
err = _is_not_unique(value)
|
||||
if err:
|
||||
return err
|
||||
if not isinstance(value, list):
|
||||
return ValueError(_('invalid value "{0}" for "{1}" which'
|
||||
' must be a list').format(
|
||||
value, self.impl_get_display_name()))
|
||||
value, self.impl_get_display_name()))
|
||||
for idx, val in enumerate(value):
|
||||
if isinstance(val, list): # pragma: no cover
|
||||
return ValueError(_('invalid value "{}" for "{}" '
|
||||
'which must not be a list').format(val,
|
||||
self.impl_get_display_name()))
|
||||
err = do_validation(val, force_index, idx)
|
||||
self.impl_get_display_name()))
|
||||
err = do_validation(val, force_index)
|
||||
if err:
|
||||
return err
|
||||
else:
|
||||
@ -419,12 +436,12 @@ class Option(OnlyOption):
|
||||
return ValueError(_('invalid value "{}", this value is already'
|
||||
' in "{}"').format(value,
|
||||
self.impl_get_display_name()))
|
||||
return do_validation(value, force_index, force_submulti_index)
|
||||
return do_validation(value, force_index)
|
||||
elif not isinstance(value, list):
|
||||
return ValueError(_('invalid value "{0}" for "{1}" which '
|
||||
'must be a list').format(value,
|
||||
self.impl_getname()))
|
||||
elif self.impl_is_submulti() and force_submulti_index is None:
|
||||
elif self.impl_is_submulti():
|
||||
for idx, val in enumerate(value):
|
||||
err = _is_not_unique(val)
|
||||
if err:
|
||||
@ -434,8 +451,9 @@ class Option(OnlyOption):
|
||||
'which must be a list of list'
|
||||
'').format(val,
|
||||
self.impl_getname()))
|
||||
for slave_idx, slave_val in enumerate(val):
|
||||
err = do_validation(slave_val, idx, slave_idx)
|
||||
for slave_val in val:
|
||||
err = do_validation(slave_val,
|
||||
idx)
|
||||
if err:
|
||||
return err
|
||||
else:
|
||||
@ -443,16 +461,17 @@ class Option(OnlyOption):
|
||||
if err:
|
||||
return err
|
||||
for idx, val in enumerate(value):
|
||||
err = do_validation(val, idx, force_submulti_index)
|
||||
err = do_validation(val,
|
||||
idx)
|
||||
if err:
|
||||
return err
|
||||
return self._valid_consistency(current_opt,
|
||||
None,
|
||||
context,
|
||||
None,
|
||||
None,
|
||||
display_warnings,
|
||||
display_error)
|
||||
display_error,
|
||||
setting_properties)
|
||||
|
||||
def impl_is_dynsymlinkoption(self):
|
||||
return False
|
||||
@ -480,7 +499,10 @@ class Option(OnlyOption):
|
||||
"accesses the Option's doc"
|
||||
return self.impl_get_information('doc')
|
||||
|
||||
def _valid_consistencies(self, other_opts, init=True, func=None):
|
||||
def _valid_consistencies(self,
|
||||
other_opts,
|
||||
init=True,
|
||||
func=None):
|
||||
if self._is_subdyn():
|
||||
dynod = self._subdyn()
|
||||
else:
|
||||
@ -488,7 +510,11 @@ class Option(OnlyOption):
|
||||
if self.impl_is_submulti():
|
||||
raise ConfigError(_('cannot add consistency with submulti option'))
|
||||
is_multi = self.impl_is_multi()
|
||||
for opt in other_opts:
|
||||
for wopt in other_opts:
|
||||
if isinstance(wopt, weakref.ReferenceType):
|
||||
opt = wopt()
|
||||
else:
|
||||
opt = wopt
|
||||
if opt.impl_is_submulti():
|
||||
raise ConfigError(_('cannot add consistency with submulti option'))
|
||||
if not isinstance(opt, Option):
|
||||
@ -515,7 +541,10 @@ class Option(OnlyOption):
|
||||
if func != 'not_equal':
|
||||
opt._has_dependency = True
|
||||
|
||||
def impl_add_consistency(self, func, *other_opts, **params):
|
||||
def impl_add_consistency(self,
|
||||
func,
|
||||
*other_opts,
|
||||
**params):
|
||||
"""Add consistency means that value will be validate with other_opts
|
||||
option's values.
|
||||
|
||||
@ -525,39 +554,51 @@ class Option(OnlyOption):
|
||||
:type other_opts: `list` of `tiramisu.option.Option`
|
||||
:param params: extra params (warnings_only and transitive are allowed)
|
||||
"""
|
||||
if self.impl_is_readonly():
|
||||
if self.impl_is_readonly():
|
||||
raise AttributeError(_("'{0}' ({1}) cannot add consistency, option is"
|
||||
" read-only").format(
|
||||
self.__class__.__name__,
|
||||
self.impl_getname()))
|
||||
self._valid_consistencies(other_opts, func=func)
|
||||
self._valid_consistencies(other_opts,
|
||||
func=func)
|
||||
func = '_cons_{0}'.format(func)
|
||||
if func not in dir(self):
|
||||
raise ConfigError(_('consistency {0} not available for this option').format(func))
|
||||
all_cons_opts = tuple([self] + list(other_opts))
|
||||
options = [weakref.ref(self)]
|
||||
for option in other_opts:
|
||||
options.append(weakref.ref(option))
|
||||
all_cons_opts = tuple(options)
|
||||
unknown_params = set(params.keys()) - set(['warnings_only', 'transitive'])
|
||||
if unknown_params != set():
|
||||
raise ValueError(_('unknown parameter {0} in consistency').format(unknown_params))
|
||||
self._add_consistency(func, all_cons_opts, params)
|
||||
self._add_consistency(func,
|
||||
all_cons_opts,
|
||||
params)
|
||||
#validate default value when add consistency
|
||||
err = self.impl_validate(self.impl_getdefault())
|
||||
if err:
|
||||
self._del_consistency()
|
||||
raise err
|
||||
if func in ALLOWED_CONST_LIST:
|
||||
for opt in all_cons_opts:
|
||||
if getattr(opt, '_unique', undefined) == undefined:
|
||||
opt._unique = True
|
||||
if func != '_cons_not_equal':
|
||||
#consistency could generate warnings or errors
|
||||
self._has_dependency = True
|
||||
for opt in all_cons_opts:
|
||||
for wopt in all_cons_opts:
|
||||
opt = wopt()
|
||||
if func in ALLOWED_CONST_LIST:
|
||||
if getattr(opt, '_unique', undefined) == undefined:
|
||||
opt._unique = True
|
||||
if opt != self:
|
||||
self._add_dependency(opt)
|
||||
opt._add_dependency(self)
|
||||
|
||||
def _valid_consistency(self, option, value, context, index, submulti_idx,
|
||||
display_warnings, display_error):
|
||||
def _valid_consistency(self,
|
||||
option,
|
||||
value,
|
||||
context,
|
||||
index,
|
||||
display_warnings,
|
||||
display_error,
|
||||
setting_properties):
|
||||
if context is not undefined:
|
||||
descr = context.cfgimpl_get_description()
|
||||
if descr._cache_consistencies is None:
|
||||
@ -586,10 +627,16 @@ class Option(OnlyOption):
|
||||
opts.append(opt._impl_to_dyn(name, path))
|
||||
else:
|
||||
opts = all_cons_opts
|
||||
err = opts[0]._launch_consistency(self, func, option, value,
|
||||
context, index, submulti_idx,
|
||||
opts, warnings_only,
|
||||
transitive)
|
||||
err = opts[0]()._launch_consistency(self,
|
||||
func,
|
||||
option,
|
||||
value,
|
||||
context,
|
||||
index,
|
||||
opts,
|
||||
warnings_only,
|
||||
transitive,
|
||||
setting_properties)
|
||||
if err:
|
||||
return err
|
||||
|
||||
@ -680,7 +727,10 @@ class Option(OnlyOption):
|
||||
|
||||
#____________________________________________________________
|
||||
# consistency
|
||||
def _add_consistency(self, func, all_cons_opts, params):
|
||||
def _add_consistency(self,
|
||||
func,
|
||||
all_cons_opts,
|
||||
params):
|
||||
cons = (func, all_cons_opts, params)
|
||||
consistencies = getattr(self, '_consistencies', None)
|
||||
if consistencies is None:
|
||||
|
@ -125,8 +125,8 @@ class CacheOptionDescription(BaseOption):
|
||||
'must be in same master/slaves for {1}').format(
|
||||
require_opt.impl_getname(), option.impl_getname()))
|
||||
else:
|
||||
raise ValueError(_('malformed requirements option {0} '
|
||||
'must not be a multi for {1}').format(
|
||||
raise ValueError(_('malformed requirements option "{0}" '
|
||||
'must not be a multi for "{1}"').format(
|
||||
require_opt.impl_getname(), option.impl_getname()))
|
||||
if init:
|
||||
if len(cache_option) != len(set(cache_option)):
|
||||
@ -137,7 +137,7 @@ class CacheOptionDescription(BaseOption):
|
||||
if _consistencies != {}:
|
||||
self._cache_consistencies = {}
|
||||
for opt, cons in _consistencies.items():
|
||||
if opt not in cache_option: # pragma: optional cover
|
||||
if opt() not in cache_option: # pragma: optional cover
|
||||
raise ConfigError(_('consistency with option {0} '
|
||||
'which is not in Config').format(
|
||||
opt.impl_getname()))
|
||||
@ -437,12 +437,12 @@ class OptionDescription(OptionDescriptionWalk):
|
||||
for child in valid_child:
|
||||
if child == old: # pragma: optional cover
|
||||
raise ConflictError(_('duplicate option name: '
|
||||
'{0}').format(child))
|
||||
'"{0}"').format(child))
|
||||
if dynopt_names:
|
||||
for dynopt in dynopt_names:
|
||||
if child != dynopt and child.startswith(dynopt):
|
||||
raise ConflictError(_('option must not start as '
|
||||
'dynoptiondescription'))
|
||||
raise ConflictError(_('the option\'s name "{}" start as '
|
||||
'the dynoptiondescription\'s name "{}"').format(child, dynopt))
|
||||
old = child
|
||||
_setattr = object.__setattr__
|
||||
_setattr(self, '_children', (tuple(child_names), tuple(children)))
|
||||
@ -623,7 +623,7 @@ class MasterSlaves(OptionDescription):
|
||||
name))
|
||||
slaves.append(child)
|
||||
child._add_dependency(self)
|
||||
for child in children:
|
||||
for idx, child in enumerate(children):
|
||||
if child._is_symlinkoption(): # pragma: optional cover
|
||||
raise ValueError(_("master group {0} shall not have "
|
||||
"a symlinkoption").format(self.impl_getname()))
|
||||
@ -635,6 +635,11 @@ class MasterSlaves(OptionDescription):
|
||||
"in group {1}"
|
||||
": this option is not a multi"
|
||||
"").format(child.impl_getname(), self.impl_getname()))
|
||||
# no empty property for save
|
||||
if idx != 0:
|
||||
properties = list(child._properties)
|
||||
properties.remove('empty')
|
||||
child._properties = tuple(properties)
|
||||
callback, callback_params = master.impl_get_callback()
|
||||
if callback is not None and callback_params != {}:
|
||||
for callbacks in callback_params.values():
|
||||
|
Reference in New Issue
Block a user