diff --git a/test/test_dyn_optiondescription.py b/test/test_dyn_optiondescription.py index 254acf4..d6e798a 100644 --- a/test/test_dyn_optiondescription.py +++ b/test/test_dyn_optiondescription.py @@ -1064,7 +1064,7 @@ def test_masterslaves_submulti_dyndescription(): assert cfg.getowner(st1val1) == owner assert cfg.getowner(st1val2) == owners.default assert cfg.getowner(st2val1, 0) == owner -# assert cfg.getowner(st2val2) == owners.default + assert cfg.getowner(st2val2) == owners.default def test_masterslaves_consistency_ip_dyndescription(): @@ -1094,6 +1094,22 @@ def test_masterslaves_consistency_ip_dyndescription(): assert cfg.netval2.broadval2 == [] +def test_masterslaves_consistency_ip_dyndescription_propertyerror(): + a = NetworkOption('net', '', multi=True) + b = NetmaskOption('mask', '', multi=True, properties=('mandatory',)) + c = BroadcastOption('broad', '', multi=True) + b.impl_add_consistency('network_netmask', a) + c.impl_add_consistency('broadcast', a, b) + dod = DynOptionDescription('net', '', [a, b, c], callback=return_list) + dod.impl_set_group_type(groups.master) + od = OptionDescription('od', '', [dod]) + cfg = Config(od) + cfg.read_write() + cfg.netval1.netval1 = ['192.168.1.0'] + cfg.read_only() + raises(PropertiesOptionError, "cfg.netval1.netval1") + + def test_masterslaves_callback_dyndescription(): st1 = StrOption('st1', "", multi=True) st2 = StrOption('st2', "", multi=True, callback=return_dynval, callback_params={'value': ((st1, False),)}) diff --git a/test/test_parsing_group.py b/test/test_parsing_group.py index c091aa0..dc34954 100644 --- a/test/test_parsing_group.py +++ b/test/test_parsing_group.py @@ -341,6 +341,13 @@ def test_reset_values_with_master_and_slaves(): assert cfg.ip_admin_eth0.netmask_admin_eth0 == [] +def test_reset_values_with_master_and_slaves_default_value(): + ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True, default=['192.168.230.145']) + netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True, default=['255.255.255.0']) + interface1 = OptionDescription('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0]) + raises(ValueError, "interface1.impl_set_group_type(groups.master)") + + def test_reset_values_with_master_and_slaves_default(): ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True, default=['192.168.230.145']) netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True) diff --git a/tiramisu/error.py b/tiramisu/error.py index 7407d41..987263e 100644 --- a/tiramisu/error.py +++ b/tiramisu/error.py @@ -56,24 +56,40 @@ class PropertiesOptionError(AttributeError): self._settings = settings self._datas = datas self._type = option_type + self._orig_opt = None super(PropertiesOptionError, self).__init__(msg) + def set_orig_opt(self, opt): + self._orig_opt = opt + def __str__(self): #this part is a bit slow, so only execute when display if self._settings is None: req = {} else: req = self._settings.apply_requires(**self._datas) - if req != {}: - msg = [] - for action, msg_ in req.items(): - msg.append('{0} ({1})'.format(action, display_list(msg_))) - if len(req) == 1: + if req != {} or self._orig_opt is not None: + if req != {}: + only_one = len(req) == 1 + msg = [] + for action, msg_ in req.items(): + msg.append('{0} ({1})'.format(action, display_list(msg_))) + else: + only_one = len(self.proptype) == 1 + msg = self.proptype + if only_one: prop_msg = _('property') else: prop_msg = _('properties') msg = display_list(msg) - return str(_('cannot access to {0} "{1}" because has {2} {3}').format(self._type, self._datas['opt'].impl_get_display_name(), prop_msg, msg)) + if self._orig_opt: + return str(_('cannot access to {0} "{1}" because "{2}" has {3} {4}').format(self._type, + self._orig_opt.impl_get_display_name(), + self._datas['opt'].impl_get_display_name(), + prop_msg, + msg)) + else: + return str(_('cannot access to {0} "{1}" because has {2} {3}').format(self._type, self._datas['opt'].impl_get_display_name(), prop_msg, msg)) else: return super(PropertiesOptionError, self).__str__() diff --git a/tiramisu/option/baseoption.py b/tiramisu/option/baseoption.py index b4883a2..81f6b01 100644 --- a/tiramisu/option/baseoption.py +++ b/tiramisu/option/baseoption.py @@ -404,10 +404,13 @@ class BaseOption(Base): if not isinstance(value, unicode) and not isinstance(value, str): return ValueError(_('invalid unicode or string')) - def impl_get_display_name(self): + def impl_get_display_name(self, dyn_name=None): name = self.impl_getdoc() if name is None or name == '': - name = self.impl_getname() + if dyn_name is not None: + name = dyn_name + else: + name = self.impl_getname() if isinstance(name, unicode): name = name.encode('utf8') return name @@ -483,6 +486,7 @@ class Option(OnlyOption): if debug: # pragma: no cover log.debug('propertyerror in _launch_consistency: {0}'.format(opt_value)) if transitive: + opt_value.set_orig_opt(option) return opt_value else: opt_value = None @@ -1073,6 +1077,9 @@ class DynSymLinkOption(object): def impl_getname(self): return self._name + def impl_get_display_name(self): + return self._impl_getopt().impl_get_display_name(dyn_name=self.impl_getname()) + def _impl_getopt(self): return self._opt diff --git a/tiramisu/option/masterslave.py b/tiramisu/option/masterslave.py index 21048c9..972c4ef 100644 --- a/tiramisu/option/masterslave.py +++ b/tiramisu/option/masterslave.py @@ -32,28 +32,29 @@ class MasterSlaves(object): __slots__ = ('_p_') def __init__(self, name, childs=None, validate=True, add=True): - #if master (same name has group) is set - #for collect all slaves - if isinstance(name, StorageMasterSlaves): + if isinstance(name, StorageMasterSlaves): # pragma: no cover + # only for sqlalchemy self._p_ = name else: + #if master (same name has group) is set + #for collect all slaves slaves = [] if childs[0].impl_getname() == name: master = childs[0] else: raise ValueError(_('master group with wrong' ' master name for {0}' - ).format(name)) + ).format(name)) for child in childs[1:]: if child.impl_getdefault() != []: raise ValueError(_("not allowed default value for option {0} " - "in group {1}").format(child.impl_getname(), - name)) + "in master/slave object {1}").format(child.impl_getname(), + name)) slaves.append(child) if validate: callback, callback_params = master.impl_get_callback() - if callback is not None and callback_params != {}: # pragma: optional cover - for key, callbacks in callback_params.items(): + if callback is not None and callback_params != {}: + for callbacks in callback_params.values(): for callbk in callbacks: if isinstance(callbk, tuple): if callbk[0] in slaves: @@ -88,14 +89,14 @@ class MasterSlaves(object): base_path = opt._dyn.split('.')[0] + '.' path = base_path + name yield slave._impl_to_dyn(name, path) - else: # pragma: no dynoptiondescription cover + else: for slave in self._p_._sm_getslaves(): yield slave def in_same_group(self, opt): if opt.impl_is_dynsymlinkoption(): return opt._opt == self._p_._sm_getmaster() or opt._opt in self._p_._sm_getslaves() - else: # pragma: no dynoptiondescription cover + else: return opt == self._p_._sm_getmaster() or opt in self._p_._sm_getslaves() def reset(self, opt, values, setting_properties): @@ -181,6 +182,8 @@ class MasterSlaves(object): undefined, force_permissive, master=master) if isinstance(masterlen, Exception): + if isinstance(masterlen, PropertiesOptionError): + masterlen.set_orig_opt(opt) return masterlen master_is_meta = values._is_meta(master, masterp, session) multi = values._get_multi(opt, path) @@ -264,8 +267,8 @@ class MasterSlaves(object): return len(value) def validate_slave_length(self, masterlen, valuelen, name, opt, setitem=False): - if valuelen > masterlen or (valuelen < masterlen and setitem): # pragma: optional cover - if debug: + if valuelen > masterlen or (valuelen < masterlen and setitem): + if debug: # pragma: no cover log.debug('validate_slave_length: masterlen: {0}, valuelen: {1}, ' 'setitem: {2}'.format(masterlen, valuelen, setitem)) raise SlaveError(_("invalid len for the slave: {0}" diff --git a/tiramisu/setting.py b/tiramisu/setting.py index ab6bede..8a99795 100644 --- a/tiramisu/setting.py +++ b/tiramisu/setting.py @@ -514,16 +514,14 @@ class Settings(object): prop_msg = _('property') else: prop_msg = _('properties') - name = opt_or_descr.impl_get_display_name() - if isinstance(name, unicode): - name = name.encode('utf8') return PropertiesOptionError(_('cannot access to {0} "{1}" ' 'because has {2} {3}' '').format(opt_type, - name, + opt_or_descr.impl_get_display_name(), prop_msg, - display_list(props)), props, - self, datas, opt_type) + display_list(props)), + props, + self, datas, opt_type) def setpermissive(self, permissive, opt=None, path=None): """