tiramisu/tiramisu/autolib.py

207 lines
7.2 KiB
Python

# 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
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# 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 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 PropertiesOptionError, ConfigError
from tiramisu.i18n import _
# ____________________________________________________________
def carry_out_calculation(name, config, callback, callback_params,
index=None, max_len=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
:param max_len: max length for a multi
:type max_len: int
* if no callback_params:
=> calculate()
* if callback_params={'': ('yes',)}
=> calculate('yes')
* if callback_params={'value': ('yes',)}
=> calculate(value='yes')
* if callback_params={'': ('yes', 'no')}
=> calculate('yes', 'no')
* if callback_params={'value': ('yes', 'no')}
=> ValueError()
* if callback_params={'': ((opt1, False),)}
- a simple option:
opt1 == 11
=> calculate(11)
- a multi option:
opt1 == [1, 2, 3]
=> calculate(1)
=> calculate(2)
=> calculate(3)
* if callback_params={'value': ((opt1, False),)}
- a simple option:
opt1 == 11
=> calculate(value=11)
- a multi option:
opt1 == [1, 2, 3]
=> calculate(value=1)
=> calculate(value=2)
=> calculate(value=3)
* if callback_params={'': ((opt1, False), (opt2, False))}
- a multi option with a simple option
opt1 == [1, 2, 3]
opt2 == 11
=> calculate(1, 11)
=> calculate(2, 11)
=> calculate(3, 11)
- 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)
- 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()
* if callback_params={'value': ((opt1, False), (opt2, False))}
=> ConfigError()
If index is not None, return a value, otherwise return:
* a list if one parameters have multi option
* a value otherwise
If calculate return list, this list is extend to return value.
"""
tcparams = {}
one_is_multi = False
len_multi = 0
for key, callbacks in callback_params.items():
for callbk in callbacks:
if isinstance(callbk, tuple):
option, force_permissive = callbk
# 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,
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
one_is_multi = True
tcparams.setdefault(key, []).append((value, is_multi))
else:
tcparams.setdefault(key, []).append((callbk, False))
if one_is_multi:
ret = []
if index:
if index < len_multi:
range_ = [index]
else:
range_ = []
ret = None
else:
if max_len and max_len < len_multi:
range_ = range(max_len)
else:
range_ = range(len_multi)
for incr in range_:
tcp = {}
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:
tcp[key] = value[incr]
else:
params.append(value)
calc = calculate(name, callback, params, tcp)
if index:
ret = calc
else:
if isinstance(calc, list):
ret.extend(calc)
else:
ret.append(calc)
return ret
else:
tcp = {}
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):
"""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)