Better support for slave with callback:
authorEmmanuel Garette <egarette@cadoles.com>
Tue, 11 Jun 2013 13:10:38 +0000 (15:10 +0200)
committerEmmanuel Garette <egarette@cadoles.com>
Tue, 11 Jun 2013 13:12:31 +0000 (15:12 +0200)
- callback must return single value, not a list
- if default value, append slave values with master len
- if not default and append, set default value

test/test_option_calculation.py
tiramisu/value.py

index 0f76c2f..d5dc0cc 100644 (file)
@@ -1,12 +1,17 @@
 import autopath
 from py.test import raises
 
+from tiramisu.setting import groups
 from tiramisu.config import Config
 from tiramisu.option import ChoiceOption, BoolOption, IntOption, FloatOption, \
-    StrOption, IPOption, OptionDescription
+    StrOption, OptionDescription
 from tiramisu.error import PropertiesOptionError, ConflictError
 
 
+def return_value():
+    return 'val'
+
+
 def make_description():
     gcoption = ChoiceOption('name', 'GC name', ('ref', 'framework'), 'ref')
     gcdummy = BoolOption('dummy', 'dummy', default=False)
@@ -269,3 +274,37 @@ def test_freeze_and_has_callback():
     dummy = config.unwrap_from_path('gc.dummy')
     setting[dummy].append('frozen')
     raises(PropertiesOptionError, "config.gc.dummy = True")
+
+
+def test_callback_master_and_slaves():
+    val1 = StrOption('val1', "", multi=True)
+    val2 = StrOption('val2', "", multi=True, callback=return_value)
+    interface1 = OptionDescription('val1', '', [val1, val2])
+    interface1.impl_set_group_type(groups.master)
+    maconfig = OptionDescription('rootconfig', '', [interface1])
+    cfg = Config(maconfig)
+    cfg.read_write()
+    assert cfg.val1.val1 == []
+    assert cfg.val1.val2 == []
+    #
+    cfg.val1.val1 = ['val1']
+    assert cfg.val1.val1 == ['val1']
+    assert cfg.val1.val2 == ['val']
+    #
+    cfg.val1.val1.append('val2')
+    assert cfg.val1.val1 == ['val1', 'val2']
+    assert cfg.val1.val2 == ['val', 'val']
+    #
+    cfg.val1.val1 = ['val1', 'val2', 'val3']
+    assert cfg.val1.val1 == ['val1', 'val2', 'val3']
+    assert cfg.val1.val2 == ['val', 'val', 'val']
+    #
+    cfg.val1.val1.pop(2)
+    assert cfg.val1.val1 == ['val1', 'val2']
+    assert cfg.val1.val2 == ['val', 'val']
+    #
+    cfg.val1.val2 = ['val2', 'val2']
+    assert cfg.val1.val2 == ['val2', 'val2']
+    #
+    cfg.val1.val1.append('val3')
+    assert cfg.val1.val2 == ['val2', 'val2', 'val']
index 0f21d8c..9e65db2 100644 (file)
@@ -115,27 +115,41 @@ class Values(object):
                  validate_properties):
         # options with callbacks
         setting = self.context.cfgimpl_get_settings()
-        value = self._get_value(opt, validate)
         is_frozen = 'frozen' in setting[opt]
-        if opt.impl_has_callback():
-            #if value is set and :
-            # - not frozen
-            # - frozen and not force_default_on_freeze
-            if not self.is_default_owner(opt) and (
-                    not is_frozen or (is_frozen and
-                                      not 'force_default_on_freeze' in setting[opt])):
-                pass
-            else:
+        #if value is callback and is not set or frozen with force_default_on_freeze
+        if opt.impl_has_callback() and (self.is_default_owner(opt) or
+                                        (is_frozen and
+                                         'force_default_on_freeze' in setting[opt])):
+            no_value_slave = False
+            if opt.impl_get_multitype() == multitypes.slave:
+                masterp = self.context.cfgimpl_get_description().impl_get_path_by_opt(
+                    opt.impl_get_master_slaves())
+                mastervalue = getattr(self.context, masterp)
+                lenmaster = len(mastervalue)
+                if lenmaster == 0:
+                    value = []
+                    no_value_slave = True
+
+            if not no_value_slave:
                 value = self._getcallback_value(opt)
                 if opt.impl_is_multi():
-                    value = Multi(value, self.context, opt, validate)
-                #suppress value if already set
-                self._reset(opt)
+                    if opt.impl_get_multitype() == multitypes.slave:
+                        if isinstance(value, list):
+                            raise ValueError('callback must not return list '
+                                            'in slave {0}: {1}'.format(opt._name,
+                                                                        value))
+                        value = [value for i in range(lenmaster)]
+            if opt.impl_is_multi():
+                value = Multi(value, self.context, opt, validate)
+            #suppress value if already set
+            self._reset(opt)
         # frozen and force default
         elif is_frozen and 'force_default_on_freeze' in setting[opt]:
             value = self._get_default(opt)
             if opt.impl_is_multi():
                 value = Multi(value, self.context, opt, validate)
+        else:
+            value = self._get_value(opt, validate)
         if validate:
             opt.impl_validate(value, self.context, 'validator' in setting)
         if self.is_default_owner(opt) and \
@@ -287,10 +301,13 @@ class Multi(list):
                 for slave in self.opt.impl_get_master_slaves():
                     values = self.context.cfgimpl_get_values()
                     if not values.is_default_owner(slave):
+                        if slave.impl_has_callback():
+                            dvalue = values._getcallback_value(slave)
+                        else:
+                            dvalue = slave.impl_getdefault_multi()
                         #get multi without valid properties
                         values.getitem(slave, validate_properties=False).append(
-                            slave.impl_getdefault_multi(),
-                            force=True)
+                            dvalue, force=True)
         self._validate(value)
         #set value without valid properties
         self.context.cfgimpl_get_values()._setvalue(self.opt, self, validate_properties=not force)