diff --git a/test/test_config_domain.py b/test/test_config_domain.py index a491350..da04235 100644 --- a/test/test_config_domain.py +++ b/test/test_config_domain.py @@ -10,6 +10,7 @@ def test_domainname(): e = DomainnameOption('e', '', "toto.com") od = OptionDescription('a', '', [d, e]) c = Config(od) + c.read_write() c.d = 'toto.com' raises(ValueError, "c.d = 'toto'") c.d = 'toto3.com' @@ -25,6 +26,7 @@ def test_domainname_netbios(): e = DomainnameOption('e', '', "toto", type_='netbios') od = OptionDescription('a', '', [d, e]) c = Config(od) + c.read_write() raises(ValueError, "c.d = 'toto.com'") c.d = 'toto' raises(ValueError, "c.d = 'domainnametoolong'") @@ -35,6 +37,7 @@ def test_domainname_hostname(): e = DomainnameOption('e', '', "toto", type_='hostname') od = OptionDescription('a', '', [d, e]) c = Config(od) + c.read_write() raises(ValueError, "c.d = 'toto.com'") c.d = 'toto' c.d = 'domainnametoolong' diff --git a/test/test_option_consistency.py b/test/test_option_consistency.py index 23905c4..d273c66 100644 --- a/test/test_option_consistency.py +++ b/test/test_option_consistency.py @@ -1,7 +1,7 @@ import autopath from py.test import raises -from tiramisu.setting import owners +from tiramisu.setting import owners, groups from tiramisu.config import Config from tiramisu.option import IPOption, NetworkOption, NetmaskOption, IntOption,\ OptionDescription @@ -85,7 +85,13 @@ def test_consistency_network_netmask(): raises(ValueError, "c.a = '192.168.1.1'") -#FIXME pas de multi si pas de multi en maitre +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)") + + def test_consistency_ip_netmask_multi(): a = IPOption('a', '', multi=True) b = NetmaskOption('b', '', multi=True) @@ -112,3 +118,33 @@ def test_consistency_network_netmask_multi(): c.a = ['192.168.1.0'] c.b = ['255.255.255.0'] raises(ValueError, "c.a = ['192.168.1.1']") + + +def test_consistency_ip_netmask_multi_master(): + a = IPOption('a', '', multi=True) + b = NetmaskOption('b', '', multi=True) + od = OptionDescription('a', '', [a, b]) + od.impl_set_group_type(groups.master) + 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_master(): + a = NetworkOption('a', '', multi=True) + b = NetmaskOption('b', '', multi=True) + od = OptionDescription('a', '', [a, b]) + od.impl_set_group_type(groups.master) + 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/option.py b/tiramisu/option.py index a22f7d7..ad56a75 100644 --- a/tiramisu/option.py +++ b/tiramisu/option.py @@ -239,6 +239,9 @@ class Option(BaseInformation): :param value: the option's value :param validate: if true enables ``self._validator`` validation """ + if not validate: + return + def _val_validator(val): callback_params = deepcopy(self._validator[1]) callback_params.setdefault('', []).insert(0, val) @@ -255,32 +258,32 @@ class Option(BaseInformation): return True else: return _val_validator(value) + # generic calculation if context is not None: descr = context.cfgimpl_get_description() - if validate: - if not self._multi: - if value is not None and ((self._validator is not None and - not val_validator()) or - not self._validate(value)): - raise ValueError(_("invalid value {0} for option {1}" - "").format(value, self._name)) + if not self._multi: + if value is not None and ((self._validator is not None and + not val_validator()) or + not self._validate(value)): + raise ValueError(_("invalid value {0} for option {1}" + "").format(value, self._name)) + if context is not None: + descr._valid_consistency(self, value, context, None) + else: + if not isinstance(value, list): + raise ValueError(_("invalid value {0} for option {1} " + "which must be a list").format(value, + self._name)) + for index in range(0, len(value)): + val = value[index] + if val is not None and ((self._validator is not None and + not val_validator()) or + not self._validate(val)): + raise ValueError(_("invalid value {0} for option {1}" + "").format(value, self._name)) if context is not None: - descr._valid_consistency(self, value, context, None) - else: - if not isinstance(value, list): - raise ValueError(_("invalid value {0} for option {1} " - "which must be a list").format(value, - self._name)) - for index in range(0, len(value)): - val = value[index] - if val is not None and ((self._validator is not None and - not val_validator()) or - not self._validate(val)): - raise ValueError(_("invalid value {0} for option {1}" - "").format(value, self._name)) - if context is not None: - descr._valid_consistency(self, val, context, index) + descr._valid_consistency(self, val, context, index) def impl_getdefault(self, default_multi=False): "accessing the default value" @@ -330,10 +333,12 @@ class Option(BaseInformation): raise ValueError('consistency must be set with an option') if self is opt: raise ValueError('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') func = '_cons_{}'.format(func) self._launch_consistency(func, self, self.impl_getdefault(), None, None, opt) self._consistencies.append((func, opt)) - self.impl_validate(self.impl_getdefault(), None) + self.impl_validate(self.impl_getdefault()) def _cons_not_equal(self, optname, value, value_): if value == value_: diff --git a/tiramisu/setting.py b/tiramisu/setting.py index 9c3c313..65a98b5 100644 --- a/tiramisu/setting.py +++ b/tiramisu/setting.py @@ -178,7 +178,7 @@ class Setting(object): def __init__(self, context): # properties attribute: the name of a property enables this property # key is None for global properties - self._properties = {None: set(('expire',))} + self._properties = {None: set(('expire', 'validator'))} # permissive properties self._permissives = {} # generic owner diff --git a/tiramisu/value.py b/tiramisu/value.py index 24da71a..9367b39 100644 --- a/tiramisu/value.py +++ b/tiramisu/value.py @@ -46,13 +46,13 @@ class Values(object): else: return opt.impl_getdefault() - def _get_value(self, opt): + def _get_value(self, opt, validate=True): "return value or default value if not set" #if no value if opt not in self._values: value = self._get_default(opt) if opt.impl_is_multi(): - value = Multi(value, self.context, opt) + value = Multi(value, self.context, opt, validate) else: #if value value = self._values[opt][1] @@ -64,7 +64,8 @@ class Values(object): def _reset(self, opt): if opt in self._values: setting = self.context.cfgimpl_get_settings() - opt.impl_validate(opt.impl_getdefault(), self.context, 'validator' in setting) + opt.impl_validate(opt.impl_getdefault(), self.context, + 'validator' in setting) self.context.cfgimpl_reset_cache() del(self._values[opt]) @@ -106,7 +107,7 @@ class Values(object): def _getitem(self, opt, validate, force_permissive, force_properties): # options with callbacks setting = self.context.cfgimpl_get_settings() - value = self._get_value(opt) + value = self._get_value(opt, validate) is_frozen = 'frozen' in setting[opt] if opt.impl_has_callback(): #if value is set and :