remove some try/except + consistency not works with submulti
authorEmmanuel Garette <egarette@cadoles.com>
Sun, 3 Jan 2016 12:23:15 +0000 (13:23 +0100)
committerEmmanuel Garette <egarette@cadoles.com>
Sun, 3 Jan 2016 12:23:15 +0000 (13:23 +0100)
13 files changed:
test/test_dyn_optiondescription.py
test/test_metaconfig.py
test/test_option_consistency.py
test/test_option_validator.py
tiramisu/autolib.py
tiramisu/error.py
tiramisu/option/baseoption.py
tiramisu/option/masterslave.py
tiramisu/option/option.py
tiramisu/option/optiondescription.py
tiramisu/storage/dictionary/option.py
tiramisu/storage/sqlalchemy/option.py
tiramisu/value.py

index 8cec2a2..e911b35 100644 (file)
@@ -720,38 +720,6 @@ def test_consistency_dyndescription_default():
     raises(ValueError, "cfg.od.dodval2.st2val2 = 'yes'")
 
 
-def test_consistency_dyndescription_multi():
-    st = StrOption('st', '', multi=True)
-    st2 = StrOption('st2', '', multi=True)
-    dod = DynOptionDescription('dod', '', [st, st2], callback=return_list)
-    od = OptionDescription('od', '', [dod])
-    st.impl_add_consistency('not_equal', st2)
-    od2 = OptionDescription('od', '', [od])
-    cfg = Config(od2)
-    cfg.od.dodval1.stval1.append('yes')
-    raises(ValueError, "cfg.od.dodval1.st2val1.append('yes')")
-    cfg.od.dodval2.stval2.append('yes')
-    raises(ValueError, "cfg.od.dodval2.st2val2.append('yes')")
-    raises(ValueError, "cfg.od.dodval1.st2val1.append('yes')")
-    del(cfg.od.dodval2.stval2)
-    raises(ValueError, "cfg.od.dodval1.st2val1.append('yes')")
-    cfg.od.dodval2.st2val2.append('yes')
-    raises(ValueError, "cfg.od.dodval2.stval2.append('yes')")
-
-
-def test_consistency_dyndescription_default_multi():
-    st = StrOption('st', '', ['yes'], multi=True)
-    st2 = StrOption('st2', '', multi=True)
-    dod = DynOptionDescription('dod', '', [st, st2], callback=return_list)
-    od = OptionDescription('od', '', [dod])
-    st.impl_add_consistency('not_equal', st2)
-    od2 = OptionDescription('od', '', [od])
-    cfg = Config(od2)
-    raises(ValueError, "cfg.od.dodval1.st2val1.append('yes')")
-    raises(ValueError, "cfg.od.dodval1.st2val1.append('yes')")
-    cfg.od.dodval1.stval1.append('yes')
-
-
 def test_consistency_dyndescription_default_multi2():
     st = StrOption('st', '', ['yes'], multi=True)
     st2 = StrOption('st2', '', ['yes'], multi=True)
index 69c4087..e53b4dc 100644 (file)
@@ -291,6 +291,25 @@ def test_meta_master_slaves_value():
     assert meta.conf1.netmask_admin_eth0 == [None]
 
 
+def test_meta_master_slaves_value_default():
+    ip_admin_eth0 = StrOption('ip_admin_eth0', "ip", multi=True, default=['192.168.1.1'])
+    netmask_admin_eth0 = StrOption('netmask_admin_eth0', "mask", multi=True)
+    interface1 = OptionDescription('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
+    interface1.impl_set_group_type(groups.master)
+    conf1 = Config(interface1, name='conf1')
+    conf2 = Config(interface1, name='conf2')
+    meta = MetaConfig([conf1, conf2])
+    assert meta.conf1.netmask_admin_eth0 == [None]
+    meta.ip_admin_eth0 = ['192.168.1.1']
+    assert meta.conf1.netmask_admin_eth0 == [None]
+    meta.netmask_admin_eth0 = ['255.255.255.0']
+    assert meta.conf1.netmask_admin_eth0 == ['255.255.255.0']
+    meta.netmask_admin_eth0 = ['255.255.0.0']
+    assert meta.conf1.netmask_admin_eth0 == ['255.255.0.0']
+    meta.conf1.ip_admin_eth0 = ['192.168.1.1']
+    assert meta.conf1.netmask_admin_eth0 == [None]
+
+
 def test_meta_master_slaves_owners():
     ip_admin_eth0 = StrOption('ip_admin_eth0', "ip", multi=True)
     netmask_admin_eth0 = StrOption('netmask_admin_eth0', "mask", multi=True, properties=('hidden',))
index 323f6e4..0c19fa7 100644 (file)
@@ -17,8 +17,6 @@ def test_consistency():
     a.impl_add_consistency('not_equal', b)
     #consistency to itself
     raises(ConfigError, "a.impl_add_consistency('not_equal', a)")
-    #consistency with string
-    raises(ConfigError, "a.impl_add_consistency('not_equal', 'a')")
 
 
 def test_consistency_not_exists():
@@ -157,21 +155,9 @@ def test_consistency_not_equal_symlink():
 def test_consistency_not_equal_submulti():
     a = IntOption('a', '', multi=submulti)
     b = IntOption('b', '', multi=submulti)
-    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.a = [[1, 2]]
-    c.b = [[3]]
-    c.b = [[3, 1]]
-    c.b = [[3]]
-    c.b[0].append(1)
-    c.b = [[3], [1]]
+    od = OptionDescription('a', '', [a, b])
+    od.impl_set_group_type(groups.master)
+    raises(ConfigError, 'a.impl_add_consistency("not_equal", b)')
 
 
 def test_consistency_not_equal_default_submulti():
@@ -179,13 +165,14 @@ def test_consistency_not_equal_default_submulti():
     b = IntOption('b', '', [[1]], multi=submulti)
     od = OptionDescription('od', '', [a, b])
     od
-    raises(ValueError, "a.impl_add_consistency('not_equal', b)")
+    raises(ConfigError, "a.impl_add_consistency('not_equal', b)")
 
 
 def test_consistency_not_equal_multi():
     a = IntOption('a', '', multi=True)
     b = IntOption('b', '', multi=True)
-    od = OptionDescription('od', '', [a, b])
+    od = OptionDescription('a', '', [a, b])
+    od.impl_set_group_type(groups.master)
     a.impl_add_consistency('not_equal', b)
     c = Config(od)
     assert c.a == []
@@ -200,16 +187,15 @@ def test_consistency_not_equal_multi():
 def test_consistency_not_equal_multi_default():
     a = IntOption('a', '', multi=True)
     b = IntOption('b', '', multi=True, default_multi=1)
-    od = OptionDescription('od', '', [a, b])
+    od = OptionDescription('a', '', [a, b])
+    od.impl_set_group_type(groups.master)
     a.impl_add_consistency('not_equal', b)
     c = Config(od)
     assert c.a == []
     assert c.b == []
-    c.a = [1]
+    raises(ValueError, 'c.a = [1]')
+    c.a = [2]
     del(c.a)
-    c.a = [1]
-    raises(ValueError, "c.b = [1]")
-    c.b = [2]
 
 
 def test_consistency_default():
@@ -325,8 +311,9 @@ def test_consistency_ip_netmask_error_multi():
 def test_consistency_ip_netmask_multi():
     a = IPOption('a', '', multi=True)
     b = NetmaskOption('b', '', multi=True)
-    od = OptionDescription('od', '', [a, b])
+    od = OptionDescription('a', '', [a, b])
     b.impl_add_consistency('ip_netmask', a)
+    od.impl_set_group_type(groups.master)
     c = Config(od)
     c.a = ['192.168.1.1']
     c.b = ['255.255.255.0']
@@ -339,7 +326,8 @@ def test_consistency_ip_netmask_multi():
 def test_consistency_network_netmask_multi():
     a = NetworkOption('a', '', multi=True)
     b = NetmaskOption('b', '', multi=True)
-    od = OptionDescription('od', '', [a, b])
+    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']
index 2ba9aec..5af5a56 100644 (file)
@@ -14,12 +14,12 @@ from tiramisu.i18n import _
 def return_true(value, param=None):
     if value == 'val' and param in [None, 'yes']:
         return True
-    raise ValueError('error')
+    return ValueError('error')
 
 
 def return_false(value, param=None):
     if value == 'val' and param in [None, 'yes']:
-        raise ValueError('error')
+        return ValueError('error')
 
 
 def return_val(value, param=None):
@@ -28,7 +28,7 @@ def return_val(value, param=None):
 
 def return_if_val(value):
     if value != 'val':
-        raise ValueError('error')
+        return ValueError('error')
 
 
 def test_validator():
index 634eac1..ace2c0a 100644 (file)
@@ -18,8 +18,7 @@
 # the whole pypy projet is under MIT licence
 # ____________________________________________________________
 "enables us to carry out a calculation and return an option's value"
-from .error import PropertiesOptionError, ConfigError, ContextError, \
-    SlaveError
+from .error import PropertiesOptionError, ConfigError, SlaveError
 from .i18n import _
 from .setting import undefined
 # ____________________________________________________________
@@ -145,7 +144,7 @@ def carry_out_calculation(option, context, callback, callback_params,
         for callbk in callbacks:
             if isinstance(callbk, tuple):
                 if context is undefined:
-                    raise ContextError()  # pragma: optional cover
+                    return undefined
                 if callbk[0] is None:  # pragma: optional cover
                     #Not an option, set full context
                     tcparams.setdefault(key, []).append((context, False))
index 93e93f9..163c7c3 100644 (file)
@@ -34,12 +34,6 @@ class ConfigError(Exception):
     pass
 
 
-class ContextError(Exception):
-    """context needed but not given
-    """
-    pass
-
-
 class ConflictError(Exception):
     "duplicate options are present in a single config"
     pass
index 41ca14c..09b9034 100644 (file)
@@ -25,8 +25,7 @@ import warnings
 from ..i18n import _
 from ..setting import log, undefined
 from ..autolib import carry_out_calculation
-from ..error import ConfigError, ValueWarning, PropertiesOptionError,\
-    ContextError
+from ..error import ConfigError, ValueWarning, PropertiesOptionError
 from ..storage import get_storages_option
 
 
@@ -142,10 +141,9 @@ class Base(StorageBase):
                              allow_empty_list)
         if multi is not False and default is None:
             default = []
-        try:
-            self.impl_validate(default, is_multi=is_multi)
-        except ContextError:
-            pass
+        err = self.impl_validate(default, is_multi=is_multi)
+        if err:
+            raise err
         self._set_default_values(default, default_multi, is_multi)
         ##callback is False in optiondescription
         if callback is not False:
@@ -347,7 +345,7 @@ class BaseOption(Base):
 
     def _impl_valid_unicode(self, value):
         if not isinstance(value, unicode) and not isinstance(value, str):
-            raise ValueError(_('invalid unicode or string'))
+            return ValueError(_('invalid unicode or string'))
 
 
 class OnlyOption(BaseOption):
@@ -413,21 +411,17 @@ class Option(OnlyOption):
                         option == opt:
                     all_cons_vals.append(opt_value)
                 elif self.impl_is_submulti():
+                    print option._name, opt_value
                     all_cons_vals.append(opt_value[index][submulti_index])
                 else:
                     all_cons_vals.append(opt_value[index])
-        except IndexError, err:
-            #value is not already set, could be higher index
-            #so return if no value and not default_value
-            log.debug('indexerror in _launch_consistency: {0}'.format(err))
-            return
         except PropertiesOptionError as err:
             log.debug('propertyerror in _launch_consistency: {0}'.format(err))
             if transitive:
                 raise err
             else:
                 return
-        getattr(self, func)(all_cons_opts, all_cons_vals, warnings_only)
+        return getattr(self, func)(all_cons_opts, all_cons_vals, warnings_only)
 
     def impl_validate(self, value, context=undefined, validate=True,
                       force_index=None, force_submulti_index=None,
@@ -467,52 +461,44 @@ class Option(OnlyOption):
                 else:
                     validator_params_ = {'': (val,)}
                 # Raise ValueError if not valid
-                try:
-                    carry_out_calculation(current_opt, context=context,
-                                          callback=validator,
-                                          callback_params=validator_params_)
-                except ContextError:
-                    pass
+                value = carry_out_calculation(current_opt, context=context,
+                                              callback=validator,
+                                              callback_params=validator_params_)
+                if isinstance(value, Exception):
+                    return value
 
         def do_validation(_value, _index, submulti_index):
             if _value is None:
                 return
             # option validation
-            try:
-                self._validate(_value, context, current_opt)
-            except ValueError as err:  # pragma: optional cover
+            err = self._validate(_value, context, current_opt)
+            if err:
                 log.debug('do_validation: value: {0}, index: {1}, '
                           'submulti_index: {2}'.format(_value, _index,
                                                        submulti_index),
                           exc_info=True)
-                raise ValueError(_('invalid value for option {0}: {1}'
-                                   '').format(self.impl_getname(), err))
-            error = None
+                return ValueError(_('invalid value for option {0}: {1}'
+                                    '').format(self.impl_getname(), err))
             warning = None
-            try:
-                # valid with self._validator
-                calculation_validator(_value)
-                self._second_level_validation(_value, self._is_warnings_only())
-            except ValueError as error:
+            error = calculation_validator(_value)
+            if not error:
+                error = self._second_level_validation(_value, self._is_warnings_only())
+            if error:
                 log.debug(_('do_validation for {0}: error in value').format(
                     self.impl_getname()), exc_info=True)
                 if self._is_warnings_only():
                     warning = error
                     error = None
             if error is None and warning is None:
-                try:
-                    # if context launch consistency validation
-                    #if context is not undefined:
-                    self._valid_consistency(current_opt, _value, context,
-                                            _index, submulti_index)
-                except ValueError as error:
-                    log.debug(_('do_validation for {0}: error in consistency').format(
-                        self.impl_getname()), exc_info=True)
-                    pass
-                except ValueWarning as warning:
-                    log.debug(_('do_validation for {0}: warning in consistency').format(
-                        self.impl_getname()), exc_info=True)
-                    pass
+                # if context launch consistency validation
+                #if context is not undefined:
+                ret = self._valid_consistency(current_opt, _value, context,
+                                              _index, submulti_index)
+                if ret:
+                    if isinstance(ret, ValueWarning):
+                        warning = ret
+                    elif isinstance(ret, ValueError):
+                        error = ret
             if warning:
                 msg = _("warning on the value of the option {0}: {1}").format(
                     self.impl_getname(), warning)
@@ -522,7 +508,7 @@ class Option(OnlyOption):
                                            ValueWarning,
                                            self.__class__.__name__, 0)
             elif error:
-                raise ValueError(_("invalid value for option {0}: {1}").format(
+                return ValueError(_("invalid value for option {0}: {1}").format(
                     self.impl_getname(), error))
 
         # generic calculation
@@ -532,7 +518,7 @@ class Option(OnlyOption):
         if is_multi is None:
             is_multi = self.impl_is_multi()
         if not is_multi:
-            do_validation(value, None, None)
+            return do_validation(value, None, None)
         elif force_index is not None:
             if self.impl_is_submulti() and force_submulti_index is None:
                 if not isinstance(value, list):  # pragma: optional cover
@@ -540,25 +526,31 @@ class Option(OnlyOption):
                                        " must be a list").format(
                                            value, self.impl_getname()))
                 for idx, val in enumerate(value):
-                    do_validation(val, force_index, idx)
+                    err = do_validation(val, force_index, idx)
+                    if err:
+                        return err
             else:
-                do_validation(value, force_index, force_submulti_index)
+                return do_validation(value, force_index, force_submulti_index)
+        elif not isinstance(value, list):  # pragma: optional cover
+            return ValueError(_("invalid value {0} for option {1} which "
+                                "must be a list").format(value,
+                                                         self.impl_getname()))
+        elif self.impl_is_submulti() and force_submulti_index is None:
+            for idx, val in enumerate(value):
+                if not isinstance(val, list):  # pragma: optional cover
+                    return ValueError(_("invalid value {0} for option {1} "
+                                        "which must be a list of list"
+                                        "").format(value,
+                                                   self.impl_getname()))
+                for slave_idx, slave_val in enumerate(val):
+                    err = do_validation(slave_val, idx, slave_idx)
+                    if err:
+                        return err
         else:
-            if not isinstance(value, list):  # pragma: optional cover
-                raise ValueError(_("invalid value {0} for option {1} which "
-                                   "must be a list").format(value,
-                                                            self.impl_getname()))
             for idx, val in enumerate(value):
-                if self.impl_is_submulti() and force_submulti_index is None:
-                    if not isinstance(val, list):  # pragma: optional cover
-                        raise ValueError(_("invalid value {0} for option {1} "
-                                           "which must be a list of list"
-                                           "").format(value,
-                                                      self.impl_getname()))
-                    for slave_idx, slave_val in enumerate(val):
-                        do_validation(slave_val, idx, slave_idx)
-                else:
-                    do_validation(val, idx, force_submulti_index)
+                err = do_validation(val, idx, force_submulti_index)
+                if err:
+                    return err
 
     def impl_is_master_slaves(self, type_='both'):
         """FIXME
@@ -585,7 +577,12 @@ class Option(OnlyOption):
             dynod = self._impl_getsubdyn()
         else:
             dynod = None
+        if self.impl_is_submulti():
+            raise ConfigError(_('cannot add consistency with submulti option'))
+        is_multi = self.impl_is_multi()
         for opt in other_opts:
+            if opt.impl_is_submulti():
+                raise ConfigError(_('cannot add consistency with submulti option'))
             if not isinstance(opt, Option):  # pragma: optional cover
                 raise ConfigError(_('consistency must be set with an option'))
             if opt._is_subdyn():
@@ -601,7 +598,7 @@ class Option(OnlyOption):
                                     'dynoptiondescription but not all'))
             if self is opt:  # pragma: optional cover
                 raise ConfigError(_('cannot add consistency with itself'))
-            if self.impl_is_multi() != opt.impl_is_multi():  # pragma: optional cover
+            if is_multi != opt.impl_is_multi():  # pragma: optional cover
                 raise ConfigError(_('every options in consistency must be '
                                     'multi or none'))
 
@@ -630,9 +627,8 @@ class Option(OnlyOption):
             raise ValueError(_('unknow parameter {0} in consistency').format(unknown_params))
         self._add_consistency(func, all_cons_opts, params)
         #validate default value when add consistency
-        try:
-            self.impl_validate(self.impl_getdefault())
-        except ValueError, err:
+        err = self.impl_validate(self.impl_getdefault())
+        if err:
             self._del_consistency()
             raise err
 
@@ -640,7 +636,7 @@ class Option(OnlyOption):
         if context is not undefined:
             descr = context.cfgimpl_get_description()
             if descr._cache_consistencies is None:
-                return True
+                return
             #consistencies is something like [('_cons_not_equal', (opt1, opt2))]
             if isinstance(option, DynSymLinkOption):
                 consistencies = descr._cache_consistencies.get(option._impl_getopt())
@@ -664,15 +660,14 @@ class Option(OnlyOption):
                         opts.append(opt._impl_to_dyn(name, path))
                 else:
                     opts = all_cons_opts
-                try:
-                    opts[0]._launch_consistency(func, option, value, context,
-                                                index, submulti_idx, opts,
-                                                warnings_only, transitive)
-                except ValueError as err:
+                err = opts[0]._launch_consistency(func, option, value, context,
+                                                  index, submulti_idx, opts,
+                                                  warnings_only, transitive)
+                if err:
                     if warnings_only:
-                        raise ValueWarning(err.message, option)
+                        return ValueWarning(err.message, option)
                     else:
-                        raise err
+                        return err
 
     def _cons_not_equal(self, opts, vals, warnings_only):
         for idx_inf, val_inf in enumerate(vals):
@@ -683,8 +678,8 @@ class Option(OnlyOption):
                     else:
                         msg = _("same value for {0} and {1}, must be different")
                     log.debug('_cons_not_equal: {0} and {1} are not different'.format(val_inf, val_sup))
-                    raise ValueError(msg.format(opts[idx_inf].impl_getname(),
-                                                opts[idx_inf + idx_sup + 1].impl_getname()))
+                    return ValueError(msg.format(opts[idx_inf].impl_getname(),
+                                                 opts[idx_inf + idx_sup + 1].impl_getname()))
 
     # serialize/unserialize
     def _impl_convert_consistencies(self, descr, load=False):
@@ -804,9 +799,8 @@ def validate_requires_arg(multi, requires, name):
                                'multi option must not set '
                                'as requires of non multi option {0}').format(name))
         if expected is not None:
-            try:
-                option._validate(expected)
-            except ValueError as err:  # pragma: optional cover
+            err = option._validate(expected)
+            if err:
                 raise ValueError(_('malformed requirements second argument '
                                    'must be valid for option {0}'
                                    ': {1}').format(name, err))
@@ -887,6 +881,9 @@ class SymLinkOption(OnlyOption):
     def _is_subdyn(self):
         return getattr(self._impl_getopt(), '_subdyn', None) is not None
 
+    def _get_consistencies(self):
+        return ()
+
 
 class DynSymLinkOption(object):
     __slots__ = ('_dyn', '_opt', '_name')
index b982aba..0a774e5 100644 (file)
@@ -21,7 +21,7 @@
 # ____________________________________________________________
 from ..i18n import _
 from ..setting import log, undefined
-from ..error import SlaveError, ConfigError, PropertiesOptionError
+from ..error import SlaveError, PropertiesOptionError
 from .baseoption import DynSymLinkOption, SymLinkOption, Option
 
 
@@ -180,6 +180,7 @@ class MasterSlaves(object):
                                     master=master)
         master_is_meta = values._is_meta(master, masterp)
         multi = values._get_multi(opt, path)
+        #if masterlen is [], test properties (has no value, don't get any value)
         if masterlen == 0:
             if validate_properties:
                 props = context.cfgimpl_get_settings().validate_properties(opt, False,
index 0ae7094..1ad49d8 100644 (file)
@@ -23,9 +23,9 @@ import re
 import sys
 from IPy import IP
 from types import FunctionType
-from ..setting import log, undefined
+from ..setting import undefined
 
-from ..error import ConfigError, ContextError
+from ..error import ConfigError
 from ..i18n import _
 from .baseoption import Option, validate_callback
 from ..autolib import carry_out_calculation
@@ -83,18 +83,18 @@ class ChoiceOption(Option):
                 values = carry_out_calculation(current_opt, context=context,
                                                callback=values,
                                                callback_params=values_params)
-                if not isinstance(values, list):  # pragma: optional cover
+                if values is not undefined and not isinstance(values, list):  # pragma: optional cover
                     raise ConfigError(_('calculated values for {0} is not a list'
                                         '').format(self.impl_getname()))
         return values
 
     def _validate(self, value, context=undefined, current_opt=undefined):
         values = self.impl_get_values(context, current_opt=current_opt)
-        if not value in values:  # pragma: optional cover
-            raise ValueError(_('value {0} is not permitted, '
+        if values is not undefined and not value in values:  # pragma: optional cover
+            return ValueError(_('value {0} is not permitted, '
                                 'only {1} is allowed'
                                 '').format(value,
-                                        values))
+                                           values))
 
 
 class BoolOption(Option):
@@ -103,7 +103,7 @@ class BoolOption(Option):
 
     def _validate(self, value, context=undefined, current_opt=undefined):
         if not isinstance(value, bool):
-            raise ValueError(_('invalid boolean'))  # pragma: optional cover
+            return ValueError(_('invalid boolean'))  # pragma: optional cover
 
 
 class IntOption(Option):
@@ -112,7 +112,7 @@ class IntOption(Option):
 
     def _validate(self, value, context=undefined, current_opt=undefined):
         if not isinstance(value, int):
-            raise ValueError(_('invalid integer'))  # pragma: optional cover
+            return ValueError(_('invalid integer'))  # pragma: optional cover
 
 
 class FloatOption(Option):
@@ -121,7 +121,7 @@ class FloatOption(Option):
 
     def _validate(self, value, context=undefined, current_opt=undefined):
         if not isinstance(value, float):
-            raise ValueError(_('invalid float'))  # pragma: optional cover
+            return ValueError(_('invalid float'))  # pragma: optional cover
 
 
 class StrOption(Option):
@@ -130,7 +130,7 @@ class StrOption(Option):
 
     def _validate(self, value, context=undefined, current_opt=undefined):
         if not isinstance(value, str):
-            raise ValueError(_('invalid string'))  # pragma: optional cover
+            return ValueError(_('invalid string'))  # pragma: optional cover
 
 
 if sys.version_info[0] >= 3:  # pragma: optional cover
@@ -146,7 +146,7 @@ else:
 
         def _validate(self, value, context=undefined, current_opt=undefined):
             if not isinstance(value, unicode):
-                raise ValueError(_('invalid unicode'))  # pragma: optional cover
+                return ValueError(_('invalid unicode'))  # pragma: optional cover
 
 
 class IPOption(Option):
@@ -175,15 +175,17 @@ class IPOption(Option):
     def _validate(self, value, context=undefined, current_opt=undefined):
         # sometimes an ip term starts with a zero
         # but this does not fit in some case, for example bind does not like it
-        self._impl_valid_unicode(value)
+        err = self._impl_valid_unicode(value)
+        if err:
+            return err
         for val in value.split('.'):
             if val.startswith("0") and len(val) > 1:
-                raise ValueError(_('invalid IP'))  # pragma: optional cover
+                return ValueError(_('invalid IP'))  # pragma: optional cover
         # 'standard' validation
         try:
             IP('{0}/32'.format(value))
         except ValueError:  # pragma: optional cover
-            raise ValueError(_('invalid IP'))
+            return ValueError(_('invalid IP'))
 
     def _second_level_validation(self, value, warnings_only):
         ip = IP('{0}/32'.format(value))
@@ -192,13 +194,13 @@ class IPOption(Option):
                 msg = _("IP is in reserved class")
             else:
                 msg = _("invalid IP, mustn't be in reserved class")
-            raise ValueError(msg)
+            return ValueError(msg)
         if self._get_extra('_private_only') and not ip.iptype() == 'PRIVATE':  # pragma: optional cover
             if warnings_only:
                 msg = _("IP is not in private class")
             else:
                 msg = _("invalid IP, must be in private class")
-            raise ValueError(msg)
+            return ValueError(msg)
 
     def _cons_in_network(self, opts, vals, warnings_only):
         if len(vals) != 3:
@@ -213,10 +215,10 @@ class IPOption(Option):
             else:
                 msg = _('invalid IP {0} ({1}) not in network {2} ({3}) with '
                         'netmask {4} ({5})')
-            raise ValueError(msg.format(ip, opts[0].impl_getname(), network,
-                             opts[1].impl_getname(), netmask, opts[2].impl_getname()))
+            return ValueError(msg.format(ip, opts[0].impl_getname(), network,
+                              opts[1].impl_getname(), netmask, opts[2].impl_getname()))
         # test if ip is not network/broadcast IP
-        opts[2]._cons_ip_netmask((opts[2], opts[0]), (netmask, ip), warnings_only)
+        return opts[2]._cons_ip_netmask((opts[2], opts[0]), (netmask, ip), warnings_only)
 
 
 class PortOption(Option):
@@ -275,15 +277,17 @@ class PortOption(Option):
     def _validate(self, value, context=undefined, current_opt=undefined):
         if isinstance(value, int):
             value = unicode(value)
-        self._impl_valid_unicode(value)
+        err = self._impl_valid_unicode(value)
+        if err:
+            return err
         if self._get_extra('_allow_range') and ":" in str(value):  # pragma: optional cover
             value = str(value).split(':')
             if len(value) != 2:
-                raise ValueError(_('invalid port, range must have two values '
-                                 'only'))
+                return ValueError(_('invalid port, range must have two values '
+                                  'only'))
             if not value[0] < value[1]:
-                raise ValueError(_('invalid port, first port in range must be'
-                                 ' smaller than the second one'))
+                return ValueError(_('invalid port, first port in range must be'
+                                  ' smaller than the second one'))
         else:
             value = [value]
 
@@ -291,11 +295,11 @@ class PortOption(Option):
             try:
                 val = int(val)
             except ValueError:  # pragma: optional cover
-                raise ValueError(_('invalid port'))
+                return ValueError(_('invalid port'))
             if not self._get_extra('_min_value') <= val <= self._get_extra('_max_value'):  # pragma: optional cover
-                raise ValueError(_('invalid port, must be an integer between {0} '
-                                   'and {1}').format(self._get_extra('_min_value'),
-                                                     self._get_extra('_max_value')))
+                return ValueError(_('invalid port, must be an integer between {0} '
+                                    'and {1}').format(self._get_extra('_min_value'),
+                                                      self._get_extra('_max_value')))
 
 
 class NetworkOption(Option):
@@ -303,11 +307,13 @@ class NetworkOption(Option):
     __slots__ = tuple()
 
     def _validate(self, value, context=undefined, current_opt=undefined):
-        self._impl_valid_unicode(value)
+        err = self._impl_valid_unicode(value)
+        if err:
+            return err
         try:
             IP(value)
         except ValueError:  # pragma: optional cover
-            raise ValueError(_('invalid network address'))
+            return ValueError(_('invalid network address'))
 
     def _second_level_validation(self, value, warnings_only):
         ip = IP(value)
@@ -316,7 +322,7 @@ class NetworkOption(Option):
                 msg = _("network address is in reserved class")
             else:
                 msg = _("invalid network address, mustn't be in reserved class")
-            raise ValueError(msg)
+            return ValueError(msg)
 
 
 class NetmaskOption(Option):
@@ -324,23 +330,25 @@ class NetmaskOption(Option):
     __slots__ = tuple()
 
     def _validate(self, value, context=undefined, current_opt=undefined):
-        self._impl_valid_unicode(value)
+        err = self._impl_valid_unicode(value)
+        if err:
+            return err
         try:
             IP('0.0.0.0/{0}'.format(value))
         except ValueError:  # pragma: optional cover
-            raise ValueError(_('invalid netmask address'))
+            return ValueError(_('invalid netmask address'))
 
     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, warnings_only)
+        return self.__cons_netmask(opts, vals[0], vals[1], False, warnings_only)
 
     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, warnings_only)
+        return self.__cons_netmask(opts, vals[0], vals[1], True, warnings_only)
 
     def __cons_netmask(self, opts, val_netmask, val_ipnetwork, make_net,
                        warnings_only):
@@ -364,19 +372,21 @@ class NetmaskOption(Option):
             if not make_net:
                 msg = _('invalid network {0} ({1}) with netmask {2}')
         if msg is not None:  # pragma: optional cover
-            raise ValueError(msg.format(val_ipnetwork, opts[1].impl_getname(),
-                                        val_netmask))
+            return ValueError(msg.format(val_ipnetwork, opts[1].impl_getname(),
+                                         val_netmask))
 
 
 class BroadcastOption(Option):
     __slots__ = tuple()
 
     def _validate(self, value, context=undefined, current_opt=undefined):
-        self._impl_valid_unicode(value)
+        err = self._impl_valid_unicode(value)
+        if err:
+            return err
         try:
             IP('{0}/32'.format(value))
         except ValueError:  # pragma: optional cover
-            raise ValueError(_('invalid broadcast address'))
+            return ValueError(_('invalid broadcast address'))
 
     def _cons_broadcast(self, opts, vals, warnings_only):
         if len(vals) != 3:
@@ -385,10 +395,10 @@ class BroadcastOption(Option):
             return
         broadcast, network, netmask = vals
         if IP('{0}/{1}'.format(network, netmask)).broadcast() != IP(broadcast):
-            raise ValueError(_('invalid broadcast {0} ({1}) with network {2} '
-                               '({3}) and netmask {4} ({5})').format(
-                                   broadcast, opts[0].impl_getname(), network,
-                                   opts[1].impl_getname(), netmask, opts[2].impl_getname()))  # pragma: optional cover
+            return ValueError(_('invalid broadcast {0} ({1}) with network {2} '
+                                '({3}) and netmask {4} ({5})').format(
+                                    broadcast, opts[0].impl_getname(), network,
+                                    opts[1].impl_getname(), netmask, opts[2].impl_getname()))  # pragma: optional cover
 
 
 class DomainnameOption(Option):
@@ -430,14 +440,16 @@ class DomainnameOption(Option):
                                                extra=extra)
 
     def _validate(self, value, context=undefined, current_opt=undefined):
-        self._impl_valid_unicode(value)
+        err = self._impl_valid_unicode(value)
+        if err:
+            return err
 
         def _valid_length(val):
             if len(val) < 1:
-                raise ValueError(_("invalid domainname's length (min 1)"))
+                return ValueError(_("invalid domainname's length (min 1)"))
             if len(val) > part_name_length:
-                raise ValueError(_("invalid domainname's length (max {0})"
-                                   "").format(part_name_length))
+                return ValueError(_("invalid domainname's length (max {0})"
+                                    "").format(part_name_length))
 
         if self._get_extra('_allow_ip') is True:  # pragma: optional cover
             try:
@@ -451,23 +463,25 @@ class DomainnameOption(Option):
             part_name_length = 63
         if self._get_extra('_dom_type') == 'domainname':
             if not self._get_extra('_allow_without_dot') and not "." in value:
-                raise ValueError(_("invalid domainname, must have dot"))
+                return ValueError(_("invalid domainname, must have dot"))
             if len(value) > 255:
-                raise ValueError(_("invalid domainname's length (max 255)"))
+                return ValueError(_("invalid domainname's length (max 255)"))
             for dom in value.split('.'):
-                _valid_length(dom)
+                err = _valid_length(dom)
+                if err:
+                    return err
         else:
-            _valid_length(value)
+            return _valid_length(value)
 
     def _second_level_validation(self, value, warnings_only):
         def _valid_char(val):
             if self._get_extra('_has_upper').search(val):
-                raise ValueError(_('some characters are uppercase'))
+                return ValueError(_('some characters are uppercase'))
             if not self._get_extra('_domain_re').search(val):
                 if warnings_only:
-                    raise ValueError(_('some characters may cause problems'))
+                    return ValueError(_('some characters may cause problems'))
                 else:
-                    raise ValueError(_('invalid domainname'))
+                    return ValueError(_('invalid domainname'))
         #not for IP
         if self._get_extra('_allow_ip') is True:
             try:
@@ -477,9 +491,9 @@ class DomainnameOption(Option):
                 pass
         if self._get_extra('_dom_type') == 'domainname':
             for dom in value.split('.'):
-                _valid_char(dom)
+                return _valid_char(dom)
         else:
-            _valid_char(value)
+            return _valid_char(value)
 
 
 class EmailOption(DomainnameOption):
@@ -487,17 +501,19 @@ class EmailOption(DomainnameOption):
     username_re = re.compile(r"^[\w!#$%&'*+\-/=?^`{|}~.]+$")
 
     def _validate(self, value, context=undefined, current_opt=undefined):
-        self._impl_valid_unicode(value)
+        err = self._impl_valid_unicode(value)
+        if err:
+            return err
         splitted = value.split('@', 1)
-        try:
-            username, domain = splitted
-        except ValueError:  # pragma: optional cover
-            raise ValueError(_('invalid email address, must contains one @'
-                               ))
+        if len(splitted) == 1:
+            return ValueError(_('invalid email address, must contains one @'))
+        username, domain = value.split('@', 1)
         if not self.username_re.search(username):
-            raise ValueError(_('invalid username in email address'))  # pragma: optional cover
-        super(EmailOption, self)._validate(domain)
-        super(EmailOption, self)._second_level_validation(domain, False)
+            return ValueError(_('invalid username in email address'))  # pragma: optional cover
+        err = super(EmailOption, self)._validate(domain)
+        if err:
+            return err
+        return super(EmailOption, self)._second_level_validation(domain, False)
 
     def _second_level_validation(self, value, warnings_only):
         pass
@@ -509,36 +525,41 @@ class URLOption(DomainnameOption):
     path_re = re.compile(r"^[A-Za-z0-9\-\._~:/\?#\[\]@!%\$&\'\(\)\*\+,;=]+$")
 
     def _validate(self, value, context=undefined, current_opt=undefined):
-        self._impl_valid_unicode(value)
+        err = self._impl_valid_unicode(value)
+        if err:
+            return err
         match = self.proto_re.search(value)
         if not match:  # pragma: optional cover
-            raise ValueError(_('invalid url, must start with http:// or '
-                               'https://'))
+            return ValueError(_('invalid url, must start with http:// or '
+                                'https://'))
         value = value[len(match.group(0)):]
         # get domain/files
         splitted = value.split('/', 1)
-        try:
-            domain, files = splitted
-        except ValueError:
+        if len(splitted) == 1:
             domain = value
             files = None
+        else:
+            domain, files = splitted
         # if port in domain
         splitted = domain.split(':', 1)
-        try:
-            domain, port = splitted
-
-        except ValueError:  # pragma: optional cover
+        if len(splitted) == 1:
             domain = splitted[0]
             port = 0
+        else:
+            domain, port = splitted
         if not 0 <= int(port) <= 65535:
-            raise ValueError(_('invalid url, port must be an between 0 and '
-                               '65536'))  # pragma: optional cover
+            return ValueError(_('invalid url, port must be an between 0 and '
+                                '65536'))  # pragma: optional cover
         # validate domainname
-        super(URLOption, self)._validate(domain)
-        super(URLOption, self)._second_level_validation(domain, False)
+        err = super(URLOption, self)._validate(domain)
+        if err:
+            return err
+        err = super(URLOption, self)._second_level_validation(domain, False)
+        if err:
+            return err
         # validate file
         if files is not None and files != '' and not self.path_re.search(files):
-            raise ValueError(_('invalid url, must ends with a valid resource name'))  # pragma: optional cover
+            return ValueError(_('invalid url, must ends with a valid resource name'))  # pragma: optional cover
 
     def _second_level_validation(self, value, warnings_only):
         pass
@@ -550,10 +571,12 @@ class UsernameOption(Option):
     username_re = re.compile(r"^[a-z_][a-z0-9_-]{0,30}[$a-z0-9_-]{0,1}$")
 
     def _validate(self, value, context=undefined, current_opt=undefined):
-        self._impl_valid_unicode(value)
+        err = self._impl_valid_unicode(value)
+        if err:
+            return err
         match = self.username_re.search(value)
         if not match:
-            raise ValueError(_('invalid username'))  # pragma: optional cover
+            return ValueError(_('invalid username'))  # pragma: optional cover
 
 
 class FilenameOption(Option):
@@ -561,7 +584,9 @@ class FilenameOption(Option):
     path_re = re.compile(r"^[a-zA-Z0-9\-\._~/+]+$")
 
     def _validate(self, value, context=undefined, current_opt=undefined):
-        self._impl_valid_unicode(value)
+        err = self._impl_valid_unicode(value)
+        if err:
+            return err
         match = self.path_re.search(value)
         if not match:
-            raise ValueError(_('invalid filename'))  # pragma: optional cover
+            return ValueError(_('invalid filename'))  # pragma: optional cover
index 0e75e9c..4c78d9a 100644 (file)
@@ -111,15 +111,32 @@ class OptionDescription(BaseOption, StorageOptionDescription):
                 #cannot set multi option as OptionDescription requires
             else:
                 option._set_readonly(True)
+                is_multi = option.impl_is_multi()
                 for func, all_cons_opts, params in option._get_consistencies():
-                    all_cons_opts[0]._valid_consistencies(all_cons_opts[1:])
+                    option._valid_consistencies(all_cons_opts[1:])
+                    if is_multi:
+                        is_slave = option.impl_is_master_slaves()
+                        if not is_slave:
+                            raise ValueError(_('malformed consistency option {0} '
+                                               'must be a master/slaves').format(
+                                                   option.impl_getname()))
+                        masterslaves = option.impl_get_master_slaves()
                     for opt in all_cons_opts:
+                        if is_multi:
+                            if not opt.impl_is_master_slaves():
+                                raise ValueError(_('malformed consistency option {0} '
+                                                   'must not be a multi for {1}').format(
+                                                       option.impl_getname(), opt.impl_getname()))
+                            elif masterslaves != opt.impl_get_master_slaves():
+                                raise ValueError(_('malformed consistency option {0} '
+                                                   'must be in same master/slaves for {1}').format(
+                                                       option.impl_getname(), opt.impl_getname()))
                         _consistencies.setdefault(opt,
                                                   []).append((func,
                                                              all_cons_opts,
                                                              params))
                 is_slave = None
-                if option.impl_is_multi():
+                if is_multi:
                     all_requires = option.impl_getrequires()
                     if all_requires != tuple():
                         for requires in all_requires:
index 9dfccfa..3ed9ec8 100644 (file)
@@ -19,7 +19,7 @@
 # ____________________________________________________________
 from ...i18n import _
 from ...setting import undefined
-from ...error import ConfigError, ContextError
+from ...error import ConfigError
 static_tuple = tuple()
 static_set = frozenset()
 
@@ -94,15 +94,12 @@ class StorageBase(object):
             _setattr(self, '_default', default)
 
         if is_multi and default_multi is not None:
-            try:
-                self._validate(default_multi)
-            except ValueError as err:  # pragma: optional cover
+            err = self._validate(default_multi)
+            if err:
                 raise ValueError(_("invalid default_multi value {0} "
                                    "for option {1}: {2}").format(
                                        str(default_multi),
                                        self.impl_getname(), str(err)))
-            except ContextError, err:
-                pass
             _setattr(self, '_default_multi', default_multi)
 
     # information
index 3a63c48..ee638ab 100644 (file)
@@ -326,7 +326,9 @@ class _Base(SqlAlchemyBase):
     def _set_default_values(self, default, default_multi):
         self._default = default
         if self.impl_is_multi() and default_multi is not None:
-            self._validate(default_multi)
+            err = self._validate(default_multi)
+            if err:
+                raise err
             self._default_multi = default_multi
 
     def _get_consistencies(self):
index 4ffd86a..0fc1ee5 100644 (file)
@@ -78,7 +78,8 @@ class Values(object):
             if meta is not None:
                 try:
                     value = meta.cfgimpl_get_values(
-                    )._get_cached_value(opt, path, index=index, from_masterslave=True)
+                    )._get_cached_value(opt, path, index=index, submulti_index=submulti_index,
+                                        from_masterslave=True)
                     if isinstance(value, Multi):
                         if index is not None:
                             value = value[index]
@@ -207,8 +208,8 @@ class Values(object):
                           force_permissive=False, trusted_cached_properties=True,
                           validate_properties=True,
                           setting_properties=undefined, self_properties=undefined,
-                          index=None, from_masterslave=False, with_meta=True,
-                          masterlen=undefined, check_frozen=False):
+                          index=None, submulti_index=undefined, from_masterslave=False,
+                          with_meta=True, masterlen=undefined, check_frozen=False):
         context = self._getcontext()
         settings = context.cfgimpl_get_settings()
         if path is None:
@@ -257,6 +258,7 @@ class Values(object):
                                             with_meta=with_meta,
                                             masterlen=masterlen,
                                             index=index,
+                                            submulti_index=submulti_index,
                                             check_frozen=check_frozen)
         # cache doesn't work with SubMulti yet
         if not isinstance(val, SubMulti) and 'cache' in setting_properties and \
@@ -325,12 +327,11 @@ class Values(object):
                     force_submulti_index = None
                 else:
                     force_submulti_index = submulti_index
-                try:
-                    opt.impl_validate(value, context,
-                                      'validator' in setting_properties,
-                                      force_index=force_index,
-                                      force_submulti_index=force_submulti_index)
-                except ValueError, err:
+                err = opt.impl_validate(value, context,
+                                        'validator' in setting_properties,
+                                        force_index=force_index,
+                                        force_submulti_index=force_submulti_index)
+                if err:
                     config_error = err
                     value = None
 
@@ -373,13 +374,15 @@ class Values(object):
         if 'validator' in setting_properties:
             fake_context = context._gen_fake_values()
             fake_values = fake_context.cfgimpl_get_values()
+            fake_values._setvalue(opt, path, value)
             props = fake_values.validate(opt, value, path, check_frozen,
                                          force_permissive, setting_properties,
                                          not_raises=not_raises)
             if props and not_raises:
                 return
-            fake_values._setvalue(opt, path, value)
-            opt.impl_validate(value, fake_context)
+            err = opt.impl_validate(value, fake_context)
+            if err:
+                raise err
         self._setvalue(opt, path, value)
 
     def _setvalue(self, opt, path, value):
@@ -811,8 +814,10 @@ class Multi(list):
         self._store()
 
     def _validate(self, value, fake_context, force_index, submulti=False):
-        self.opt.impl_validate(value, context=fake_context,
-                               force_index=force_index)
+        err = self.opt.impl_validate(value, context=fake_context,
+                                     force_index=force_index)
+        if err:
+            raise err
 
     def pop(self, index, force=False):
         """the list value can be updated (poped)
@@ -877,9 +882,11 @@ class SubMulti(Multi):
                 super(SubMulti, self)._validate(value, fake_context,
                                                 force_index, submulti)
             else:
-                self.opt.impl_validate(value, context=fake_context,
-                                       force_index=self._index,
-                                       force_submulti_index=force_index)
+                err = self.opt.impl_validate(value, context=fake_context,
+                                             force_index=self._index,
+                                             force_submulti_index=force_index)
+                if err:
+                    raise err
 
     def _get_validated_value(self, index):
         values = self._getcontext().cfgimpl_get_values()