diff --git a/test/test_dyn_optiondescription.py b/test/test_dyn_optiondescription.py index 8cec2a2..e911b35 100644 --- a/test/test_dyn_optiondescription.py +++ b/test/test_dyn_optiondescription.py @@ -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) diff --git a/test/test_metaconfig.py b/test/test_metaconfig.py index 69c4087..e53b4dc 100644 --- a/test/test_metaconfig.py +++ b/test/test_metaconfig.py @@ -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',)) diff --git a/test/test_option_consistency.py b/test/test_option_consistency.py index 323f6e4..0c19fa7 100644 --- a/test/test_option_consistency.py +++ b/test/test_option_consistency.py @@ -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'] diff --git a/test/test_option_validator.py b/test/test_option_validator.py index 2ba9aec..5af5a56 100644 --- a/test/test_option_validator.py +++ b/test/test_option_validator.py @@ -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(): diff --git a/tiramisu/autolib.py b/tiramisu/autolib.py index 634eac1..ace2c0a 100644 --- a/tiramisu/autolib.py +++ b/tiramisu/autolib.py @@ -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)) diff --git a/tiramisu/error.py b/tiramisu/error.py index 93e93f9..163c7c3 100644 --- a/tiramisu/error.py +++ b/tiramisu/error.py @@ -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 diff --git a/tiramisu/option/baseoption.py b/tiramisu/option/baseoption.py index 41ca14c..09b9034 100644 --- a/tiramisu/option/baseoption.py +++ b/tiramisu/option/baseoption.py @@ -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) - 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())) + 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 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) + 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: + for idx, val in enumerate(value): + 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') diff --git a/tiramisu/option/masterslave.py b/tiramisu/option/masterslave.py index b982aba..0a774e5 100644 --- a/tiramisu/option/masterslave.py +++ b/tiramisu/option/masterslave.py @@ -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, diff --git a/tiramisu/option/option.py b/tiramisu/option/option.py index 0ae7094..1ad49d8 100644 --- a/tiramisu/option/option.py +++ b/tiramisu/option/option.py @@ -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 diff --git a/tiramisu/option/optiondescription.py b/tiramisu/option/optiondescription.py index 0e75e9c..4c78d9a 100644 --- a/tiramisu/option/optiondescription.py +++ b/tiramisu/option/optiondescription.py @@ -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: diff --git a/tiramisu/storage/dictionary/option.py b/tiramisu/storage/dictionary/option.py index 9dfccfa..3ed9ec8 100644 --- a/tiramisu/storage/dictionary/option.py +++ b/tiramisu/storage/dictionary/option.py @@ -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 diff --git a/tiramisu/storage/sqlalchemy/option.py b/tiramisu/storage/sqlalchemy/option.py index 3a63c48..ee638ab 100644 --- a/tiramisu/storage/sqlalchemy/option.py +++ b/tiramisu/storage/sqlalchemy/option.py @@ -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): diff --git a/tiramisu/value.py b/tiramisu/value.py index 4ffd86a..0fc1ee5 100644 --- a/tiramisu/value.py +++ b/tiramisu/value.py @@ -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()