comment tiramisu/autolib.py + some modification
authorEmmanuel Garette <egarette@cadoles.com>
Mon, 23 Sep 2013 20:40:10 +0000 (22:40 +0200)
committerEmmanuel Garette <egarette@cadoles.com>
Mon, 23 Sep 2013 20:40:10 +0000 (22:40 +0200)
test/test_option_calculation.py
tiramisu/autolib.py

index 8ca8687..117de9d 100644 (file)
@@ -28,6 +28,12 @@ def return_value(value=None):
     return value
 
 
+def return_value2(*args, **kwargs):
+    value = list(args)
+    value.extend(kwargs.values())
+    return value
+
+
 def make_description():
     gcoption = ChoiceOption('name', 'GC name', ('ref', 'framework'), 'ref')
     gcdummy = BoolOption('dummy', 'dummy', default=False)
@@ -675,3 +681,13 @@ def test_callback_multi_multi():
     raises(ConfigError, "cfg.val4")
     assert cfg.val5 == ['val1', 'val4', 'val2', 'val4', 'val3', 'val4']
     assert cfg.val7 == ['val1', 'val21', 'val2', 'val22', 'val3', 'val23']
+
+
+def test_multi_with_no_value():
+    #First option return [] (so without value)
+    val1 = StrOption('val1', "", ['val'], multi=True)
+    val2 = StrOption('val2', "", multi=True)
+    val3 = StrOption('val3', '', multi=True, callback=return_value, callback_params={'': ((val2, False),), 'value': ((val1, False),)})
+    od = OptionDescription('od', '', [val1, val2, val3])
+    c = Config(od)
+    raises(ConfigError, "c.val3")
index de8a8c5..efb7c0e 100644 (file)
@@ -41,6 +41,13 @@ def carry_out_calculation(name, config, callback, callback_params,
     :param max_len: max length for a multi
     :type max_len: int
 
+    The callback_params is a dict. Key is used to build args (if key is '')
+    and kwargs (otherwise). Values are tuple of:
+    - values
+    - tuple with option and boolean's force_permissive (True when don't raise
+    if PropertiesOptionError)
+    Values could have multiple values only when key is ''.
+
     * if no callback_params:
       => calculate()
 
@@ -92,7 +99,6 @@ def carry_out_calculation(name, config, callback, callback_params,
       - a multi option with an other multi option but with same length
           opt1 == [1, 2, 3]
           opt2 == [11, 12, 13]
-          callback_params={'': ((opt1, False), (opt2, False))}
           => calculate(1, 11)
           => calculate(2, 12)
           => calculate(3, 13)
@@ -100,9 +106,13 @@ def carry_out_calculation(name, config, callback, callback_params,
       - a multi option with an other multi option but with different length
           opt1 == [1, 2, 3]
           opt2 == [11, 12]
-          callback_params={'': ((opt1, False), (opt2, False))}
           => ConfigError()
 
+      - a multi option without value with a simple option
+          opt1 == []
+          opt2 == 11
+          => []
+
     * if callback_params={'value': ((opt1, False), (opt2, False))}
       => ConfigError()
 
@@ -114,39 +124,47 @@ def carry_out_calculation(name, config, callback, callback_params,
     If calculate return list, this list is extend to return value.
     """
     tcparams = {}
+    # if callback_params has a callback, launch several time calculate()
     one_is_multi = False
-    len_multi = 0
+    # multi's option should have same value for all option
+    len_multi = None
 
     for key, callbacks in callback_params.items():
         for callbk in callbacks:
             if isinstance(callbk, tuple):
+                # callbk is something link (opt, True|False)
                 option, force_permissive = callbk
+                path = config.cfgimpl_get_description().impl_get_path_by_opt(
+                    option)
                 # get value
                 try:
-                    path = config.cfgimpl_get_description().impl_get_path_by_opt(option)
                     value = config._getattr(path, force_permissive=True)
                 except PropertiesOptionError as err:
                     if force_permissive:
                         continue
                     raise ConfigError(_('unable to carry out a calculation, '
                                         'option {0} has properties: {1} for: '
-                                        '{2}').format(option._name, err.proptype,
+                                        '{2}').format(option._name,
+                                                      err.proptype,
                                                       name))
                 is_multi = option.impl_is_multi()
                 if is_multi:
-                    if value is not None:
-                        len_value = len(value)
-                        if len_multi != 0 and len_multi != len_value:
-                            raise ConfigError(_('unable to carry out a '
-                                              'calculation, option value with'
-                                              ' multi types must have same '
-                                              'length for: {0}').format(name))
-                        len_multi = len_value
+                    len_value = len(value)
+                    if len_multi is not None and len_multi != len_value:
+                        raise ConfigError(_('unable to carry out a '
+                                            'calculation, option value with'
+                                            ' multi types must have same '
+                                            'length for: {0}').format(name))
+                    len_multi = len_value
                     one_is_multi = True
                 tcparams.setdefault(key, []).append((value, is_multi))
             else:
+                # callbk is a value and not a multi
                 tcparams.setdefault(key, []).append((callbk, False))
 
+    # if one value is a multi, launch several time calculate
+    # if index is set, return a value
+    # if no index, return a list
     if one_is_multi:
         ret = []
         if index:
@@ -161,19 +179,20 @@ def carry_out_calculation(name, config, callback, callback_params,
             else:
                 range_ = range(len_multi)
         for incr in range_:
-            tcp = {}
-            params = []
+            args = []
+            kwargs = {}
             for key, couples in tcparams.items():
                 for couple in couples:
                     value, ismulti = couple
-                    if ismulti and value is not None:
-                        if key == '':
-                            params.append(value[incr])
-                        else:
-                            tcp[key] = value[incr]
+                    if ismulti:
+                        val = value[incr]
+                    else:
+                        val = value
+                    if key == '':
+                        args.append(val)
                     else:
-                        params.append(value)
-            calc = calculate(name, callback, params, tcp)
+                        kwargs[key] = val
+            calc = calculate(callback, args, kwargs)
             if index:
                 ret = calc
             else:
@@ -183,24 +202,26 @@ def carry_out_calculation(name, config, callback, callback_params,
                     ret.append(calc)
         return ret
     else:
-        tcp = {}
-        params = []
+        # no value is multi
+        # return a single value
+        args = []
+        kwargs = {}
         for key, couples in tcparams.items():
             for couple in couples:
+                # couple[1] (ismulti) is always False
                 if key == '':
-                    value = couple[0]
-                    params.append(value)
+                    args.append(couple[0])
                 else:
-                    tcp[key] = couple[0]
-        return calculate(name, callback, params, tcp)
+                    kwargs[key] = couple[0]
+        return calculate(callback, args, kwargs)
 
 
-def calculate(name, callback, params, tcparams):
+def calculate(callback, args, kwargs):
     """wrapper that launches the 'callback'
 
-    :param callback: callback name
-    :param params: in the callback's arity, the unnamed parameters
-    :param tcparams: in the callback's arity, the named parameters
+    :param callback: callback function
+    :param args: in the callback's arity, the unnamed parameters
+    :param kwargs: in the callback's arity, the named parameters
 
     """
-    return callback(*params, **tcparams)
+    return callback(*args, **kwargs)