impl_get_information and impl_set_information are, now, persistent in storage
[tiramisu.git] / tiramisu / autolib.py
index febc172..2cf41ca 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (C) 2012 Team tiramisu (see README for all contributors)
+# Copyright (C) 2012-2013 Team tiramisu (see AUTHORS for all contributors)
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 #
-# The original `Config` design model is unproudly borrowed from 
+# The original `Config` design model is unproudly borrowed from
 # the rough gus of pypy: pypy: http://codespeak.net/svn/pypy/dist/pypy/config/
 # the whole pypy projet is under MIT licence
 # ____________________________________________________________
 "enables us to carry out a calculation and return an option's value"
-from tiramisu.error import DisabledOptionError, SpecialOwnersError
+from tiramisu.error import PropertiesOptionError, ConfigError
+from tiramisu.i18n import _
 # ____________________________________________________________
-# automatic Option object
-special_owners = ['auto', 'fill']
-                  
-def special_owner_factory(name, owner, value, 
-                          callback, callback_params=None, config=None):
-    # in case of an 'auto' and a 'fill' without a value, 
-    # we have to carry out a calculation
-    return calc_factory(name, callback, callback_params, config)
 
-def calc_factory(name, callback, callback_params, config):
-    # FIXME we have to know the exact status of the config 
-    # not to disrupt it
-    # config.freeze()
-    if callback_params is None:
-        callback_params = {}
+def carry_out_calculation(name,
+                          config,
+                          callback,
+                          callback_params,
+                          index=None):
+    """a function that carries out a calculation for an option's value
+
+    :param name: the option name (`opt._name`)
+    :param config: the context config in order to have
+                   the whole options available
+    :param callback: the name of the callback function
+    :type callback: str
+    :param callback_params: the callback's parameters
+                            (only keyword parameters are allowed)
+    :type callback_params: dict
+    :param index: if an option is multi, only calculates the nth value
+    :type index: int
+    """
+    #callback, callback_params = option.getcallback()
+    #if callback_params is None:
+    #    callback_params = {}
     tcparams = {}
     one_is_multi = False
     len_multi = 0
-    for key, value in callback_params.items():
-        if type(value) == tuple:
-            path, check_disabled = value
-            try:
-                opt_value = getattr(config, path)
-                opt = config.unwrap_from_path(path)
-            except DisabledOptionError, e:
-                if chek_disabled:
-                    continue
-                raise DisabledOptionError(e)
-            is_multi = opt.is_multi()
-            if is_multi:
-                if opt_value != None:
-                    len_value = len(opt_value)
-                    if len_multi != 0 and len_multi != len_value:
-                        raise SpecialOwnersError('unable to carry out a calculation, '
-                        'option values with multi types must have same length for: '
-                         + name)
-                    len_multi = len_value
-                one_is_multi = True
-            tcparams[key] = (opt_value, is_multi)
-        else:
-            tcparams[key] = (value, False)
+
+    for key, values in callback_params.items():
+        for value in values:
+            if type(value) == tuple:
+                path, check_disabled = value
+                if config is None:
+                    if check_disabled:
+                        continue
+                    raise ConfigError(_('no config specified but needed'))
+                try:
+                    opt_value = config._getattr(path, force_permissive=True)
+                    opt = config.unwrap_from_path(path, force_permissive=True)
+                except PropertiesOptionError as err:
+                    if check_disabled:
+                        continue
+                    raise ConfigError(_('unable to carry out a calculation, '
+                                        'option {0} has properties: {1} for: '
+                                        '{2}').format(path, err.proptype,
+                                                      name))
+                is_multi = opt.impl_is_multi()
+                if is_multi:
+                    if opt_value is not None:
+                        len_value = len(opt_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
+                    one_is_multi = True
+                tcparams.setdefault(key, []).append((opt_value, is_multi))
+            else:
+                tcparams.setdefault(key, []).append((value, False))
 
     if one_is_multi:
         ret = []
-        for incr in range(len_multi):
+        if index:
+            range_ = [index]
+        else:
+            range_ = range(len_multi)
+        for incr in range_:
             tcp = {}
-            for key, couple in tcparams.items():
-                value, ismulti = couple
-                if ismulti and value != None:
-                    tcp[key] = value[incr]
+            params = []
+            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:
+                            if len(value) > incr:
+                                tcp[key] = value[incr]
+                            else:
+                                tcp[key] = ''
+                    else:
+                        if key == '':
+                            params.append(value)
+                        else:
+                            tcp[key] = value
+            calc = calculate(name, callback, params, tcp)
+            if index:
+                ret = calc
+            else:
+                if isinstance(calc, list):
+                    ret.extend(calc)
                 else:
-                    tcp[key] = value
-            ret.append(calculate(name, callback, tcp))
+                    ret.append(calc)
+
         return ret
     else:
         tcp = {}
-        for key, couple in tcparams.items():
-            tcp[key] = couple[0]
-        return calculate(name, callback, tcp)
-    
-def calculate(name, callback, tcparams):
-    try:
-        # XXX not only creole...
-        from creole import eosfunc
-        return getattr(eosfunc, callback)(**tcparams) 
-    except AttributeError, err:
-        import traceback
-        traceback.print_exc()
-        raise SpecialOwnersError("callback: {0} return error {1} for "
-                       "option: {2}".format(callback, str(err), name))
+        params = []
+        for key, couples in tcparams.items():
+            for couple in couples:
+                if key == '':
+                    value = couple[0]
+                    params.append(value)
+                else:
+                    tcp[key] = couple[0]
+        return calculate(name, callback, params, tcp)
+
+
+def calculate(name, callback, params, tcparams):
+    # FIXME we don't need the option's name down there.
+    """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
 
+    """
+    return callback(*params, **tcparams)