diff --git a/ChangeLog b/ChangeLog index 4f15433..53ab5f1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +Mon Oct 10 21:39:04 2016 +0200 Emmanuel Garette + * consistency with default value for all values now works + * warnings works now even if default value is None + Thu Sep 22 08:25:33 2016 +0200 Emmanuel Garette * force_store_value is rebuild if needed diff --git a/test/test_option_consistency.py b/test/test_option_consistency.py index 0c19fa7..a5fedc4 100644 --- a/test/test_option_consistency.py +++ b/test/test_option_consistency.py @@ -55,6 +55,23 @@ def test_consistency_warnings_only(): assert w != [] +def test_consistency_warnings_only_more_option(): + a = IntOption('a', '') + b = IntOption('b', '') + d = IntOption('d', '') + od = OptionDescription('od', '', [a, b, d]) + a.impl_add_consistency('not_equal', b, d, warnings_only=True) + c = Config(od) + c.a = 1 + warnings.simplefilter("always", ValueWarning) + with warnings.catch_warnings(record=True) as w: + c.b = 1 + assert w != [] + with warnings.catch_warnings(record=True) as w: + c.d = 1 + assert w != [] + + def test_consistency_not_equal(): a = IntOption('a', '') b = IntOption('b', '') @@ -283,10 +300,7 @@ def test_consistency_ip_in_network_len_error(): b = NetmaskOption('b', '') c = IPOption('c', '') od = OptionDescription('od', '', [a, b, c]) - c.impl_add_consistency('in_network', a) - cfg = Config(od) - cfg - raises(ConfigError, "cfg.a = '192.168.2.0'") + raises(ConfigError, "c.impl_add_consistency('in_network', a)") def test_consistency_ip_netmask_network_error(): @@ -338,6 +352,17 @@ def test_consistency_network_netmask_multi(): raises(ValueError, "c.a = ['192.168.1.1']") +def test_consistency_network_netmask_multi_slave_default_multi(): + a = NetworkOption('a', '', default_multi=u'192.168.1.0', multi=True, properties=('mandatory',)) + b = NetmaskOption('b', '', default_multi=u'255.255.255.0', multi=True, properties=('mandatory',)) + od = OptionDescription('a', '', [a, b]) + od.impl_set_group_type(groups.master) + b.impl_add_consistency('network_netmask', a) + c = Config(od) + c.read_write() + c.a.append() + + def test_consistency_network_netmask_multi_slave_default(): a = NetworkOption('a', '', multi=True, properties=('mandatory',)) b = NetmaskOption('b', '', default_multi=u'255.255.255.0', multi=True, properties=('mandatory',)) diff --git a/test/test_option_validator.py b/test/test_option_validator.py index 54a44f4..eedffb6 100644 --- a/test/test_option_validator.py +++ b/test/test_option_validator.py @@ -11,7 +11,7 @@ from tiramisu.error import ValueWarning from tiramisu.i18n import _ -msg_err = _("attention, {0} could be an invalid {1} for option {2}, {3}") +msg_err = _('attention, "{0}" could be an invalid {1} for "{2}", {3}') def return_true(value, param=None): @@ -99,7 +99,7 @@ def test_validator_warning(): cfg.opt2 = 'val' assert len(w) == 1 assert w[0].message.opt == opt2 - assert str(w[0].message) == msg_err.format('val', opt2.display_name, 'opt2', 'test error') + assert str(w[0].message) == msg_err.format('val', opt2._display_name, 'opt2', 'test error') # with warnings.catch_warnings(record=True) as w: cfg.opt3.append('val') @@ -109,7 +109,7 @@ def test_validator_warning(): cfg.opt3.append('val1') assert len(w) == 1 assert w[0].message.opt == opt3 - assert str(w[0].message) == msg_err.format('val1', opt3.display_name, 'opt3', 'test error') + assert str(w[0].message) == msg_err.format('val1', opt3._display_name, 'opt3', 'test error') raises(ValueError, "cfg.opt2 = 1") # with warnings.catch_warnings(record=True) as w: @@ -117,9 +117,9 @@ def test_validator_warning(): cfg.opt3.append('val') assert len(w) == 2 assert w[0].message.opt == opt2 - assert str(w[0].message) == msg_err.format('val', opt2.display_name, 'opt2', 'test error') + assert str(w[0].message) == msg_err.format('val', opt2._display_name, 'opt2', 'test error') assert w[1].message.opt == opt3 - assert str(w[0].message) == msg_err.format('val', opt2.display_name, 'opt2', 'test error') + assert str(w[0].message) == msg_err.format('val', opt2._display_name, 'opt2', 'test error') def test_validator_warning_disabled(): @@ -155,8 +155,10 @@ def test_validator_warning_disabled(): def test_validator_warning_master_slave(): - ip_admin_eth0 = StrOption('ip_admin_eth0', "ip reseau autorise", multi=True, validator=return_false, warnings_only=True) - netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-reseau", multi=True, validator=return_if_val, warnings_only=True) + display_name_ip = "ip reseau autorise" + display_name_netmask = "masque du sous-reseau" + ip_admin_eth0 = StrOption('ip_admin_eth0', display_name_ip, multi=True, validator=return_false, warnings_only=True) + netmask_admin_eth0 = StrOption('netmask_admin_eth0', display_name_netmask, multi=True, validator=return_if_val, warnings_only=True) interface1 = OptionDescription('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0]) interface1.impl_set_group_type(groups.master) assert interface1.impl_get_group_type() == groups.master @@ -171,29 +173,29 @@ def test_validator_warning_master_slave(): cfg.ip_admin_eth0.netmask_admin_eth0 = ['val1'] assert len(w) == 1 assert w[0].message.opt == netmask_admin_eth0 - assert str(w[0].message) == msg_err.format('val1', netmask_admin_eth0.display_name, 'netmask_admin_eth0', 'test error') + assert str(w[0].message) == msg_err.format('val1', netmask_admin_eth0._display_name, display_name_netmask, 'test error') # with warnings.catch_warnings(record=True) as w: cfg.ip_admin_eth0.ip_admin_eth0 = ['val'] assert len(w) == 1 assert w[0].message.opt == ip_admin_eth0 - assert str(w[0].message) == msg_err.format('val', ip_admin_eth0.display_name, 'ip_admin_eth0', 'test error') + assert str(w[0].message) == msg_err.format('val', ip_admin_eth0._display_name, display_name_ip, 'test error') # with warnings.catch_warnings(record=True) as w: cfg.ip_admin_eth0.ip_admin_eth0 = ['val', 'val1', 'val1'] assert len(w) == 1 assert w[0].message.opt == ip_admin_eth0 - assert str(w[0].message) == msg_err.format('val', ip_admin_eth0.display_name, 'ip_admin_eth0', 'test error') + assert str(w[0].message) == msg_err.format('val', ip_admin_eth0._display_name, display_name_ip, 'test error') # with warnings.catch_warnings(record=True) as w: cfg.ip_admin_eth0.ip_admin_eth0 = ['val1', 'val', 'val1'] assert len(w) == 1 assert w[0].message.opt == ip_admin_eth0 - assert str(w[0].message) == msg_err.format('val', ip_admin_eth0.display_name, 'ip_admin_eth0', 'test error') + assert str(w[0].message) == msg_err.format('val', ip_admin_eth0._display_name, display_name_ip, 'test error') # warnings.resetwarnings() with warnings.catch_warnings(record=True) as w: cfg.ip_admin_eth0.ip_admin_eth0 = ['val1', 'val1', 'val'] assert len(w) == 1 assert w[0].message.opt == ip_admin_eth0 - assert str(w[0].message) == msg_err.format('val', ip_admin_eth0.display_name, 'ip_admin_eth0', 'test error') + assert str(w[0].message) == msg_err.format('val', ip_admin_eth0._display_name, display_name_ip, 'test error') diff --git a/tiramisu/option/baseoption.py b/tiramisu/option/baseoption.py index 55aaf71..de2e35f 100644 --- a/tiramisu/option/baseoption.py +++ b/tiramisu/option/baseoption.py @@ -367,8 +367,8 @@ class Option(OnlyOption): __slots__ = tuple() _empty = '' - def _launch_consistency(self, func, option, value, context, index, - submulti_index, all_cons_opts, warnings_only, + def _launch_consistency(self, current_opt, func, option, value, context, + index, submulti_index, all_cons_opts, warnings_only, transitive): """Launch consistency now @@ -434,7 +434,7 @@ class Option(OnlyOption): #only check properties for slaves val_consistencies = False if val_consistencies: - return getattr(self, func)(all_cons_opts, all_cons_vals, warnings_only) + return getattr(self, func)(current_opt, all_cons_opts, all_cons_vals, warnings_only) def impl_validate(self, value, context=undefined, validate=True, force_index=None, force_submulti_index=None, @@ -483,37 +483,41 @@ class Option(OnlyOption): def do_validation(_value, _index, submulti_index): if _value is None: - return - # option validation - err = self._validate(_value, context, current_opt, - returns_raise=True) - if err: - if debug: - log.debug('do_validation: value: {0}, index: {1}, ' - 'submulti_index: {2}'.format(_value, _index, - submulti_index), - exc_info=True) - err_msg = '{0}'.format(err) - if err_msg: - msg = _('{0} is an invalid {1} for option {2}, {3}' - '').format(_value, self.display_name, - self.impl_getname(), err_msg) - else: - msg = _('{0} is an invalid {1} for option {2}' - '').format(_value, self.display_name, - self.impl_getname()) - return ValueError(msg) - warning = None - error = calculation_validator(_value) - if not error: - error = self._second_level_validation(_value, self._is_warnings_only()) - if error: - if debug: - 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 + error = warning = None + else: + # option validation + err = self._validate(_value, context, current_opt, + returns_raise=True) + if err: + if debug: + log.debug('do_validation: value: {0}, index: {1}, ' + 'submulti_index: {2}'.format(_value, _index, + submulti_index), + exc_info=True) + err_msg = '{0}'.format(err) + name = self.impl_getdoc() + if name is None or name == '': + name = self.impl_getname() + if err_msg: + msg = _('"{0}" is an invalid {1} for "{2}", {3}' + '').format(_value, self._display_name, + self.impl_get_display_name(), err_msg) + else: + msg = _('"{0}" is an invalid {1} for "{2}"' + '').format(_value, self._display_name, + self.impl_get_display_name()) + return ValueError(msg) + warning = None + error = calculation_validator(_value) + if not error: + error = self._second_level_validation(_value, self._is_warnings_only()) + if error: + if debug: + 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: # if context launch consistency validation #if context is not undefined: @@ -527,8 +531,8 @@ class Option(OnlyOption): else: return ret if warning: - msg = _("attention, {0} could be an invalid {1} for option {2}, {3}").format( - _value, self.display_name, self.impl_getname(), warning) + msg = _('attention, "{0}" could be an invalid {1} for "{2}", {3}').format( + _value, self._display_name, self.impl_get_display_name(), warning) if context is undefined or 'warnings' in \ context.cfgimpl_get_settings(): warnings.warn_explicit(ValueWarning(msg, self), @@ -537,13 +541,13 @@ class Option(OnlyOption): elif error: err_msg = '{0}'.format(error) if err_msg: - msg = _("{0} is an invalid {1} for option {2}, {3}" - "").format(_value, self.display_name, - self.impl_getname(), err_msg) + msg = _('"{0}" is an invalid {1} for "{2}", {3}' + '').format(_value, self._display_name, + self.impl_get_display_name(), err_msg) else: - msg = _("{0} is an invalid {1} for option {2}" - "").format(_value, self.display_name, - self.impl_getname()) + msg = _('"{0}" is an invalid {1} for "{2}"' + '').format(_value, self._display_name, + self.impl_get_display_name()) return ValueError(msg) # generic calculation @@ -618,6 +622,12 @@ class Option(OnlyOption): "accesses the Option's doc" return self.impl_get_information('doc') + def impl_get_display_name(self): + name = self.impl_getdoc() + if name is None or name == '': + name = self.impl_getname() + return name + def _valid_consistencies(self, other_opts): if self._is_subdyn(): dynod = self._impl_getsubdyn() @@ -706,27 +716,42 @@ class Option(OnlyOption): opts.append(opt._impl_to_dyn(name, path)) else: opts = all_cons_opts - err = opts[0]._launch_consistency(func, option, value, context, - index, submulti_idx, opts, - warnings_only, transitive) + err = opts[0]._launch_consistency(self, func, option, value, + context, index, submulti_idx, + opts, warnings_only, + transitive) if err: if warnings_only: return ValueWarning(str(err), option) else: return err - def _cons_not_equal(self, opts, vals, warnings_only): + def _cons_not_equal(self, current_opt, opts, vals, warnings_only): + equal = set() + is_current = False for idx_inf, val_inf in enumerate(vals): for idx_sup, val_sup in enumerate(vals[idx_inf + 1:]): if val_inf == val_sup is not None: - if warnings_only: - msg = _("value for {0} and {1} should be different") - else: - msg = _("value for {0} and {1} must be different") - if debug: - log.debug('_cons_not_equal: {0} and {1} are not different'.format(val_inf, val_sup)) - return ValueError(msg.format(opts[idx_inf].impl_getname(), - opts[idx_inf + idx_sup + 1].impl_getname())) + for opt_ in [opts[idx_inf], opts[idx_inf + idx_sup + 1]]: + if opt_ == current_opt: + is_current = True + else: + equal.add('"{}"'.format(opt_.impl_get_display_name())) + if equal: + if debug: + log.debug(_('_cons_not_equal: {} are not different').format(display_list(list(equal)))) + if is_current: + if warnings_only: + msg = _('should be different from the value of {}') + else: + msg = _('must be different from the value of {}') + return ValueError(msg.format(display_list(list(equal)))) + else: + if warnings_only: + msg = _('value for {} should be different') + else: + msg = _('value for {} must be different') + return ValueError(msg.format(display_list(list(equal)))) # serialize/unserialize def _impl_convert_consistencies(self, descr, load=False): diff --git a/tiramisu/option/option.py b/tiramisu/option/option.py index e90fb77..1ec35e4 100644 --- a/tiramisu/option/option.py +++ b/tiramisu/option/option.py @@ -36,8 +36,8 @@ class ChoiceOption(Option): The option can also have the value ``None`` """ - __slots__ = tuple('_init') - display_name = _('choice') + __slots__ = tuple() + _display_name = _('choice') def __init__(self, name, doc, values, default=None, values_params=None, default_multi=None, requires=None, @@ -56,9 +56,7 @@ class ChoiceOption(Option): raise TypeError(_('values must be a tuple or a function for {0}' ).format(name)) session = self.getsession() - #cannot add values and values_params in database before add option - #set in _init temporary - self._init = (values, values_params) + self.impl_set_choice_values_params(values, values_params, session) super(ChoiceOption, self).__init__(name, doc, default=default, default_multi=default_multi, callback=callback, @@ -70,9 +68,7 @@ class ChoiceOption(Option): properties=properties, warnings_only=warnings_only, session=session) - self.impl_set_choice_values_params(values, values_params, session) - session.commit() - del(self._init) + self.commit(session) def impl_get_values(self, context, current_opt=undefined, returns_raise=False): @@ -80,10 +76,7 @@ class ChoiceOption(Option): current_opt = self params = undefined #FIXME cache? but in context... - if '_init' in dir(self): - values, params = self._init - else: - values = self._choice_values + values = self._choice_values if isinstance(values, FunctionType): if context is None: values = [] @@ -122,7 +115,7 @@ class ChoiceOption(Option): class BoolOption(Option): "represents a choice between ``True`` and ``False``" __slots__ = tuple() - display_name = _('boolean') + _display_name = _('boolean') def _validate(self, value, context=undefined, current_opt=undefined, returns_raise=False): @@ -133,7 +126,7 @@ class BoolOption(Option): class IntOption(Option): "represents a choice of an integer" __slots__ = tuple() - display_name = _('integer') + _display_name = _('integer') def _validate(self, value, context=undefined, current_opt=undefined, returns_raise=False): @@ -144,7 +137,7 @@ class IntOption(Option): class FloatOption(Option): "represents a choice of a floating point number" __slots__ = tuple() - display_name = _('float') + _display_name = _('float') def _validate(self, value, context=undefined, current_opt=undefined, returns_raise=False): @@ -155,7 +148,7 @@ class FloatOption(Option): class StrOption(Option): "represents the choice of a string" __slots__ = tuple() - display_name = _('string') + _display_name = _('string') def _validate(self, value, context=undefined, current_opt=undefined, returns_raise=False): @@ -173,7 +166,7 @@ else: "represents the choice of a unicode string" __slots__ = tuple() _empty = u'' - display_name = _('unicode string') + _display_name = _('unicode string') def _validate(self, value, context=undefined, current_opt=undefined, returns_raise=False): @@ -184,7 +177,7 @@ else: class PasswordOption(Option): "represents the choice of a password" __slots__ = tuple() - display_name = _('password') + _display_name = _('password') def _validate(self, value, context=undefined, current_opt=undefined, returns_raise=False): @@ -196,7 +189,7 @@ class PasswordOption(Option): class IPOption(Option): "represents the choice of an ip" __slots__ = tuple() - display_name = _('IP') + _display_name = _('IP') def __init__(self, name, doc, default=None, default_multi=None, requires=None, multi=False, callback=None, @@ -250,7 +243,7 @@ class IPOption(Option): msg = _("must be in private class") return ValueError(msg) - def _cons_in_network(self, opts, vals, warnings_only): + def _cons_in_network(self, current_opt, opts, vals, warnings_only): if len(vals) != 3: raise ConfigError(_('invalid len for vals')) # pragma: optional cover if None in vals: @@ -264,7 +257,7 @@ class IPOption(Option): return ValueError(msg.format(network, netmask, opts[1].impl_getname(), opts[2].impl_getname())) # test if ip is not network/broadcast IP - return opts[2]._cons_ip_netmask((opts[2], opts[0]), (netmask, ip), warnings_only) + return opts[2]._cons_ip_netmask(current_opt, (opts[2], opts[0]), (netmask, ip), warnings_only) class PortOption(Option): @@ -279,7 +272,7 @@ class PortOption(Option): """ __slots__ = tuple() port_re = re.compile(r"^[0-9]*$") - display_name = _('port') + _display_name = _('port') def __init__(self, name, doc, default=None, default_multi=None, requires=None, multi=False, callback=None, @@ -355,7 +348,7 @@ class PortOption(Option): class NetworkOption(Option): "represents the choice of a network" __slots__ = tuple() - display_name = _('network address') + _display_name = _('network address') def _validate(self, value, context=undefined, current_opt=undefined, returns_raise=False): @@ -385,7 +378,7 @@ class NetworkOption(Option): class NetmaskOption(Option): "represents the choice of a netmask" __slots__ = tuple() - display_name = _('netmask address') + _display_name = _('netmask address') def _validate(self, value, context=undefined, current_opt=undefined, returns_raise=False): @@ -402,13 +395,13 @@ class NetmaskOption(Option): except ValueError: # pragma: optional cover return ValueError() - def _cons_network_netmask(self, opts, vals, warnings_only): + def _cons_network_netmask(self, current_opt, opts, vals, warnings_only): #opts must be (netmask, network) options if None in vals: return return self.__cons_netmask(opts, vals[0], vals[1], False, warnings_only) - def _cons_ip_netmask(self, opts, vals, warnings_only): + def _cons_ip_netmask(self, current_opt, opts, vals, warnings_only): #opts must be (netmask, ip) options if None in vals: return @@ -439,7 +432,7 @@ class NetmaskOption(Option): class BroadcastOption(Option): __slots__ = tuple() - display_name = _('broadcast address') + _display_name = _('broadcast address') def _validate(self, value, context=undefined, current_opt=undefined, returns_raise=False): @@ -451,7 +444,7 @@ class BroadcastOption(Option): except ValueError: # pragma: optional cover return ValueError() - def _cons_broadcast(self, opts, vals, warnings_only): + def _cons_broadcast(self, current_opt, opts, vals, warnings_only): if len(vals) != 3: raise ConfigError(_('invalid len for vals')) # pragma: optional cover if None in vals: @@ -470,7 +463,7 @@ class DomainnameOption(Option): fqdn: with tld, not supported yet """ __slots__ = tuple() - display_name = _('domain name') + _display_name = _('domain name') def __init__(self, name, doc, default=None, default_multi=None, requires=None, multi=False, callback=None, @@ -569,7 +562,7 @@ class DomainnameOption(Option): class EmailOption(DomainnameOption): __slots__ = tuple() username_re = re.compile(r"^[\w!#$%&'*+\-/=?^`{|}~.]+$") - display_name = _('email address') + _display_name = _('email address') def _validate(self, value, context=undefined, current_opt=undefined, returns_raise=False): @@ -595,7 +588,7 @@ class URLOption(DomainnameOption): __slots__ = tuple() proto_re = re.compile(r'(http|https)://') path_re = re.compile(r"^[A-Za-z0-9\-\._~:/\?#\[\]@!%\$&\'\(\)\*\+,;=]+$") - display_name = _('URL') + _display_name = _('URL') def _validate(self, value, context=undefined, current_opt=undefined, returns_raise=False): @@ -643,7 +636,7 @@ class UsernameOption(Option): __slots__ = tuple() #regexp build with 'man 8 adduser' informations username_re = re.compile(r"^[a-z_][a-z0-9_-]{0,30}[$a-z0-9_-]{0,1}$") - display_name = _('username') + _display_name = _('username') def _validate(self, value, context=undefined, current_opt=undefined, returns_raise=False): @@ -658,7 +651,7 @@ class UsernameOption(Option): class FilenameOption(Option): __slots__ = tuple() path_re = re.compile(r"^[a-zA-Z0-9\-\._~/+]+$") - display_name = _('file name') + _display_name = _('file name') def _validate(self, value, context=undefined, current_opt=undefined, returns_raise=False): diff --git a/tiramisu/storage/dictionary/option.py b/tiramisu/storage/dictionary/option.py index e9b49a8..aa9ae13 100644 --- a/tiramisu/storage/dictionary/option.py +++ b/tiramisu/storage/dictionary/option.py @@ -165,7 +165,7 @@ class StorageBase(object): val_call = tuple([callback, callback_params]) self._val_call = (val, val_call) - def impl_set_choice_values_params(self, values, values_params): + def impl_set_choice_values_params(self, values, values_params, session): self._choice_values = values if values_params is not None: self._choice_values_params = values_params diff --git a/tiramisu/storage/sqlalchemy/option.py b/tiramisu/storage/sqlalchemy/option.py index 9d5e137..db2675b 100644 --- a/tiramisu/storage/sqlalchemy/option.py +++ b/tiramisu/storage/sqlalchemy/option.py @@ -129,14 +129,14 @@ class _PropertyOption(SqlAlchemyBase): class _Information(SqlAlchemyBase): __tablename__ = 'information' id = Column(Integer, primary_key=True) - option = Column(String, index=True, nullable=False) + option = Column(String, ForeignKey('baseoption.id'), nullable=False) key = Column(String) value = Column(PickleType) - def __init__(self, option, key, value): - self.option = option - self.key = key - self.value = value +# def __init__(self, option, key, value): +# self.option = option +# self.key = key +# self.value = value #____________________________________________________________ @@ -392,6 +392,7 @@ class _Base(SqlAlchemyBase): # collection_class=attribute_mapped_collection('key'), # cascade="all, delete-orphan") # _informations = association_proxy("_infos", "value") + _informations = relationship("_Information") _default = Column(PickleType) _default_multi = Column(PickleType) _subdyn = Column(Integer) @@ -450,7 +451,8 @@ class _Base(SqlAlchemyBase): if allow_empty_list is not undefined: self._allow_empty_list = allow_empty_list if doc is not undefined: - self._informations = {'doc': doc} + self._informations = [_Information(key='doc', value=doc)] + #self._informations = {'doc': doc} if opt is not undefined: self._opt = opt.id if extra is not undefined: @@ -489,10 +491,14 @@ class _Base(SqlAlchemyBase): return self.id def impl_get_callback(self): + a=self.getsession().query(_Base).filter_by(id=self.id).first() ret = self._callback if ret is None: return (None, {}) - return ret, self._callback_params + params = self._callback_params + if params is None: + params = {} + return ret, params def impl_get_validator(self): ret = self._validator @@ -559,7 +565,13 @@ class _Base(SqlAlchemyBase): def _set_callback(self, callback, callback_params): self._callback = callback if callback_params is not None: - self._callback_params = callback_params + opt._callback_params = callback_params + #session = self.getsession() + #opt = session.query(_Base).filter_by(id=self.id).first() + #opt._callback = callback + #if callback_params is not None: + # opt._callback_params = callback_params + #session.commit() def impl_set_choice_values_params(self, values, values_params, session): self._choice_values = values @@ -632,11 +644,10 @@ class _Base(SqlAlchemyBase): # information def impl_set_information(self, key, value): session = self.getsession() -# self._informations[key] = value val = session.query(_Information).filter_by( option=self.id, key=key).first() if val is None: - session.add(_Information(self.id, key, value)) + session.add(_Information(self, key, value)) else: val.value = value session.commit() diff --git a/tiramisu/value.py b/tiramisu/value.py index 22efbbb..0a25dec 100644 --- a/tiramisu/value.py +++ b/tiramisu/value.py @@ -771,11 +771,13 @@ class Multi(list): raise value return value - def _get_validated_value(self, index): + def _getdefaultvalue(self, index): values = self._getcontext().cfgimpl_get_values() - return values._get_validated_value(self.opt, self.path, - True, False, True, - index=index) + value = values._getdefaultvalue(self.opt, self.path, True, index, + undefined, True) + if self.opt.impl_is_submulti(): + value = SubMulti(value, self.context, self.opt, self.path, index) + return value def append(self, value=undefined, force=False, setitem=True, validate=True, force_permissive=False): @@ -787,7 +789,7 @@ class Multi(list): " which is a slave").format(self.opt.impl_getname())) index = self.__len__() if value is undefined: - value = self._get_validated_value(index) + value = self._getdefaultvalue(index) if validate and value not in [None, undefined]: context = self._getcontext() setting = context.cfgimpl_get_settings() @@ -943,9 +945,7 @@ class SubMulti(Multi): if err: raise err - def _get_validated_value(self, index): + def _getdefaultvalue(self, index): values = self._getcontext().cfgimpl_get_values() - return values._get_validated_value(self.opt, self.path, - True, False, True, - index=index, - submulti_index=self._index) + return values._getdefaultvalue(self.opt, self.path, True, index, + self._index, True)