tiramisu/option.py:
separate _consistencies (for Option) and _cache_consistencies (for OptionDescription) _launch_consistency need index for multi's option _cons_not_equal support multi options tiramisu/value.py: Multi._validate support consistency
This commit is contained in:
parent
482dfec7f2
commit
70f684e70c
|
@ -5,6 +5,7 @@ from tiramisu.setting import owners, groups
|
|||
from tiramisu.config import Config
|
||||
from tiramisu.option import IPOption, NetworkOption, NetmaskOption, IntOption,\
|
||||
BroadcastOption, SymLinkOption, OptionDescription
|
||||
from tiramisu.error import ConfigError
|
||||
|
||||
|
||||
def test_consistency_not_equal():
|
||||
|
@ -22,6 +23,60 @@ def test_consistency_not_equal():
|
|||
c.b = 2
|
||||
|
||||
|
||||
def test_consistency_not_equal_many_opts():
|
||||
a = IntOption('a', '')
|
||||
b = IntOption('b', '')
|
||||
c = IntOption('c', '')
|
||||
d = IntOption('d', '')
|
||||
e = IntOption('e', '')
|
||||
f = IntOption('f', '')
|
||||
od = OptionDescription('od', '', [a, b, c, d, e, f])
|
||||
a.impl_add_consistency('not_equal', b, c, d, e, f)
|
||||
c = Config(od)
|
||||
assert c.a is None
|
||||
assert c.b is None
|
||||
#
|
||||
c.a = 1
|
||||
del(c.a)
|
||||
#
|
||||
c.a = 1
|
||||
raises(ValueError, "c.b = 1")
|
||||
#
|
||||
c.b = 2
|
||||
raises(ValueError, "c.f = 2")
|
||||
raises(ValueError, "c.f = 1")
|
||||
#
|
||||
c.d = 3
|
||||
raises(ValueError, "c.f = 3")
|
||||
raises(ValueError, "c.a = 3")
|
||||
raises(ValueError, "c.c = 3")
|
||||
raises(ValueError, "c.e = 3")
|
||||
|
||||
|
||||
def test_consistency_not_in_config():
|
||||
a = IntOption('a', '')
|
||||
b = IntOption('b', '')
|
||||
a.impl_add_consistency('not_equal', b)
|
||||
od1 = OptionDescription('od1', '', [a])
|
||||
od2 = OptionDescription('od2', '', [b])
|
||||
od = OptionDescription('root', '', [od1])
|
||||
raises(ConfigError, "Config(od)")
|
||||
od = OptionDescription('root', '', [od1, od2])
|
||||
Config(od)
|
||||
#with subconfig
|
||||
raises(ConfigError, "Config(od.od1)")
|
||||
|
||||
|
||||
def test_consistency_afer_config():
|
||||
a = IntOption('a', '')
|
||||
b = IntOption('b', '')
|
||||
od1 = OptionDescription('od1', '', [a])
|
||||
od2 = OptionDescription('od2', '', [b])
|
||||
od = OptionDescription('root', '', [od1, od2])
|
||||
Config(od)
|
||||
raises(AttributeError, "a.impl_add_consistency('not_equal', b)")
|
||||
|
||||
|
||||
def test_consistency_not_equal_symlink():
|
||||
a = IntOption('a', '')
|
||||
b = IntOption('b', '')
|
||||
|
@ -29,7 +84,7 @@ def test_consistency_not_equal_symlink():
|
|||
od = OptionDescription('od', '', [a, b, c])
|
||||
a.impl_add_consistency('not_equal', b)
|
||||
c = Config(od)
|
||||
assert set(od._consistencies.keys()) == set([a, b])
|
||||
assert set(od._cache_consistencies.keys()) == set([a, b])
|
||||
|
||||
|
||||
def test_consistency_not_equal_multi():
|
||||
|
@ -53,6 +108,14 @@ def test_consistency_default():
|
|||
raises(ValueError, "a.impl_add_consistency('not_equal', b)")
|
||||
|
||||
|
||||
def test_consistency_default_multi():
|
||||
a = IntOption('a', '', [2, 1], multi=True)
|
||||
b = IntOption('b', '', [1, 1], multi=True)
|
||||
c = IntOption('c', '', [1, 2], multi=True)
|
||||
raises(ValueError, "a.impl_add_consistency('not_equal', b)")
|
||||
a.impl_add_consistency('not_equal', c)
|
||||
|
||||
|
||||
def test_consistency_default_diff():
|
||||
a = IntOption('a', '', 3)
|
||||
b = IntOption('b', '', 1)
|
||||
|
@ -99,7 +162,7 @@ def test_consistency_ip_netmask_error_multi():
|
|||
a = IPOption('a', '', multi=True)
|
||||
b = NetmaskOption('b', '')
|
||||
od = OptionDescription('od', '', [a, b])
|
||||
raises(ValueError, "b.impl_add_consistency('ip_netmask', a)")
|
||||
raises(ConfigError, "b.impl_add_consistency('ip_netmask', a)")
|
||||
|
||||
|
||||
def test_consistency_ip_netmask_multi():
|
||||
|
@ -170,11 +233,42 @@ def test_consistency_broadcast():
|
|||
b.impl_add_consistency('network_netmask', a)
|
||||
c.impl_add_consistency('broadcast', a, b)
|
||||
c = Config(od)
|
||||
#first, test network_netmask
|
||||
c.a = ['192.168.1.128']
|
||||
raises(ValueError, "c.b = ['255.255.255.0']")
|
||||
#
|
||||
c.a = ['192.168.1.0']
|
||||
c.b = ['255.255.255.0']
|
||||
c.c = ['192.168.1.255']
|
||||
raises(ValueError, "c.a = ['192.168.1.1']")
|
||||
#
|
||||
c.a = ['192.168.1.0', '192.168.2.128']
|
||||
c.b = ['255.255.255.0', '255.255.255.128']
|
||||
c.c = ['192.168.1.255', '192.168.2.255']
|
||||
raises(ValueError, "c.c[1] = '192.168.2.128'")
|
||||
c.c[1] = '192.168.2.255'
|
||||
|
||||
|
||||
def test_consistency_broadcast_default():
|
||||
a = NetworkOption('a', '', '192.168.1.0')
|
||||
b = NetmaskOption('b', '', '255.255.255.128')
|
||||
c = BroadcastOption('c', '', '192.168.2.127')
|
||||
d = BroadcastOption('d', '', '192.168.1.127')
|
||||
od = OptionDescription('a', '', [a, b, c])
|
||||
raises(ValueError, "c.impl_add_consistency('broadcast', a, b)")
|
||||
od2 = OptionDescription('a', '', [a, b, d])
|
||||
d.impl_add_consistency('broadcast', a, b)
|
||||
|
||||
|
||||
def test_consistency_not_all():
|
||||
#_cache_consistencies is not None by not options has consistencies
|
||||
a = NetworkOption('a', '', multi=True)
|
||||
b = NetmaskOption('b', '', multi=True)
|
||||
c = BroadcastOption('c', '', multi=True)
|
||||
od = OptionDescription('a', '', [a, b, c])
|
||||
od.impl_set_group_type(groups.master)
|
||||
b.impl_add_consistency('network_netmask', a)
|
||||
c = Config(od)
|
||||
c.a = ['192.168.1.0']
|
||||
c.b = ['255.255.255.0']
|
||||
c.c = ['192.168.1.255']
|
||||
|
|
|
@ -40,7 +40,7 @@ def _diff_opt(opt1, opt2):
|
|||
if diff2 != set():
|
||||
raise Exception('more attribute in opt2 {0}'.format(list(diff2)))
|
||||
for attr in attr1:
|
||||
if attr in ['_cache_paths']:
|
||||
if attr in ['_cache_paths', '_cache_consistencies']:
|
||||
continue
|
||||
err1 = False
|
||||
err2 = False
|
||||
|
|
|
@ -61,9 +61,8 @@ class BaseOption(object):
|
|||
__setattr__ method
|
||||
"""
|
||||
__slots__ = ('_name', '_requires', '_properties', '_readonly',
|
||||
'_consistencies', '_calc_properties', '_impl_informations',
|
||||
'_state_consistencies', '_state_readonly', '_state_requires',
|
||||
'_stated')
|
||||
'_calc_properties', '_impl_informations',
|
||||
'_state_readonly', '_state_requires', '_stated')
|
||||
|
||||
def __init__(self, name, doc, requires, properties):
|
||||
if not valid_name(name):
|
||||
|
@ -73,7 +72,6 @@ class BaseOption(object):
|
|||
self.impl_set_information('doc', doc)
|
||||
self._calc_properties, self._requires = validate_requires_arg(
|
||||
requires, self._name)
|
||||
self._consistencies = None
|
||||
if properties is None:
|
||||
properties = tuple()
|
||||
if not isinstance(properties, tuple):
|
||||
|
@ -98,8 +96,7 @@ class BaseOption(object):
|
|||
"frozen" (which has noting to do with the high level "freeze"
|
||||
propertie or "read_only" property)
|
||||
"""
|
||||
if not name.startswith('_state') and name not in ('_cache_paths',
|
||||
'_consistencies'):
|
||||
if not name.startswith('_state') and not name.startswith('_cache'):
|
||||
is_readonly = False
|
||||
# never change _name
|
||||
if name == '_name':
|
||||
|
@ -109,15 +106,12 @@ class BaseOption(object):
|
|||
is_readonly = True
|
||||
except:
|
||||
pass
|
||||
elif name != '_readonly':
|
||||
try:
|
||||
if self._readonly is True:
|
||||
if value is True:
|
||||
# already readonly and try to re set readonly
|
||||
# don't raise, just exit
|
||||
return
|
||||
is_readonly = True
|
||||
except AttributeError:
|
||||
pass
|
||||
self._readonly = False
|
||||
if is_readonly:
|
||||
raise AttributeError(_("'{0}' ({1}) object attribute '{2}' is"
|
||||
" read-only").format(
|
||||
|
@ -149,57 +143,6 @@ class BaseOption(object):
|
|||
raise ValueError(_("information's item not found: {0}").format(
|
||||
key))
|
||||
|
||||
# serialize/unserialize
|
||||
def _impl_convert_consistencies(self, descr, load=False):
|
||||
"""during serialization process, many things have to be done.
|
||||
one of them is the localisation of the options.
|
||||
The paths are set once for all.
|
||||
|
||||
:type descr: :class:`tiramisu.option.OptionDescription`
|
||||
:param load: `True` if we are at the init of the option description
|
||||
:type load: bool
|
||||
"""
|
||||
if not load and self._consistencies is None:
|
||||
self._state_consistencies = None
|
||||
elif load and self._state_consistencies is None:
|
||||
self._consistencies = None
|
||||
del(self._state_consistencies)
|
||||
else:
|
||||
if load:
|
||||
consistencies = self._state_consistencies
|
||||
else:
|
||||
consistencies = self._consistencies
|
||||
if isinstance(consistencies, list):
|
||||
new_value = []
|
||||
for consistency in consistencies:
|
||||
values = []
|
||||
for obj in consistency[1]:
|
||||
if load:
|
||||
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)))
|
||||
|
||||
else:
|
||||
new_value = {}
|
||||
for key, _consistencies in consistencies.items():
|
||||
new_value[key] = []
|
||||
for key_cons, _cons in _consistencies:
|
||||
_list_cons = []
|
||||
for _con in _cons:
|
||||
if load:
|
||||
_list_cons.append(
|
||||
descr.impl_get_opt_by_path(_con))
|
||||
else:
|
||||
_list_cons.append(
|
||||
descr.impl_get_path_by_opt(_con))
|
||||
new_value[key].append((key_cons, tuple(_list_cons)))
|
||||
if load:
|
||||
del(self._state_consistencies)
|
||||
self._consistencies = new_value
|
||||
else:
|
||||
self._state_consistencies = new_value
|
||||
|
||||
def _impl_convert_requires(self, descr, load=False):
|
||||
"""export of the requires during the serialization process
|
||||
|
||||
|
@ -245,10 +188,7 @@ class BaseOption(object):
|
|||
for func in dir(self):
|
||||
if func.startswith('_impl_convert_'):
|
||||
getattr(self, func)(descr)
|
||||
try:
|
||||
self._state_readonly = self._readonly
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
def __getstate__(self, stated=True):
|
||||
"""special method to enable the serialization with pickle
|
||||
|
@ -268,7 +208,8 @@ class BaseOption(object):
|
|||
for subclass in self.__class__.__mro__:
|
||||
if subclass is not object:
|
||||
slots.update(subclass.__slots__)
|
||||
slots -= frozenset(['_cache_paths', '__weakref__'])
|
||||
slots -= frozenset(['_cache_paths', '_cache_consistencies',
|
||||
'__weakref__'])
|
||||
states = {}
|
||||
for slot in slots:
|
||||
# remove variable if save variable converted
|
||||
|
@ -327,7 +268,8 @@ class Option(BaseOption):
|
|||
"""
|
||||
__slots__ = ('_multi', '_validator', '_default_multi', '_default',
|
||||
'_state_callback', '_callback', '_multitype',
|
||||
'_warnings_only', '_master_slaves', '__weakref__')
|
||||
'_consistencies', '_warnings_only', '_master_slaves',
|
||||
'_state_consistencies', '__weakref__')
|
||||
_empty = ''
|
||||
|
||||
def __init__(self, name, doc, default=None, default_multi=None,
|
||||
|
@ -393,66 +335,58 @@ class Option(BaseOption):
|
|||
self._warnings_only = warnings_only
|
||||
self.impl_validate(default)
|
||||
self._default = default
|
||||
self._consistencies = None
|
||||
|
||||
def _launch_consistency(self, func, right_opt, right_val, context, index,
|
||||
left_opts):
|
||||
def _launch_consistency(self, func, option, value, context, index,
|
||||
all_cons_opts):
|
||||
"""Launch consistency now
|
||||
|
||||
:param func: function name, this name should start with _cons_
|
||||
:type func: `str`
|
||||
:param option: option that value is changing
|
||||
:type option: `tiramisu.option.Option`
|
||||
:param value: new value of this option
|
||||
:param context: Config's context, if None, check default value instead
|
||||
:type context: `tiramisu.config.Config`
|
||||
:param index: only for multi option, consistency should be launch for
|
||||
specified index
|
||||
:type index: `int`
|
||||
:param all_cons_opts: all options concerne by this consistency
|
||||
:type all_cons_opts: `list` of `tiramisu.option.Option`
|
||||
"""
|
||||
if context is not None:
|
||||
descr = context.cfgimpl_get_description()
|
||||
#right_opt is also in left_opts
|
||||
if right_opt not in left_opts:
|
||||
raise ConfigError(_('right_opt not in left_opts'))
|
||||
#option is also in all_cons_opts
|
||||
if option not in all_cons_opts:
|
||||
raise ConfigError(_('option not in all_cons_opts'))
|
||||
|
||||
left_vals = []
|
||||
for opt in left_opts:
|
||||
if right_opt == opt:
|
||||
value = right_val
|
||||
all_cons_vals = []
|
||||
for opt in all_cons_opts:
|
||||
#get value
|
||||
if option == opt:
|
||||
opt_value = value
|
||||
else:
|
||||
#if context, calculate value, otherwise get default value
|
||||
if context is not None:
|
||||
path = descr.impl_get_path_by_opt(opt)
|
||||
value = context._getattr(path, validate=False)
|
||||
opt_value = context._getattr(
|
||||
descr.impl_get_path_by_opt(opt), validate=False)
|
||||
else:
|
||||
value = opt.impl_getdefault()
|
||||
if index is None:
|
||||
#could be multi or not
|
||||
left_vals.append(value)
|
||||
opt_value = opt.impl_getdefault()
|
||||
|
||||
#append value
|
||||
if not self.impl_is_multi() or option == opt:
|
||||
all_cons_vals.append(opt_value)
|
||||
else:
|
||||
#value is not already set, could be higher
|
||||
#value is not already set, could be higher index
|
||||
try:
|
||||
if right_opt == opt:
|
||||
val = value
|
||||
else:
|
||||
val = value[index]
|
||||
if val is None:
|
||||
#no value so no consistencies
|
||||
return
|
||||
left_vals.append(val)
|
||||
all_cons_vals.append(opt_value[index])
|
||||
except IndexError:
|
||||
#so return if no value
|
||||
return
|
||||
|
||||
if self.impl_is_multi():
|
||||
if index is None:
|
||||
for idx, right_v in enumerate(right_val):
|
||||
try:
|
||||
left_v = []
|
||||
for left_val in left_vals:
|
||||
left_v.append(left_val[idx])
|
||||
if None in left_v:
|
||||
continue
|
||||
except IndexError:
|
||||
continue
|
||||
getattr(self, func)(left_opts, left_v)
|
||||
else:
|
||||
if None in left_vals:
|
||||
return
|
||||
getattr(self, func)(left_opts, left_vals)
|
||||
else:
|
||||
if None in left_vals:
|
||||
return
|
||||
getattr(self, func)(left_opts, left_vals)
|
||||
getattr(self, func)(all_cons_opts, all_cons_vals)
|
||||
|
||||
def impl_validate(self, value, context=None, validate=True,
|
||||
force_no_multi=False):
|
||||
force_index=None):
|
||||
"""
|
||||
:param value: the option's value
|
||||
:param context: Config's context
|
||||
|
@ -509,12 +443,11 @@ class Option(BaseOption):
|
|||
if context is not None:
|
||||
descr = context.cfgimpl_get_description()
|
||||
|
||||
if not self._multi or force_no_multi:
|
||||
do_validation(value)
|
||||
if not self._multi or force_index is not None:
|
||||
do_validation(value, force_index)
|
||||
else:
|
||||
if not isinstance(value, list):
|
||||
raise ValueError(_("invalid value {0} for option {1} "
|
||||
"which must be a list").format(value,
|
||||
raise ValueError(_("which must be a list").format(value,
|
||||
self._name))
|
||||
for index, val in enumerate(value):
|
||||
do_validation(val, index)
|
||||
|
@ -561,31 +494,45 @@ class Option(BaseOption):
|
|||
def impl_is_multi(self):
|
||||
return self._multi
|
||||
|
||||
def impl_add_consistency(self, func, *left_opts):
|
||||
def impl_add_consistency(self, func, *other_opts):
|
||||
"""Add consistency means that value will be validate with other_opts
|
||||
option's values.
|
||||
|
||||
:param func: function's name
|
||||
:type func: `str`
|
||||
:param other_opts: options used to validate value
|
||||
:type other_opts: `list` of `tiramisu.option.Option`
|
||||
"""
|
||||
if self._consistencies is None:
|
||||
self._consistencies = []
|
||||
for opt in left_opts:
|
||||
for opt in other_opts:
|
||||
if not isinstance(opt, Option):
|
||||
raise ValueError(_('consistency should be set with an option'))
|
||||
raise ConfigError(_('consistency should be set with an option'))
|
||||
if self is opt:
|
||||
raise ValueError(_('cannot add consistency with itself'))
|
||||
raise ConfigError(_('cannot add consistency with itself'))
|
||||
if self.impl_is_multi() != opt.impl_is_multi():
|
||||
raise ValueError(_('options in consistency should be multi in '
|
||||
'two sides'))
|
||||
raise ConfigError(_('every options in consistency should be '
|
||||
'multi or none'))
|
||||
func = '_cons_{0}'.format(func)
|
||||
opts = tuple([self] + list(left_opts))
|
||||
self._launch_consistency(func, self, self.impl_getdefault(), None,
|
||||
None, opts)
|
||||
self._consistencies.append((func, opts))
|
||||
all_cons_opts = tuple([self] + list(other_opts))
|
||||
value = self.impl_getdefault()
|
||||
if value is not None:
|
||||
if self.impl_is_multi():
|
||||
for idx, val in enumerate(value):
|
||||
self._launch_consistency(func, self, val, None,
|
||||
idx, all_cons_opts)
|
||||
else:
|
||||
self._launch_consistency(func, self, value, None,
|
||||
None, all_cons_opts)
|
||||
self._consistencies.append((func, all_cons_opts))
|
||||
self.impl_validate(self.impl_getdefault())
|
||||
|
||||
def _cons_not_equal(self, opts, vals):
|
||||
if len(opts) != 2:
|
||||
raise ConfigError(_('invalid len for opts'))
|
||||
if vals[0] == vals[1]:
|
||||
raise ValueError(_("invalid value {0} for option {1} "
|
||||
"must be different as {2} option"
|
||||
"").format(vals[0], self._name, opts[1]._name))
|
||||
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))
|
||||
|
||||
def _impl_convert_callbacks(self, descr, load=False):
|
||||
if not load and self._callback is None:
|
||||
|
@ -621,6 +568,57 @@ class Option(BaseOption):
|
|||
else:
|
||||
self._state_callback = (callback, cllbck_prms)
|
||||
|
||||
# serialize/unserialize
|
||||
def _impl_convert_consistencies(self, descr, load=False):
|
||||
"""during serialization process, many things have to be done.
|
||||
one of them is the localisation of the options.
|
||||
The paths are set once for all.
|
||||
|
||||
:type descr: :class:`tiramisu.option.OptionDescription`
|
||||
:param load: `True` if we are at the init of the option description
|
||||
:type load: bool
|
||||
"""
|
||||
if not load and self._consistencies is None:
|
||||
self._state_consistencies = None
|
||||
elif load and self._state_consistencies is None:
|
||||
self._consistencies = None
|
||||
del(self._state_consistencies)
|
||||
else:
|
||||
if load:
|
||||
consistencies = self._state_consistencies
|
||||
else:
|
||||
consistencies = self._consistencies
|
||||
if isinstance(consistencies, list):
|
||||
new_value = []
|
||||
for consistency in consistencies:
|
||||
values = []
|
||||
for obj in consistency[1]:
|
||||
if load:
|
||||
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)))
|
||||
|
||||
else:
|
||||
new_value = {}
|
||||
for key, _consistencies in consistencies.items():
|
||||
new_value[key] = []
|
||||
for key_cons, _cons in _consistencies:
|
||||
_list_cons = []
|
||||
for _con in _cons:
|
||||
if load:
|
||||
_list_cons.append(
|
||||
descr.impl_get_opt_by_path(_con))
|
||||
else:
|
||||
_list_cons.append(
|
||||
descr.impl_get_path_by_opt(_con))
|
||||
new_value[key].append((key_cons, tuple(_list_cons)))
|
||||
if load:
|
||||
del(self._state_consistencies)
|
||||
self._consistencies = new_value
|
||||
else:
|
||||
self._state_consistencies = new_value
|
||||
|
||||
def _second_level_validation(self, value):
|
||||
pass
|
||||
|
||||
|
@ -734,7 +732,7 @@ class SymLinkOption(BaseOption):
|
|||
__slots__ = ('_name', '_opt', '_state_opt')
|
||||
_opt_type = 'symlink'
|
||||
#not return _opt consistencies
|
||||
_consistencies = {}
|
||||
_consistencies = None
|
||||
|
||||
def __init__(self, name, opt):
|
||||
self._name = name
|
||||
|
@ -760,12 +758,6 @@ class SymLinkOption(BaseOption):
|
|||
del(self._state_opt)
|
||||
super(SymLinkOption, self)._impl_setstate(descr)
|
||||
|
||||
def _impl_convert_consistencies(self, descr, load=False):
|
||||
if load:
|
||||
del(self._state_consistencies)
|
||||
else:
|
||||
self._state_consistencies = None
|
||||
|
||||
|
||||
class IPOption(Option):
|
||||
"represents the choice of an ip"
|
||||
|
@ -904,10 +896,14 @@ class NetmaskOption(Option):
|
|||
|
||||
def _cons_network_netmask(self, opts, vals):
|
||||
#opts must be (netmask, network) options
|
||||
if None in vals:
|
||||
return
|
||||
self.__cons_netmask(opts, vals[0], vals[1], False)
|
||||
|
||||
def _cons_ip_netmask(self, opts, vals):
|
||||
#opts must be (netmask, ip) options
|
||||
if None in vals:
|
||||
return
|
||||
self.__cons_netmask(opts, vals[0], vals[1], True)
|
||||
|
||||
def __cons_netmask(self, opts, val_netmask, val_ipnetwork, make_net):
|
||||
|
@ -955,6 +951,8 @@ class BroadcastOption(Option):
|
|||
def _cons_broadcast(self, opts, vals):
|
||||
if len(vals) != 3:
|
||||
raise ConfigError(_('invalid len for vals'))
|
||||
if None in vals:
|
||||
return
|
||||
broadcast, network, netmask = vals
|
||||
if IP('{0}/{1}'.format(network, netmask)).broadcast() != IP(broadcast):
|
||||
raise ValueError(_('invalid broadcast {0} ({1}) with network {2} '
|
||||
|
@ -964,7 +962,12 @@ class BroadcastOption(Option):
|
|||
|
||||
|
||||
class DomainnameOption(Option):
|
||||
"represents the choice of a domain name"
|
||||
"""represents the choice of a domain name
|
||||
netbios: for MS domain
|
||||
hostname: to identify the device
|
||||
domainname:
|
||||
fqdn: with tld, not supported yet
|
||||
"""
|
||||
__slots__ = ('_type', '_allow_ip')
|
||||
_opt_type = 'domainname'
|
||||
|
||||
|
@ -973,10 +976,6 @@ class DomainnameOption(Option):
|
|||
callback_params=None, validator=None, validator_params=None,
|
||||
properties=None, allow_ip=False, type_='domainname',
|
||||
warnings_only=False):
|
||||
#netbios: for MS domain
|
||||
#hostname: to identify the device
|
||||
#domainname:
|
||||
#fqdn: with tld, not supported yet
|
||||
if type_ not in ['netbios', 'hostname', 'domainname']:
|
||||
raise ValueError(_('unknown type_ {0} for hostname').format(type_))
|
||||
self._type = type_
|
||||
|
@ -1030,9 +1029,9 @@ class OptionDescription(BaseOption):
|
|||
"""
|
||||
__slots__ = ('_name', '_requires', '_cache_paths', '_group_type',
|
||||
'_state_group_type', '_properties', '_children',
|
||||
'_consistencies', '_calc_properties', '__weakref__',
|
||||
'_cache_consistencies', '_calc_properties', '__weakref__',
|
||||
'_readonly', '_impl_informations', '_state_requires',
|
||||
'_state_consistencies', '_stated', '_state_readonly')
|
||||
'_stated', '_state_readonly')
|
||||
_opt_type = 'optiondescription'
|
||||
|
||||
def __init__(self, name, doc, children, requires=None, properties=None):
|
||||
|
@ -1053,6 +1052,7 @@ class OptionDescription(BaseOption):
|
|||
old = child
|
||||
self._children = (tuple(child_names), tuple(children))
|
||||
self._cache_paths = None
|
||||
self._cache_consistencies = None
|
||||
# the group_type is useful for filtering OptionDescriptions in a config
|
||||
self._group_type = groups.default
|
||||
|
||||
|
@ -1126,11 +1126,11 @@ class OptionDescription(BaseOption):
|
|||
if not force_no_consistencies and \
|
||||
option._consistencies is not None:
|
||||
for consistency in option._consistencies:
|
||||
func, left_opts = consistency
|
||||
for opt in left_opts:
|
||||
func, all_cons_opts = consistency
|
||||
for opt in all_cons_opts:
|
||||
_consistencies.setdefault(opt,
|
||||
[]).append((func,
|
||||
left_opts))
|
||||
all_cons_opts))
|
||||
else:
|
||||
_currpath.append(attr)
|
||||
option.impl_build_cache(cache_path,
|
||||
|
@ -1142,7 +1142,12 @@ class OptionDescription(BaseOption):
|
|||
if save:
|
||||
self._cache_paths = (tuple(cache_option), tuple(cache_path))
|
||||
if not force_no_consistencies:
|
||||
self._consistencies = _consistencies
|
||||
if _consistencies != {}:
|
||||
self._cache_consistencies = {}
|
||||
for opt, cons in _consistencies.items():
|
||||
if opt not in cache_option:
|
||||
raise ConfigError(_('consistency with option {0} which is not in Config').format(opt._name))
|
||||
self._cache_consistencies[opt] = tuple(cons)
|
||||
self._readonly = True
|
||||
|
||||
def impl_get_opt_by_path(self, path):
|
||||
|
@ -1213,15 +1218,18 @@ class OptionDescription(BaseOption):
|
|||
def impl_get_group_type(self):
|
||||
return self._group_type
|
||||
|
||||
def _valid_consistency(self, right_opt, right_val, context=None, index=None):
|
||||
#[('_cons_not_equal', (opt1, opt2))]
|
||||
consistencies = self._consistencies.get(right_opt)
|
||||
def _valid_consistency(self, option, value, context, index):
|
||||
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, opts in consistencies:
|
||||
#opts[0] is the option where func is set
|
||||
#opts is left_opts
|
||||
ret = opts[0]._launch_consistency(func, right_opt, right_val,
|
||||
context, index, opts)
|
||||
for func, all_cons_opts in consistencies:
|
||||
#all_cons_opts[0] is the option where func is set
|
||||
ret = all_cons_opts[0]._launch_consistency(func, option,
|
||||
value,
|
||||
context, index,
|
||||
all_cons_opts)
|
||||
if ret is False:
|
||||
return False
|
||||
return True
|
||||
|
@ -1261,6 +1269,7 @@ class OptionDescription(BaseOption):
|
|||
"""
|
||||
if descr is None:
|
||||
self._cache_paths = None
|
||||
self._cache_consistencies = None
|
||||
self.impl_build_cache(force_no_consistencies=True)
|
||||
descr = self
|
||||
self._group_type = getattr(groups, self._state_group_type)
|
||||
|
|
|
@ -455,10 +455,10 @@ class Multi(list):
|
|||
value_slave.append(slave.impl_getdefault_multi(),
|
||||
force=True)
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
self._validate(value)
|
||||
def __setitem__(self, index, value):
|
||||
self._validate(value, index)
|
||||
#assume not checking mandatory property
|
||||
super(Multi, self).__setitem__(key, value)
|
||||
super(Multi, self).__setitem__(index, value)
|
||||
self.context().cfgimpl_get_values()._setvalue(self.opt, self.path, self)
|
||||
|
||||
def append(self, value, force=False):
|
||||
|
@ -476,7 +476,8 @@ class Multi(list):
|
|||
#Force None il return a list
|
||||
if isinstance(value, list):
|
||||
value = None
|
||||
self._validate(value)
|
||||
index = self.__len__()
|
||||
self._validate(value, index)
|
||||
super(Multi, self).append(value)
|
||||
self.context().cfgimpl_get_values()._setvalue(self.opt, self.path,
|
||||
self,
|
||||
|
@ -486,7 +487,6 @@ class Multi(list):
|
|||
path = values._get_opt_path(slave)
|
||||
if not values._is_default_owner(path):
|
||||
if slave.impl_has_callback():
|
||||
index = self.__len__() - 1
|
||||
dvalue = values._getcallback_value(slave, index=index)
|
||||
else:
|
||||
dvalue = slave.impl_getdefault_multi()
|
||||
|
@ -538,11 +538,11 @@ class Multi(list):
|
|||
super(Multi, self).extend(iterable)
|
||||
self.context().cfgimpl_get_values()._setvalue(self.opt, self.path, self)
|
||||
|
||||
def _validate(self, value):
|
||||
def _validate(self, value, force_index):
|
||||
if value is not None:
|
||||
try:
|
||||
self.opt.impl_validate(value, context=self.context(),
|
||||
force_no_multi=True)
|
||||
force_index=force_index)
|
||||
except ValueError as err:
|
||||
raise ValueError(_("invalid value {0} "
|
||||
"for option {1}: {2}"
|
||||
|
|
Loading…
Reference in New Issue