1 # Copyright (C) 2012-2013 Team tiramisu (see AUTHORS for all contributors)
3 # This program is free software; you can redistribute it and/or modify
4 # it under the terms of the GNU General Public License as published by
5 # the Free Software Foundation; either version 2 of the License, or
6 # (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software
15 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 # The original `Config` design model is unproudly borrowed from
18 # the rough gus of pypy: pypy: http://codespeak.net/svn/pypy/dist/pypy/config/
19 # the whole pypy projet is under MIT licence
20 # ____________________________________________________________
21 "enables us to carry out a calculation and return an option's value"
22 from tiramisu.error import PropertiesOptionError, ConfigError
23 from tiramisu.i18n import _
24 # ____________________________________________________________
27 def carry_out_calculation(name, config, callback, callback_params,
28 index=None, max_len=None):
29 """a function that carries out a calculation for an option's value
31 :param name: the option name (`opt.impl_getname()`)
32 :param config: the context config in order to have
33 the whole options available
34 :param callback: the name of the callback function
36 :param callback_params: the callback's parameters
37 (only keyword parameters are allowed)
38 :type callback_params: dict
39 :param index: if an option is multi, only calculates the nth value
41 :param max_len: max length for a multi
44 The callback_params is a dict. Key is used to build args (if key is '')
45 and kwargs (otherwise). Values are tuple of:
47 - tuple with option and boolean's force_permissive (True when don't raise
48 if PropertiesOptionError)
49 Values could have multiple values only when key is ''.
51 * if no callback_params:
54 * if callback_params={'': ('yes',)}
57 * if callback_params={'value': ('yes',)}
58 => calculate(value='yes')
60 * if callback_params={'': ('yes', 'no')}
61 => calculate('yes', 'no')
63 * if callback_params={'value': ('yes', 'no')}
66 * if callback_params={'': ((opt1, False),)}
78 * if callback_params={'value': ((opt1, False),)}
82 => calculate(value=11)
90 * if callback_params={'': ((opt1, False), (opt2, False))}
92 - a multi option with a simple option
99 - a multi option with an other multi option but with same length
106 - a multi option with an other multi option but with different length
111 - a multi option without value with a simple option
116 * if callback_params={'value': ((opt1, False), (opt2, False))}
119 If index is not None, return a value, otherwise return:
121 * a list if one parameters have multi option
124 If calculate return list, this list is extend to return value.
127 # if callback_params has a callback, launch several time calculate()
129 # multi's option should have same value for all option
132 if callback_params != []:
133 for callbacks in callback_params:
135 for callbk in callbacks.params:
136 if callbk.option is not None:
137 # callbk is something link (opt, True|False)
138 option = callbk.get_option(config)
139 force_permissive = callbk.force_permissive
140 path = config.cfgimpl_get_description().impl_get_path_by_opt(
144 value = config._getattr(path, force_permissive=True)
145 except PropertiesOptionError as err:
148 raise ConfigError(_('unable to carry out a calculation, '
149 'option {0} has properties: {1} for: '
150 '{2}').format(option.impl_getname(),
153 is_multi = option.impl_is_multi()
155 len_value = len(value)
156 if len_multi is not None and len_multi != len_value:
157 raise ConfigError(_('unable to carry out a '
158 'calculation, option value with'
159 ' multi types must have same '
160 'length for: {0}').format(name))
161 len_multi = len_value
163 tcparams.setdefault(key, []).append((value, is_multi))
165 # callbk is a value and not a multi
166 tcparams.setdefault(key, []).append((callbk.value, False))
168 # if one value is a multi, launch several time calculate
169 # if index is set, return a value
170 # if no index, return a list
174 if index < len_multi:
180 if max_len and max_len < len_multi:
181 range_ = range(max_len)
183 range_ = range(len_multi)
187 for key, couples in tcparams.items():
188 for couple in couples:
189 value, ismulti = couple
198 calc = calculate(callback, args, kwargs)
202 if isinstance(calc, list):
209 # return a single value
212 for key, couples in tcparams.items():
213 for couple in couples:
214 # couple[1] (ismulti) is always False
216 args.append(couple[0])
218 kwargs[key] = couple[0]
219 return calculate(callback, args, kwargs)
222 def calculate(callback, args, kwargs):
223 """wrapper that launches the 'callback'
225 :param callback: callback function
226 :param args: in the callback's arity, the unnamed parameters
227 :param kwargs: in the callback's arity, the named parameters
230 return callback(*args, **kwargs)