consistencies can make a warning instead of raises
for that, you have to set something like: a.impl_add_consistency('not_equal', b, warnings_only=True) warning product now adapted message
This commit is contained in:
@ -336,7 +336,7 @@ class Option(BaseOption):
|
||||
self._consistencies = None
|
||||
|
||||
def _launch_consistency(self, func, option, value, context, index,
|
||||
all_cons_opts):
|
||||
all_cons_opts, warnings_only):
|
||||
"""Launch consistency now
|
||||
|
||||
:param func: function name, this name should start with _cons_
|
||||
@ -351,6 +351,8 @@ class Option(BaseOption):
|
||||
:type index: `int`
|
||||
:param all_cons_opts: all options concerne by this consistency
|
||||
:type all_cons_opts: `list` of `tiramisu.option.Option`
|
||||
:param warnings_only: specific raise error for warning
|
||||
:type warnings_only: `boolean`
|
||||
"""
|
||||
if context is not None:
|
||||
descr = context.cfgimpl_get_description()
|
||||
@ -379,7 +381,7 @@ class Option(BaseOption):
|
||||
except IndexError:
|
||||
#so return if no value
|
||||
return
|
||||
getattr(self, func)(all_cons_opts, all_cons_vals)
|
||||
getattr(self, func)(all_cons_opts, all_cons_vals, warnings_only)
|
||||
|
||||
def impl_validate(self, value, context=None, validate=True,
|
||||
force_index=None):
|
||||
@ -422,22 +424,31 @@ class Option(BaseOption):
|
||||
except ValueError as err:
|
||||
raise ValueError(_('invalid value for option {0}: {1}'
|
||||
'').format(self._name, err))
|
||||
error = None
|
||||
warning = None
|
||||
try:
|
||||
# valid with self._validator
|
||||
val_validator(_value)
|
||||
# if not context launch consistency validation
|
||||
# if context launch consistency validation
|
||||
if context is not None:
|
||||
descr._valid_consistency(self, _value, context, _index)
|
||||
self._second_level_validation(_value)
|
||||
except ValueError as err:
|
||||
msg = _("invalid value for option {0}: {1}").format(
|
||||
self._name, err)
|
||||
descr._valid_consistency(self, _value, context, _index,
|
||||
self._warnings_only)
|
||||
self._second_level_validation(_value, self._warnings_only)
|
||||
except ValueError as error:
|
||||
if self._warnings_only:
|
||||
warnings.warn_explicit(ValueWarning(msg, self),
|
||||
ValueWarning,
|
||||
self.__class__.__name__, 0)
|
||||
else:
|
||||
raise ValueError(msg)
|
||||
warning = error
|
||||
error = None
|
||||
except ValueWarning as warning:
|
||||
pass
|
||||
if warning:
|
||||
msg = _("warning on the value of the option {0}: {1}").format(
|
||||
self._name, warning)
|
||||
warnings.warn_explicit(ValueWarning(msg, self),
|
||||
ValueWarning,
|
||||
self.__class__.__name__, 0)
|
||||
elif error:
|
||||
raise ValueError(_("invalid value for option {0}: {1}").format(
|
||||
self._name, error))
|
||||
|
||||
# generic calculation
|
||||
if context is not None:
|
||||
@ -490,7 +501,7 @@ class Option(BaseOption):
|
||||
def impl_is_multi(self):
|
||||
return self._multi
|
||||
|
||||
def impl_add_consistency(self, func, *other_opts):
|
||||
def impl_add_consistency(self, func, *other_opts, **params):
|
||||
"""Add consistency means that value will be validate with other_opts
|
||||
option's values.
|
||||
|
||||
@ -498,16 +509,18 @@ class Option(BaseOption):
|
||||
:type func: `str`
|
||||
:param other_opts: options used to validate value
|
||||
:type other_opts: `list` of `tiramisu.option.Option`
|
||||
:param params: extra params (only warnings_only are allowed)
|
||||
"""
|
||||
if self._consistencies is None:
|
||||
self._consistencies = []
|
||||
warnings_only = params.get('warnings_only', False)
|
||||
for opt in other_opts:
|
||||
if not isinstance(opt, Option):
|
||||
raise ConfigError(_('consistency should be set with an option'))
|
||||
raise ConfigError(_('consistency must be set with an option'))
|
||||
if self is opt:
|
||||
raise ConfigError(_('cannot add consistency with itself'))
|
||||
if self.impl_is_multi() != opt.impl_is_multi():
|
||||
raise ConfigError(_('every options in consistency should be '
|
||||
raise ConfigError(_('every options in consistency must be '
|
||||
'multi or none'))
|
||||
func = '_cons_{0}'.format(func)
|
||||
all_cons_opts = tuple([self] + list(other_opts))
|
||||
@ -516,19 +529,23 @@ class Option(BaseOption):
|
||||
if self.impl_is_multi():
|
||||
for idx, val in enumerate(value):
|
||||
self._launch_consistency(func, self, val, None,
|
||||
idx, all_cons_opts)
|
||||
idx, all_cons_opts, warnings_only)
|
||||
else:
|
||||
self._launch_consistency(func, self, value, None,
|
||||
None, all_cons_opts)
|
||||
self._consistencies.append((func, all_cons_opts))
|
||||
None, all_cons_opts, warnings_only)
|
||||
self._consistencies.append((func, all_cons_opts, params))
|
||||
self.impl_validate(self.impl_getdefault())
|
||||
|
||||
def _cons_not_equal(self, opts, vals):
|
||||
def _cons_not_equal(self, opts, vals, warnings_only):
|
||||
for idx_inf, val_inf in enumerate(vals):
|
||||
for idx_sup, val_sup in enumerate(vals[idx_inf + 1:]):
|
||||
if val_inf == val_sup is not None:
|
||||
raise ValueError(_("same value for {0} and {1}").format(
|
||||
opts[idx_inf]._name, opts[idx_inf + idx_sup + 1]._name))
|
||||
if warnings_only:
|
||||
msg = _("same value for {0} and {1}, should be different")
|
||||
else:
|
||||
msg = _("same value for {0} and {1}, must be different")
|
||||
raise ValueError(msg.format(opts[idx_inf]._name,
|
||||
opts[idx_inf + idx_sup + 1]._name))
|
||||
|
||||
def _impl_convert_callbacks(self, descr, load=False):
|
||||
if not load and self._callback is None:
|
||||
@ -592,14 +609,14 @@ class Option(BaseOption):
|
||||
values.append(descr.impl_get_opt_by_path(obj))
|
||||
else:
|
||||
values.append(descr.impl_get_path_by_opt(obj))
|
||||
new_value.append((consistency[0], tuple(values)))
|
||||
new_value.append((consistency[0], tuple(values), consistency[2]))
|
||||
if load:
|
||||
del(self._state_consistencies)
|
||||
self._consistencies = new_value
|
||||
else:
|
||||
self._state_consistencies = new_value
|
||||
|
||||
def _second_level_validation(self, value):
|
||||
def _second_level_validation(self, value, warnings_only):
|
||||
pass
|
||||
|
||||
|
||||
@ -777,24 +794,36 @@ class IPOption(Option):
|
||||
except ValueError:
|
||||
raise ValueError(_('invalid IP'))
|
||||
|
||||
def _second_level_validation(self, value):
|
||||
def _second_level_validation(self, value, warnings_only):
|
||||
ip = IP('{0}/32'.format(value))
|
||||
if not self._allow_reserved and ip.iptype() == 'RESERVED':
|
||||
raise ValueError(_("invalid IP, mustn't not be in reserved class"))
|
||||
if warnings_only:
|
||||
msg = _("IP shouldn't be in reserved class")
|
||||
else:
|
||||
msg = _("invalid IP, mustn't be in reserved class")
|
||||
raise ValueError(msg)
|
||||
if self._private_only and not ip.iptype() == 'PRIVATE':
|
||||
raise ValueError(_("invalid IP, must be in private class"))
|
||||
if warnings_only:
|
||||
msg = _("IP should be in private class")
|
||||
else:
|
||||
msg = _("invalid IP, must be in private class")
|
||||
raise ValueError(msg)
|
||||
|
||||
def _cons_in_network(self, opts, vals):
|
||||
def _cons_in_network(self, opts, vals, warnings_only):
|
||||
if len(vals) != 3:
|
||||
raise ConfigError(_('invalid len for vals'))
|
||||
if None in vals:
|
||||
return
|
||||
ip, network, netmask = vals
|
||||
if IP(ip) not in IP('{0}/{1}'.format(network, netmask)):
|
||||
raise ValueError(_('invalid IP {0} ({1}) with network {2} '
|
||||
'({3}) and netmask {4} ({5})').format(
|
||||
ip, opts[0]._name, network,
|
||||
opts[1]._name, netmask, opts[2]._name))
|
||||
if warnings_only:
|
||||
msg = _('IP {0} ({1}) not in network {2} ({3}) with netmask {4}'
|
||||
' ({5})')
|
||||
else:
|
||||
msg = _('invalid IP {0} ({1}) not in network {2} ({3}) with '
|
||||
'netmask {4} ({5})')
|
||||
raise ValueError(msg.format(ip, opts[0]._name, network,
|
||||
opts[1]._name, netmask, opts[2]._name))
|
||||
|
||||
|
||||
class PortOption(Option):
|
||||
@ -884,10 +913,14 @@ class NetworkOption(Option):
|
||||
except ValueError:
|
||||
raise ValueError(_('invalid network address'))
|
||||
|
||||
def _second_level_validation(self, value):
|
||||
def _second_level_validation(self, value, warnings_only):
|
||||
ip = IP(value)
|
||||
if ip.iptype() == 'RESERVED':
|
||||
raise ValueError(_("invalid network address, must not be in reserved class"))
|
||||
if warnings_only:
|
||||
msg = _("network address shouldn't be in reserved class")
|
||||
else:
|
||||
msg = _("invalid network address, mustn't be in reserved class")
|
||||
raise ValueError(msg)
|
||||
|
||||
|
||||
class NetmaskOption(Option):
|
||||
@ -901,19 +934,20 @@ class NetmaskOption(Option):
|
||||
except ValueError:
|
||||
raise ValueError(_('invalid netmask address'))
|
||||
|
||||
def _cons_network_netmask(self, opts, vals):
|
||||
def _cons_network_netmask(self, opts, vals, warnings_only):
|
||||
#opts must be (netmask, network) options
|
||||
if None in vals:
|
||||
return
|
||||
self.__cons_netmask(opts, vals[0], vals[1], False)
|
||||
self.__cons_netmask(opts, vals[0], vals[1], False, warnings_only)
|
||||
|
||||
def _cons_ip_netmask(self, opts, vals):
|
||||
def _cons_ip_netmask(self, opts, vals, warnings_only):
|
||||
#opts must be (netmask, ip) options
|
||||
if None in vals:
|
||||
return
|
||||
self.__cons_netmask(opts, vals[0], vals[1], True)
|
||||
self.__cons_netmask(opts, vals[0], vals[1], True, warnings_only)
|
||||
|
||||
def __cons_netmask(self, opts, val_netmask, val_ipnetwork, make_net):
|
||||
def __cons_netmask(self, opts, val_netmask, val_ipnetwork, make_net,
|
||||
warnings_only):
|
||||
if len(opts) != 2:
|
||||
raise ConfigError(_('invalid len for opts'))
|
||||
msg = None
|
||||
@ -950,7 +984,7 @@ class BroadcastOption(Option):
|
||||
except ValueError:
|
||||
raise ValueError(_('invalid broadcast address'))
|
||||
|
||||
def _cons_broadcast(self, opts, vals):
|
||||
def _cons_broadcast(self, opts, vals, warnings_only):
|
||||
if len(vals) != 3:
|
||||
raise ConfigError(_('invalid len for vals'))
|
||||
if None in vals:
|
||||
@ -1047,7 +1081,7 @@ class EmailOption(DomainnameOption):
|
||||
try:
|
||||
username, domain = splitted
|
||||
except ValueError:
|
||||
raise ValueError(_('invalid email address, should contains one @'
|
||||
raise ValueError(_('invalid email address, must contains one @'
|
||||
))
|
||||
if not self.username_re.search(username):
|
||||
raise ValueError(_('invalid username in email address'))
|
||||
@ -1063,7 +1097,7 @@ class URLOption(DomainnameOption):
|
||||
def _validate(self, value):
|
||||
match = self.proto_re.search(value)
|
||||
if not match:
|
||||
raise ValueError(_('invalid url, should start with http:// or '
|
||||
raise ValueError(_('invalid url, must start with http:// or '
|
||||
'https://'))
|
||||
value = value[len(match.group(0)):]
|
||||
# get domain/files
|
||||
@ -1088,7 +1122,7 @@ class URLOption(DomainnameOption):
|
||||
super(URLOption, self)._validate(domain)
|
||||
# validate file
|
||||
if files is not None and files != '' and not self.path_re.search(files):
|
||||
raise ValueError(_('invalid url, should ends with filename'))
|
||||
raise ValueError(_('invalid url, must ends with filename'))
|
||||
|
||||
|
||||
class UsernameOption(Option):
|
||||
@ -1217,11 +1251,12 @@ class OptionDescription(BaseOption):
|
||||
if not force_no_consistencies and \
|
||||
option._consistencies is not None:
|
||||
for consistency in option._consistencies:
|
||||
func, all_cons_opts = consistency
|
||||
func, all_cons_opts, params = consistency
|
||||
for opt in all_cons_opts:
|
||||
_consistencies.setdefault(opt,
|
||||
[]).append((func,
|
||||
all_cons_opts))
|
||||
all_cons_opts,
|
||||
params))
|
||||
else:
|
||||
_currpath.append(attr)
|
||||
option.impl_build_cache(cache_path,
|
||||
@ -1311,18 +1346,29 @@ class OptionDescription(BaseOption):
|
||||
def impl_get_group_type(self):
|
||||
return self._group_type
|
||||
|
||||
def _valid_consistency(self, option, value, context, index):
|
||||
def _valid_consistency(self, option, value, context, index, warnings_only):
|
||||
if self._cache_consistencies is None:
|
||||
return True
|
||||
#consistencies is something like [('_cons_not_equal', (opt1, opt2))]
|
||||
consistencies = self._cache_consistencies.get(option)
|
||||
if consistencies is not None:
|
||||
for func, all_cons_opts in consistencies:
|
||||
for func, all_cons_opts, params in consistencies:
|
||||
if not warnings_only:
|
||||
l_warnings_only = params.get('warnings_only', False)
|
||||
else:
|
||||
l_warnings_only = warnings_only
|
||||
#all_cons_opts[0] is the option where func is set
|
||||
all_cons_opts[0]._launch_consistency(func, option,
|
||||
value,
|
||||
context, index,
|
||||
all_cons_opts)
|
||||
try:
|
||||
all_cons_opts[0]._launch_consistency(func, option,
|
||||
value,
|
||||
context, index,
|
||||
all_cons_opts,
|
||||
l_warnings_only)
|
||||
except ValueError as err:
|
||||
if l_warnings_only:
|
||||
raise ValueWarning(err.message, option)
|
||||
else:
|
||||
raise err
|
||||
|
||||
def _impl_getstate(self, descr=None):
|
||||
"""enables us to export into a dict
|
||||
@ -1432,7 +1478,7 @@ def validate_requires_arg(requires, name):
|
||||
'must be an option in option {0}').format(name))
|
||||
if option.impl_is_multi():
|
||||
raise ValueError(_('malformed requirements option {0} '
|
||||
'should not be a multi').format(name))
|
||||
'must not be a multi').format(name))
|
||||
if expected is not None:
|
||||
try:
|
||||
option._validate(expected)
|
||||
@ -1467,17 +1513,17 @@ def validate_requires_arg(requires, name):
|
||||
|
||||
def validate_callback(callback, callback_params, type_):
|
||||
if type(callback) != FunctionType:
|
||||
raise ValueError(_('{0} should be a function').format(type_))
|
||||
raise ValueError(_('{0} must be a function').format(type_))
|
||||
if callback_params is not None:
|
||||
if not isinstance(callback_params, dict):
|
||||
raise ValueError(_('{0}_params should be a dict').format(type_))
|
||||
raise ValueError(_('{0}_params must be a dict').format(type_))
|
||||
for key, callbacks in callback_params.items():
|
||||
if key != '' and len(callbacks) != 1:
|
||||
raise ValueError(_('{0}_params with key {1} should not have '
|
||||
'length different to 1').format(type_,
|
||||
raise ValueError(_("{0}_params with key {1} mustn't have "
|
||||
"length different to 1").format(type_,
|
||||
key))
|
||||
if not isinstance(callbacks, tuple):
|
||||
raise ValueError(_('{0}_params should be tuple for key "{1}"'
|
||||
raise ValueError(_('{0}_params must be tuple for key "{1}"'
|
||||
).format(type_, key))
|
||||
for callbk in callbacks:
|
||||
if isinstance(callbk, tuple):
|
||||
@ -1486,11 +1532,11 @@ def validate_callback(callback, callback_params, type_):
|
||||
raise ValueError(_('validator not support tuple'))
|
||||
if not isinstance(option, Option) and not \
|
||||
isinstance(option, SymLinkOption):
|
||||
raise ValueError(_('{0}_params should have an option '
|
||||
raise ValueError(_('{0}_params must have an option '
|
||||
'not a {0} for first argument'
|
||||
).format(type_, type(option)))
|
||||
if force_permissive not in [True, False]:
|
||||
raise ValueError(_('{0}_params should have a boolean'
|
||||
raise ValueError(_('{0}_params must have a boolean'
|
||||
' not a {0} for second argument'
|
||||
).format(type_, type(
|
||||
force_permissive)))
|
||||
|
Reference in New Issue
Block a user