can set valid value for an option with invalid consistency
This commit is contained in:
parent
165b28cb00
commit
50a2ab4186
|
@ -316,11 +316,33 @@ def test_consistency_not_equal_multi():
|
|||
raises(ValueError, "api.option('b').value.set([2, 3])")
|
||||
|
||||
|
||||
def test_consistency_not_equal_multi_default():
|
||||
def test_consistency_not_equal_multi_default1():
|
||||
a = IntOption('a', '', multi=True, default=[1])
|
||||
b = IntOption('b', '', multi=True, default=[1, 2])
|
||||
b = IntOption('b', '', multi=True, default=[3, 1])
|
||||
od = OptionDescription('a', '', [a, b])
|
||||
raises(ValueError, "a.impl_add_consistency('not_equal', b)")
|
||||
raises(ValueError, "b.impl_add_consistency('not_equal', a)")
|
||||
|
||||
|
||||
def test_consistency_not_equal_multi_default2():
|
||||
a = IntOption('a', '', multi=True, default=[1])
|
||||
b = IntOption('b', '', multi=True, default_multi=1)
|
||||
od = OptionDescription('a', '', [a, b])
|
||||
#default_multi not tested now
|
||||
a.impl_add_consistency('not_equal', b)
|
||||
|
||||
|
||||
def test_consistency_not_equal_master_default():
|
||||
a = IntOption('a', '', multi=True, default=[2, 1])
|
||||
b = IntOption('b', '', multi=True, default_multi=1)
|
||||
od = MasterSlaves('a', '', [a, b])
|
||||
a.impl_add_consistency('not_equal', b)
|
||||
od2 = OptionDescription('a', '', [od])
|
||||
api = getapi(Config(od2))
|
||||
# default_multi not tested
|
||||
raises(ValueError, "api.option('a.b', 0).value.get()")
|
||||
api.option('a.b', 0).value.set(3)
|
||||
api.option('a.b', 1).value.set(3)
|
||||
assert api.option('a.b', 1).value.get() == 3
|
||||
|
||||
|
||||
def test_consistency_not_equal_multi_default_modif():
|
||||
|
@ -417,24 +439,26 @@ def test_consistency_ip_in_network():
|
|||
assert len(w) == 1
|
||||
|
||||
|
||||
def test_consistency_ip_in_network_len_error():
|
||||
a = NetworkOption('a', '')
|
||||
b = NetmaskOption('b', '')
|
||||
c = IPOption('c', '')
|
||||
od = OptionDescription('od', '', [a, b, c])
|
||||
raises(ConfigError, "c.impl_add_consistency('in_network', a)")
|
||||
# needs 3 arguments, not 2
|
||||
#def test_consistency_ip_in_network_len_error():
|
||||
# a = NetworkOption('a', '')
|
||||
# b = NetmaskOption('b', '')
|
||||
# c = IPOption('c', '')
|
||||
# od = OptionDescription('od', '', [a, b, c])
|
||||
# raises(ConfigError, "c.impl_add_consistency('in_network', a)")
|
||||
|
||||
|
||||
def test_consistency_ip_netmask_network_error():
|
||||
a = IPOption('a', '')
|
||||
b = NetworkOption('b', '')
|
||||
c = NetmaskOption('c', '')
|
||||
od = OptionDescription('od', '', [a, b, c])
|
||||
c.impl_add_consistency('ip_netmask', a, b)
|
||||
api = getapi(Config(od))
|
||||
api.option('a').value.set('192.168.1.1')
|
||||
api.option('b').value.set('192.168.1.0')
|
||||
raises(ConfigError, "api.option('c').value.set('255.255.255.0')")
|
||||
# needs 2 arguments, not 3
|
||||
#def test_consistency_ip_netmask_network_error():
|
||||
# a = IPOption('a', '')
|
||||
# b = NetworkOption('b', '')
|
||||
# c = NetmaskOption('c', '')
|
||||
# od = OptionDescription('od', '', [a, b, c])
|
||||
# c.impl_add_consistency('ip_netmask', a, b)
|
||||
# api = getapi(Config(od))
|
||||
# api.option('a').value.set('192.168.1.1')
|
||||
# api.option('b').value.set('192.168.1.0')
|
||||
# raises(ConfigError, "api.option('c').value.set('255.255.255.0')")
|
||||
|
||||
|
||||
def test_consistency_ip_netmask_error_multi():
|
||||
|
|
|
@ -30,10 +30,10 @@ from .option import ChoiceOption
|
|||
TIRAMISU_VERSION = 3
|
||||
|
||||
|
||||
try:
|
||||
from .value import Multi
|
||||
except:
|
||||
Multi = list
|
||||
#try:
|
||||
# from .value import Multi
|
||||
#except:
|
||||
# Multi = list
|
||||
|
||||
|
||||
COUNT_TIME = False
|
||||
|
@ -532,8 +532,8 @@ class TiramisuOptionValue(CommonTiramisuOption):
|
|||
value = self.subconfig.getattr(self._name,
|
||||
self.index,
|
||||
self.config_bag)
|
||||
if isinstance(value, Multi):
|
||||
value = list(value)
|
||||
#if isinstance(value, Multi):
|
||||
# value = list(value)
|
||||
return value
|
||||
|
||||
@count
|
||||
|
|
|
@ -75,6 +75,7 @@ class SubConfig(object):
|
|||
masterpath = master.impl_getname()
|
||||
mconfig_bag = config_bag.copy('nooption')
|
||||
mconfig_bag.option = master
|
||||
mconfig_bag.validate = False
|
||||
value = self.getattr(masterpath,
|
||||
None,
|
||||
mconfig_bag)
|
||||
|
|
|
@ -102,9 +102,7 @@ class IPOption(Option):
|
|||
opts,
|
||||
vals,
|
||||
warnings_only):
|
||||
if len(vals) != 3:
|
||||
raise ConfigError(_('invalid len for vals'))
|
||||
if None in vals:
|
||||
if len(vals) != 3 or None in vals:
|
||||
return
|
||||
ip, network, netmask = vals
|
||||
if IP(ip) not in IP('{0}/{1}'.format(network,
|
||||
|
|
|
@ -52,13 +52,15 @@ class NetmaskOption(Option):
|
|||
vals,
|
||||
warnings_only):
|
||||
#opts must be (netmask, network) options
|
||||
if None in vals:
|
||||
if len(vals) != 2 or None in vals:
|
||||
return
|
||||
return self.__cons_netmask(opts,
|
||||
return self.__cons_netmask(current_opt,
|
||||
opts,
|
||||
vals[0],
|
||||
vals[1],
|
||||
False,
|
||||
warnings_only)
|
||||
warnings_only,
|
||||
'network')
|
||||
|
||||
def _cons_ip_netmask(self,
|
||||
current_opt,
|
||||
|
@ -66,20 +68,24 @@ class NetmaskOption(Option):
|
|||
vals,
|
||||
warnings_only):
|
||||
#opts must be (netmask, ip) options
|
||||
if None in vals:
|
||||
if len(vals) != 2 or None in vals:
|
||||
return
|
||||
self.__cons_netmask(opts,
|
||||
self.__cons_netmask(current_opt,
|
||||
opts,
|
||||
vals[0],
|
||||
vals[1],
|
||||
True,
|
||||
warnings_only)
|
||||
warnings_only,
|
||||
'ip')
|
||||
|
||||
def __cons_netmask(self,
|
||||
current_opt,
|
||||
opts,
|
||||
val_netmask,
|
||||
val_ipnetwork,
|
||||
make_net,
|
||||
warnings_only):
|
||||
warnings_only,
|
||||
typ):
|
||||
if len(opts) != 2:
|
||||
raise ConfigError(_('invalid len for opts'))
|
||||
msg = None
|
||||
|
@ -95,7 +101,10 @@ class NetmaskOption(Option):
|
|||
|
||||
except ValueError:
|
||||
if not make_net:
|
||||
msg = _('with netmask "{0}" ("{1}")')
|
||||
if current_opt == opts[1]:
|
||||
raise ValueError(_('with netmask "{0}" ("{1}")').format(val_netmask, opts[0].impl_get_display_name()))
|
||||
else:
|
||||
raise ValueError(_('with {2} "{0}" ("{1}")').format(val_ipnetwork, opts[1].impl_get_display_name(), typ))
|
||||
if msg is not None:
|
||||
raise ValueError(msg.format(val_netmask,
|
||||
opts[1].impl_get_display_name()))
|
||||
|
|
|
@ -199,13 +199,19 @@ class Option(OnlyOption):
|
|||
if current_opt is undefined:
|
||||
current_opt = self
|
||||
|
||||
if config_bag is not undefined and \
|
||||
((check_error is True and not 'validator' in config_bag.setting_properties) or \
|
||||
(check_error is False and not 'warnings' in config_bag.setting_properties)):
|
||||
if check_error and config_bag is not undefined and \
|
||||
not config_bag.validate:
|
||||
# just to check propertieserror
|
||||
self.valid_consistency(current_opt,
|
||||
value,
|
||||
context,
|
||||
force_index,
|
||||
check_error,
|
||||
config_bag)
|
||||
return
|
||||
|
||||
def _is_not_unique(value):
|
||||
#FIXME pourquoi la longueur doit etre egal ???
|
||||
#FIXME pourquoi la longueur doit etre egal ?
|
||||
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:]:
|
||||
|
@ -303,7 +309,7 @@ class Option(OnlyOption):
|
|||
do_validation(val,
|
||||
idx)
|
||||
|
||||
self._valid_consistency(current_opt,
|
||||
self.valid_consistency(current_opt,
|
||||
value,
|
||||
context,
|
||||
force_index,
|
||||
|
@ -458,7 +464,7 @@ class Option(OnlyOption):
|
|||
self._add_dependency(opt)
|
||||
opt._add_dependency(self)
|
||||
|
||||
def _valid_consistency(self,
|
||||
def valid_consistency(self,
|
||||
option,
|
||||
value,
|
||||
context,
|
||||
|
@ -494,7 +500,7 @@ class Option(OnlyOption):
|
|||
else:
|
||||
opts = all_cons_opts
|
||||
wopt = opts[0]()
|
||||
wopt._launch_consistency(self,
|
||||
wopt.launch_consistency(self,
|
||||
func,
|
||||
cons_id,
|
||||
option,
|
||||
|
@ -506,7 +512,47 @@ class Option(OnlyOption):
|
|||
transitive,
|
||||
config_bag)
|
||||
|
||||
def _launch_consistency(self,
|
||||
def _get_consistency_value(self,
|
||||
orig_option,
|
||||
current_option,
|
||||
index,
|
||||
cons_id,
|
||||
context,
|
||||
config_bag,
|
||||
value,
|
||||
transitive,
|
||||
func):
|
||||
if func in ALLOWED_CONST_LIST:
|
||||
index = None
|
||||
index_ = None
|
||||
elif not current_option.impl_is_master_slaves('slave'):
|
||||
index_ = None
|
||||
else:
|
||||
index_ = index
|
||||
if orig_option == current_option:
|
||||
# orig_option is current option
|
||||
# we have already value, so use it
|
||||
return value
|
||||
if context is undefined:
|
||||
#if no context get default value
|
||||
return current_option.impl_getdefault()
|
||||
#otherwise calculate value
|
||||
sconfig_bag = config_bag.copy('nooption')
|
||||
sconfig_bag.option = current_option
|
||||
sconfig_bag.fromconsistency.append(cons_id)
|
||||
sconfig_bag.force_permissive = True
|
||||
path = current_option.impl_getpath(context)
|
||||
opt_value = context.getattr(path,
|
||||
index_,
|
||||
sconfig_bag)
|
||||
if index_ is None and index is not None:
|
||||
if len(opt_value) <= index:
|
||||
opt_value = current_option.impl_getdefault_multi()
|
||||
else:
|
||||
opt_value = opt_value[index]
|
||||
return opt_value
|
||||
|
||||
def launch_consistency(self,
|
||||
current_opt,
|
||||
func,
|
||||
cons_id,
|
||||
|
@ -537,8 +583,8 @@ class Option(OnlyOption):
|
|||
:param transitive: propertyerror is transitive
|
||||
:type transitive: `boolean`
|
||||
"""
|
||||
if context is not undefined:
|
||||
descr = context.cfgimpl_get_description()
|
||||
#if context is not undefined:
|
||||
# descr = context.cfgimpl_get_description()
|
||||
if config_bag is not undefined and cons_id in config_bag.fromconsistency:
|
||||
return
|
||||
all_cons_vals = []
|
||||
|
@ -547,44 +593,27 @@ class Option(OnlyOption):
|
|||
for opt in opts:
|
||||
if isinstance(opt, weakref.ReferenceType):
|
||||
opt = opt()
|
||||
if option == opt:
|
||||
# option is current option
|
||||
# we have already value, so use it
|
||||
opt_value = value
|
||||
elif context is undefined:
|
||||
opt_value = opt.impl_getdefault()
|
||||
else:
|
||||
#if context, calculate value, otherwise get default value
|
||||
sconfig_bag = config_bag.copy('nooption')
|
||||
sconfig_bag.option = opt
|
||||
sconfig_bag.fromconsistency.append(cons_id)
|
||||
sconfig_bag.force_permissive = True
|
||||
path = opt.impl_getpath(context)
|
||||
if opt.impl_is_master_slaves('slave'):
|
||||
index_ = index
|
||||
else:
|
||||
index_ = None
|
||||
is_multi = False
|
||||
try:
|
||||
opt_value = context.getattr(path,
|
||||
index_,
|
||||
sconfig_bag)
|
||||
opt_value = self._get_consistency_value(option,
|
||||
opt,
|
||||
index,
|
||||
cons_id,
|
||||
context,
|
||||
config_bag,
|
||||
value,
|
||||
transitive,
|
||||
func)
|
||||
except PropertiesOptionError as err:
|
||||
if debug: # pragma: no cover
|
||||
log.debug('propertyerror in _launch_consistency: {0}'.format(err))
|
||||
log.debug('propertyerror in launch_consistency: {0}'.format(err))
|
||||
if transitive:
|
||||
err.set_orig_opt(option)
|
||||
raise err
|
||||
opt_value = None
|
||||
if not option == opt and opt_value is not None and index is not None and \
|
||||
(context is undefined or \
|
||||
not opt.impl_is_master_slaves('slave')):
|
||||
if len(opt_value) <= index:
|
||||
opt_value = opt.impl_getdefault_multi()
|
||||
else:
|
||||
opt_value = opt_value[index]
|
||||
|
||||
if opt_value is not None and opt.impl_is_multi() and index is None and func not in ALLOWED_CONST_LIST:
|
||||
if length is not None and length != len(opt_value):
|
||||
if opt.impl_is_multi() and index is None and func not in ALLOWED_CONST_LIST:
|
||||
len_value = len(opt_value)
|
||||
if length is not None and length != len_value:
|
||||
if context is undefined:
|
||||
return
|
||||
raise ValueError(_('unexpected length of "{}" in constency "{}", should be "{}"'
|
||||
|
@ -592,13 +621,11 @@ class Option(OnlyOption):
|
|||
opt.impl_get_display_name(),
|
||||
length))
|
||||
else:
|
||||
length = len(opt_value)
|
||||
length = len_value
|
||||
is_multi = True
|
||||
else:
|
||||
is_multi = False
|
||||
if isinstance(opt_value, list) and func in ALLOWED_CONST_LIST:
|
||||
for value_ in opt_value:
|
||||
if isinstance(value_, list):
|
||||
if opt.impl_is_submulti():
|
||||
for val in value_:
|
||||
all_cons_vals.append((False, val))
|
||||
all_cons_opts.append(opt)
|
||||
|
@ -608,8 +635,8 @@ class Option(OnlyOption):
|
|||
else:
|
||||
all_cons_vals.append((is_multi, opt_value))
|
||||
all_cons_opts.append(opt)
|
||||
else:
|
||||
try:
|
||||
if config_bag is not undefined and not config_bag.validate:
|
||||
return
|
||||
all_values = []
|
||||
if length is None:
|
||||
all_value = []
|
||||
|
@ -625,6 +652,7 @@ class Option(OnlyOption):
|
|||
else:
|
||||
all_value.append(values[idx])
|
||||
all_values.append(all_value)
|
||||
try:
|
||||
for values in all_values:
|
||||
getattr(self, func)(current_opt,
|
||||
all_cons_opts,
|
||||
|
|
|
@ -124,36 +124,53 @@ class ConfigBag(object):
|
|||
'option',
|
||||
'ori_option',
|
||||
'properties',
|
||||
'validate',
|
||||
'setting_properties',
|
||||
'force_permissive',
|
||||
'force_unrestraint',
|
||||
'display_warnings',
|
||||
'trusted_cached_properties',
|
||||
'fromconsistency',
|
||||
'_validator'
|
||||
)
|
||||
def __init__(self, config, **kwargs):
|
||||
self.default = {'force_permissive': False,
|
||||
'force_unrestraint': False,
|
||||
'display_warnings': True,
|
||||
'trusted_cached_properties': True,
|
||||
}
|
||||
self.config = config
|
||||
self._validator = True
|
||||
self.fromconsistency = []
|
||||
for key, value in kwargs.items():
|
||||
if value != self.default.get(key):
|
||||
setattr(self, key, value)
|
||||
|
||||
def __getattr__(self, key):
|
||||
if key in ['validate', 'validate_properties']:
|
||||
if key == 'validate_properties':
|
||||
return not self.force_unrestraint
|
||||
if key == 'validate':
|
||||
if self.setting_properties is not None:
|
||||
return 'validator' in self.setting_properties
|
||||
return self._validator
|
||||
if key == 'setting_properties':
|
||||
if self.force_unrestraint:
|
||||
return None
|
||||
self.setting_properties = self.config.cfgimpl_get_settings().get_context_properties()
|
||||
return self.setting_properties
|
||||
if key not in self.__slots__:
|
||||
raise KeyError('unknown key {}'.format(key))
|
||||
return self.default.get(key)
|
||||
|
||||
def __setattr__(self, key, value):
|
||||
if key == 'validate':
|
||||
if self.setting_properties is not None:
|
||||
if value is False:
|
||||
self.setting_properties = frozenset(set(self.setting_properties) - {'validator'})
|
||||
else:
|
||||
self.setting_properties = frozenset(set(self.setting_properties) | {'validator'})
|
||||
else:
|
||||
self._validator = value
|
||||
else:
|
||||
super().__setattr__(key, value)
|
||||
|
||||
def delete(self, key):
|
||||
try:
|
||||
return self.__delattr__(key)
|
||||
|
|
|
@ -100,9 +100,7 @@ class Values(object):
|
|||
value = self.getvalue(path,
|
||||
index,
|
||||
config_bag)
|
||||
#FIXME suboptimal ...
|
||||
# validate value
|
||||
if config_bag.validate:
|
||||
context = self._getcontext()
|
||||
opt = config_bag.option
|
||||
opt.impl_validate(value,
|
||||
|
@ -110,7 +108,7 @@ class Values(object):
|
|||
force_index=index,
|
||||
check_error=True,
|
||||
config_bag=config_bag)
|
||||
if config_bag.display_warnings:
|
||||
if setting_properties and 'warnings' in setting_properties:
|
||||
opt.impl_validate(value,
|
||||
context=context,
|
||||
force_index=index,
|
||||
|
@ -178,7 +176,7 @@ class Values(object):
|
|||
#so return default value
|
||||
else:
|
||||
return value
|
||||
return self._getdefaultvalue(path,
|
||||
return self.getdefaultvalue(path,
|
||||
index,
|
||||
config_bag)
|
||||
|
||||
|
@ -197,14 +195,6 @@ class Values(object):
|
|||
:type index: int
|
||||
:returns: default value
|
||||
"""
|
||||
return self._getdefaultvalue(path,
|
||||
index,
|
||||
config_bag)
|
||||
|
||||
def _getdefaultvalue(self,
|
||||
path,
|
||||
index,
|
||||
config_bag):
|
||||
context = self._getcontext()
|
||||
opt = config_bag.option
|
||||
def _reset_cache(_value):
|
||||
|
@ -325,9 +315,7 @@ class Values(object):
|
|||
|
||||
context = self._getcontext()
|
||||
owner = context.cfgimpl_get_settings().getowner()
|
||||
if config_bag.setting_properties is not None and \
|
||||
'validator' in config_bag.setting_properties and \
|
||||
config_bag.validate:
|
||||
if config_bag.validate:
|
||||
if index is not None or config_bag.option._has_consistencies(context):
|
||||
# set value to a fake config when option has dependency
|
||||
# validation will be complet in this case (consistency, ...)
|
||||
|
@ -365,7 +353,7 @@ class Values(object):
|
|||
context = self._getcontext()
|
||||
settings = context.cfgimpl_get_settings()
|
||||
# First validate properties with this value
|
||||
self_properties = config_bag.self_properties
|
||||
self_properties = config_bag.properties
|
||||
if self_properties is None:
|
||||
self_properties = settings.getproperties(path,
|
||||
index,
|
||||
|
@ -385,6 +373,7 @@ class Values(object):
|
|||
context,
|
||||
check_error=True,
|
||||
force_index=index)
|
||||
if config_bag.setting_properties and 'warnings' in config_bag.setting_properties:
|
||||
# No error found so emit warnings
|
||||
opt.impl_validate(value,
|
||||
config_bag,
|
||||
|
@ -555,14 +544,14 @@ class Values(object):
|
|||
setting = context.cfgimpl_get_settings()
|
||||
hasvalue = self._p_.hasvalue(path)
|
||||
|
||||
if config_bag.validate and hasvalue and 'validator' in config_bag.setting_properties:
|
||||
if hasvalue and config_bag.validate:
|
||||
fake_context = context._gen_fake_values()
|
||||
fake_value = fake_context.cfgimpl_get_values()
|
||||
sconfig_bag = config_bag.copy()
|
||||
sconfig_bag.validate = False
|
||||
fake_value.reset(path,
|
||||
sconfig_bag)
|
||||
value = fake_value._getdefaultvalue(path,
|
||||
value = fake_value.getdefaultvalue(path,
|
||||
None,
|
||||
config_bag)
|
||||
fake_value.setvalue_validation(path,
|
||||
|
@ -578,7 +567,7 @@ class Values(object):
|
|||
if 'force_store_value' in setting.getproperties(path,
|
||||
None,
|
||||
config_bag):
|
||||
value = self._getdefaultvalue(path,
|
||||
value = self.getdefaultvalue(path,
|
||||
None,
|
||||
config_bag)
|
||||
self._setvalue(path,
|
||||
|
@ -601,7 +590,7 @@ class Values(object):
|
|||
|
||||
if self._p_.hasvalue(path, index=index):
|
||||
context = self._getcontext()
|
||||
if config_bag.validate and 'validator' in config_bag.setting_properties:
|
||||
if config_bag.validate:
|
||||
fake_context = context._gen_fake_values()
|
||||
fake_value = fake_context.cfgimpl_get_values()
|
||||
sconfig_bag = config_bag.copy()
|
||||
|
@ -609,7 +598,7 @@ class Values(object):
|
|||
fake_value.reset_slave(path,
|
||||
index,
|
||||
sconfig_bag)
|
||||
value = fake_value._getdefaultvalue(path,
|
||||
value = fake_value.getdefaultvalue(path,
|
||||
index,
|
||||
config_bag)
|
||||
fake_value.setvalue_validation(path,
|
||||
|
@ -756,11 +745,10 @@ class Values(object):
|
|||
context = self._getcontext()
|
||||
# copy
|
||||
od_setting_properties = config_bag.setting_properties - {'mandatory', 'empty'}
|
||||
setting_properties = set(config_bag.setting_properties)
|
||||
setting_properties = set(config_bag.setting_properties) - {'warnings'}
|
||||
setting_properties.update(['mandatory', 'empty'])
|
||||
config_bag.setting_properties = frozenset(setting_properties)
|
||||
config_bag.force_permissive = True
|
||||
config_bag.display_warnings = False
|
||||
|
||||
descr = context.cfgimpl_get_description()
|
||||
return self._mandatory_warnings(context,
|
||||
|
|
Loading…
Reference in New Issue