some improvements
authorEmmanuel Garette <egarette@cadoles.com>
Mon, 10 Oct 2016 19:41:22 +0000 (21:41 +0200)
committerEmmanuel Garette <egarette@cadoles.com>
Mon, 10 Oct 2016 19:41:22 +0000 (21:41 +0200)
ChangeLog
test/test_option_consistency.py
test/test_option_validator.py
tiramisu/option/baseoption.py
tiramisu/option/option.py
tiramisu/storage/dictionary/option.py
tiramisu/storage/sqlalchemy/option.py
tiramisu/value.py

index 4f15433..53ab5f1 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+Mon Oct 10 21:39:04 2016 +0200 Emmanuel Garette <egarette@cadoles.com>
+       * 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 <egarette@cadoles.com>
        * force_store_value is rebuild if needed
 
index 0c19fa7..a5fedc4 100644 (file)
@@ -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',))
index 54a44f4..eedffb6 100644 (file)
@@ -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')
index 55aaf71..de2e35f 100644 (file)
@@ -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):
index e90fb77..1ec35e4 100644 (file)
@@ -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):
index e9b49a8..aa9ae13 100644 (file)
@@ -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
index 9d5e137..db2675b 100644 (file)
@@ -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()
index 22efbbb..0a25dec 100644 (file)
@@ -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)