diff --git a/test/test_option_consistency.py b/test/test_option_consistency.py index 9af6452..23905c4 100644 --- a/test/test_option_consistency.py +++ b/test/test_option_consistency.py @@ -11,7 +11,7 @@ def test_consistency_not_equal(): a = IntOption('a', '') b = IntOption('b', '') od = OptionDescription('od', '', [a, b]) - a.impl_add_consistency('not_equal', (a, b)) + a.impl_add_consistency('not_equal', b) c = Config(od) assert c.a is None assert c.b is None @@ -22,17 +22,32 @@ def test_consistency_not_equal(): c.b = 2 +def test_consistency_not_equal_multi(): + a = IntOption('a', '', multi=True) + b = IntOption('b', '', multi=True) + od = OptionDescription('od', '', [a, b]) + a.impl_add_consistency('not_equal', b) + c = Config(od) + assert c.a == [] + assert c.b == [] + c.a = [1] + del(c.a) + c.a = [1] + raises(ValueError, "c.b = [1]") + c.b = [2] + + def test_consistency_default(): a = IntOption('a', '', 1) b = IntOption('b', '', 1) - raises(ValueError, "a.impl_add_consistency('not_equal', (a, b))") + raises(ValueError, "a.impl_add_consistency('not_equal', b)") def test_consistency_default_diff(): a = IntOption('a', '', 3) b = IntOption('b', '', 1) od = OptionDescription('od', '', [a, b]) - a.impl_add_consistency('not_equal', (a, b)) + a.impl_add_consistency('not_equal', b) c = Config(od) raises(ValueError, "c.a = 1") c.a = 2 @@ -46,7 +61,7 @@ def test_consistency_ip_netmask(): a = IPOption('a', '') b = NetmaskOption('b', '') od = OptionDescription('od', '', [a, b]) - b.impl_add_consistency('ip_netmask', (b, a)) + b.impl_add_consistency('ip_netmask', a) c = Config(od) c.a = '192.168.1.1' c.b = '255.255.255.0' @@ -60,7 +75,7 @@ def test_consistency_network_netmask(): a = NetworkOption('a', '') b = NetmaskOption('b', '') od = OptionDescription('od', '', [a, b]) - b.impl_add_consistency('network_netmask', (b, a)) + b.impl_add_consistency('network_netmask', a) c = Config(od) c.a = '192.168.1.1' c.b = '255.255.255.255' @@ -68,3 +83,32 @@ def test_consistency_network_netmask(): c.a = '192.168.1.0' c.b = '255.255.255.0' raises(ValueError, "c.a = '192.168.1.1'") + + +#FIXME pas de multi si pas de multi en maitre +def test_consistency_ip_netmask_multi(): + a = IPOption('a', '', multi=True) + b = NetmaskOption('b', '', multi=True) + od = OptionDescription('od', '', [a, b]) + b.impl_add_consistency('ip_netmask', a) + c = Config(od) + c.a = ['192.168.1.1'] + c.b = ['255.255.255.0'] + c.a = ['192.168.1.2'] + c.b = ['255.255.255.255'] + c.b = ['255.255.255.0'] + raises(ValueError, "c.a = ['192.168.1.0']") + + +def test_consistency_network_netmask_multi(): + a = NetworkOption('a', '', multi=True) + b = NetmaskOption('b', '', multi=True) + od = OptionDescription('od', '', [a, b]) + b.impl_add_consistency('network_netmask', a) + c = Config(od) + c.a = ['192.168.1.1'] + c.b = ['255.255.255.255'] + del(c.b) + c.a = ['192.168.1.0'] + c.b = ['255.255.255.0'] + raises(ValueError, "c.a = ['192.168.1.1']") diff --git a/tiramisu/autolib.py b/tiramisu/autolib.py index 6a659a3..60927af 100644 --- a/tiramisu/autolib.py +++ b/tiramisu/autolib.py @@ -56,7 +56,7 @@ def carry_out_calculation(name, config, callback, callback_params): if check_disabled: continue raise PropertiesOptionError(err, err.proptype) - is_multi = opt.optimpl_is_multi() + is_multi = opt.impl_is_multi() if is_multi: if opt_value is not None: len_value = len(opt_value) diff --git a/tiramisu/option.py b/tiramisu/option.py index 970d348..8598037 100644 --- a/tiramisu/option.py +++ b/tiramisu/option.py @@ -189,8 +189,50 @@ class Option(BaseInformation): return False return not self == other - def _launch_consistency(self, func, opt, value, context, index, opts): - return getattr(self, func)(opt, value, context, index, opts) + def _launch_consistency(self, func, opt, vals, context, index, opt_): + if context is not None: + descr = context.cfgimpl_get_description() + if opt is self: + #values are for self, search opt_ values + values = vals + if context is not None: + path = descr.impl_get_path_by_opt(opt_) + values_ = context._getattr(path, validate=False) + else: + values_ = opt_.impl_getdefault() + if index is not None: + #value is not already set, could be higher + try: + values_ = values_[index] + except IndexError: + values_ = None + else: + #values are for opt_, search self values + values_ = vals + if context is not None: + path = descr.impl_get_path_by_opt(self) + values = context._getattr(path, validate=False) + else: + values = self.impl_getdefault() + if index is not None: + #value is not already set, could be higher + try: + values = values[index] + except IndexError: + values = None + if index is None and self.impl_is_multi(): + for index in range(0, len(values)): + try: + value = values[index] + value_ = values_[index] + except IndexError: + value = None + value_ = None + if None not in (value, value_): + getattr(self, func)(opt_._name, value, value_) + else: + if None not in (values, values_): + getattr(self, func)(opt_._name, values, values_) def impl_validate(self, value, context=None, validate=True): """ @@ -282,38 +324,23 @@ class Option(BaseInformation): def impl_is_multi(self): return self._multi - def impl_add_consistency(self, func, opts): + def impl_add_consistency(self, func, opt): if self._consistencies is None: self._consistencies = [] - if self not in opts: - opts = list(opts) - opts.append(self) - opts = tuple(opts) + if not isinstance(opt, Option): + raise ValueError('consistency must be set with an option') + if self is opt: + raise ValueError('cannot add consistency with itself') func = '_cons_{}'.format(func) - for opt in opts: - if opt != self: - self._launch_consistency(func, opt, self.impl_getdefault(), None, None, opts) - self._consistencies.append((func, opts)) + self._launch_consistency(func, self, self.impl_getdefault(), None, None, opt) + self._consistencies.append((func, opt)) self.impl_validate(self.impl_getdefault(), None) - def _cons_not_equal(self, opt, value, context, index, opts): - values = [value] - if context is not None: - descr = context.cfgimpl_get_description() - for opt_ in opts: - if opt_ is not opt: - if context is not None: - path = descr.impl_get_path_by_opt(opt_) - val = context._getattr(path, validate=False) - else: - val = opt.impl_getdefault() - if val is not None: - if val in values: - raise ValueError(_("invalid value {0} for option {1} " - "must be different as {2} option" - "").format(val, self._name, - opt_._name)) - values.append(val) + def _cons_not_equal(self, optname, value, value_): + if value == value_: + raise ValueError(_("invalid value {0} for option {1} " + "must be different as {2} option" + "").format(value, self._name, optname)) class ChoiceOption(Option): @@ -466,63 +493,42 @@ class NetmaskOption(Option): except ValueError: return False - def _cons_network_netmask(self, opt, value, context, index, opts): + def _cons_network_netmask(self, optname, value, value_): #opts must be (netmask, network) options - self.__cons_netmask(opt, value, context, index, opts, False) + self.__cons_netmask(optname, value, value_, False) - def _cons_ip_netmask(self, opt, value, context, index, opts): + def _cons_ip_netmask(self, optname, value, value_): #opts must be (netmask, ip) options - self.__cons_netmask(opt, value, context, index, opts, True) + self.__cons_netmask(optname, value, value_, True) - def __cons_netmask(self, opt, value, context, index, opts, make_net): - opt_netmask, opt_ipnetwork = opts - if context is not None: - descr = context.cfgimpl_get_description() - if opt is opt_ipnetwork: - val_ipnetwork = value - if context is not None: - path = descr.impl_get_path_by_opt(opt_netmask) - val_netmask = context._getattr(path, validate=False) - else: - val_netmask = opt_netmask.impl_getdefault() - if opt_netmask.impl_is_multi(): - val_netmask = val_netmask[index] - else: - val_netmask = value - if context is not None: - path = descr.impl_get_path_by_opt(opt_ipnetwork) - val_ipnetwork = context._getattr(path, validate=False) - else: - val_ipnetwork = opt_ipnetwork.impl_getdefault() - if opt_ipnetwork.impl_is_multi(): - val_ipnetwork = val_ipnetwork[index] - if None not in (val_ipnetwork, val_netmask): - msg = None - try: - ip = IP('{0}/{1}'.format(val_ipnetwork, val_netmask), - make_net=make_net) - #if cidr == 32, ip same has network - if ip.prefixlen() != 32: - try: - IP('{0}/{1}'.format(val_ipnetwork, val_netmask), - make_net=not make_net) - except ValueError: - if not make_net: - msg = _("invalid network {0} ({1}) with netmask {2} ({3})," - " this network is an ip") - else: - if make_net: - msg = _("invalid ip {0} ({1}) with netmask {2} ({3})," - " this ip is a network") - - except ValueError: - if make_net: - msg = _("invalid ip {0} ({1}) with netmask {2} ({3})") + #def __cons_netmask(self, opt, value, context, index, opts, make_net): + def __cons_netmask(self, optname, val_netmask, val_ipnetwork, make_net): + msg = None + try: + ip = IP('{0}/{1}'.format(val_ipnetwork, val_netmask), + make_net=make_net) + #if cidr == 32, ip same has network + if ip.prefixlen() != 32: + try: + IP('{0}/{1}'.format(val_ipnetwork, val_netmask), + make_net=not make_net) + except ValueError: + if not make_net: + msg = _("invalid network {0} ({1}) with netmask {2} ({3})," + " this network is an ip") else: - msg = _("invalid network {0} ({1}) with netmask {2} ({3})") - if msg is not None: - raise ValueError(msg.format(val_ipnetwork, opt_ipnetwork._name, - val_netmask, opt_netmask._name)) + if make_net: + msg = _("invalid ip {0} ({1}) with netmask {2} ({3})," + " this ip is a network") + + except ValueError: + if make_net: + msg = _("invalid ip {0} ({1}) with netmask {2} ({3})") + else: + msg = _("invalid network {0} ({1}) with netmask {2} ({3})") + if msg is not None: + raise ValueError(msg.format(val_ipnetwork, optname, + val_netmask, self._name)) class DomainnameOption(Option): @@ -674,9 +680,10 @@ class OptionDescription(BaseInformation): if not isinstance(option, OptionDescription): if option._consistencies is not None: for consistency in option._consistencies: - func, opts = consistency - for opt in opts: - _consistencies.setdefault(opt, []).append((func, opts)) + func, opt = consistency + opts = (option, opt) + _consistencies.setdefault(opt, []).append((func, opts)) + _consistencies.setdefault(option, []).append((func, opts)) else: _currpath.append(attr) option.impl_build_cache(cache_path, cache_option, _currpath, _consistencies) @@ -759,10 +766,9 @@ class OptionDescription(BaseInformation): consistencies = self._consistencies.get(opt) if consistencies is not None: for consistency in consistencies: - func, opts = consistency - #ret = getattr(opts[0], func)(opt, value, context, index, opts) - ret = opts[0]._launch_consistency(func, opt, value, context, - index, opts) + opt_ = consistency[1] + ret = opt_[0]._launch_consistency(consistency[0], opt, value, context, + index, opt_[1]) if ret is False: return False return True diff --git a/tiramisu/value.py b/tiramisu/value.py index 47046a0..24da71a 100644 --- a/tiramisu/value.py +++ b/tiramisu/value.py @@ -99,7 +99,7 @@ class Values(object): if exp < created: return value val = self._getitem(opt, validate, force_permissive, force_properties) - if validate: + if validate and force_permissive is False and force_properties is None: self._set_cache(opt, val) return val @@ -119,14 +119,14 @@ class Values(object): else: value = self._getcallback_value(opt) if opt.impl_is_multi(): - value = Multi(value, self.context, opt) + value = Multi(value, self.context, opt, validate) #suppress value if already set self._reset(opt) # frozen and force default elif is_frozen and 'force_default_on_freeze' in setting[opt]: value = self._get_default(opt) if opt.impl_is_multi(): - value = Multi(value, self.context, opt) + value = Multi(value, self.context, opt, validate) if validate: opt.impl_validate(value, self.context, 'validator' in setting) if self.is_default_owner(opt) and \ @@ -209,7 +209,7 @@ class Multi(list): that support item notation for the values of multi options""" __slots__ = ('opt', 'context') - def __init__(self, value, context, opt): + def __init__(self, value, context, opt, validate=True): """ :param value: the Multi wraps a list value :param context: the home config that has the values @@ -219,7 +219,7 @@ class Multi(list): self.context = context if not isinstance(value, list): value = [value] - if self.opt.impl_get_multitype() == multitypes.slave: + if validate and self.opt.impl_get_multitype() == multitypes.slave: value = self._valid_slave(value) elif self.opt.impl_get_multitype() == multitypes.master: self._valid_master(value)