254 lines
10 KiB
Python
254 lines
10 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 Lesser General Public License as published by the
|
|
# Free Software Foundation, either version 3 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 Lesser General Public License for more
|
|
# details.
|
|
#
|
|
# You should have received a copy of the GNU Lesser General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
#
|
|
# 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 .error import PropertiesOptionError, ConfigError, SlaveError
|
|
from .i18n import _
|
|
from .setting import undefined
|
|
# ____________________________________________________________
|
|
|
|
|
|
def carry_out_calculation(option, context, callback, callback_params,
|
|
index=undefined):
|
|
"""a function that carries out a calculation for an option's value
|
|
|
|
:param option: the option
|
|
:param context: 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
|
|
|
|
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(<function func at 0x2092320>, [], {})
|
|
|
|
* if callback_params={'': ('yes',)}
|
|
=> calculate(<function func at 0x2092320>, ['yes'], {})
|
|
|
|
* if callback_params={'value': ('yes',)}
|
|
=> calculate(<function func at 0x165b320>, [], {'value': 'yes'})
|
|
|
|
* if callback_params={'': ('yes', 'no')}
|
|
=> calculate('yes', 'no')
|
|
|
|
* if callback_params={'value': ('yes', 'no')}
|
|
=> ValueError()
|
|
|
|
* if callback_params={'': (['yes', 'no'],)}
|
|
=> calculate(<function func at 0x176b320>, ['yes', 'no'], {})
|
|
|
|
* if callback_params={'value': ('yes', 'no')}
|
|
=> raises ValueError()
|
|
|
|
* if callback_params={'': ((opt1, False),)}
|
|
|
|
- a simple option:
|
|
opt1 == 11
|
|
=> calculate(<function func at 0x1cea320>, [11], {})
|
|
|
|
- a multi option and not master/slave:
|
|
opt1 == [1, 2, 3]
|
|
=> calculate(<function func at 0x223c320>, [[1, 2, 3]], {})
|
|
|
|
- option is master or slave of opt1:
|
|
opt1 == [1, 2, 3]
|
|
=> calculate(<function func at 0x223c320>, [1], {})
|
|
=> calculate(<function func at 0x223c320>, [2], {})
|
|
=> calculate(<function func at 0x223c320>, [3], {})
|
|
|
|
- opt is a master or slave but not related to option:
|
|
opt1 == [1, 2, 3]
|
|
=> calculate(<function func at 0x11b0320>, [[1, 2, 3]], {})
|
|
|
|
* if callback_params={'value': ((opt1, False),)}
|
|
|
|
- a simple option:
|
|
opt1 == 11
|
|
=> calculate(<function func at 0x17ff320>, [], {'value': 11})
|
|
|
|
- a multi option:
|
|
opt1 == [1, 2, 3]
|
|
=> calculate(<function func at 0x1262320>, [], {'value': [1, 2, 3]})
|
|
|
|
* if callback_params={'': ((opt1, False), (opt2, False))}
|
|
|
|
- two single options
|
|
opt1 = 11
|
|
opt2 = 12
|
|
=> calculate(<function func at 0x217a320>, [11, 12], {})
|
|
|
|
- a multi option with a simple option
|
|
opt1 == [1, 2, 3]
|
|
opt2 == 12
|
|
=> calculate(<function func at 0x2153320>, [[1, 2, 3], 12], {})
|
|
|
|
- a multi option with an other multi option but with same length
|
|
opt1 == [1, 2, 3]
|
|
opt2 == [11, 12, 13]
|
|
=> calculate(<function func at 0x1981320>, [[1, 2, 3], [11, 12, 13]], {})
|
|
|
|
- a multi option with an other multi option but with different length
|
|
opt1 == [1, 2, 3]
|
|
opt2 == [11, 12]
|
|
=> calculate(<function func at 0x2384320>, [[1, 2, 3], [11, 12]], {})
|
|
|
|
- a multi option without value with a simple option
|
|
opt1 == []
|
|
opt2 == 11
|
|
=> calculate(<function func at 0xb65320>, [[], 12], {})
|
|
|
|
* if callback_params={'value': ((opt1, False), (opt2, False))}
|
|
=> raises ValueError()
|
|
|
|
If index is not undefined, 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 = {}
|
|
# if callback_params has a callback, launch several time calculate()
|
|
master_slave = False
|
|
has_option = False
|
|
# multi's option should have same value for all option
|
|
if option._is_subdyn():
|
|
tcparams['suffix'] = [(option.impl_getsuffix(), False)]
|
|
for key, callbacks in callback_params.items():
|
|
for callbk in callbacks:
|
|
if isinstance(callbk, tuple):
|
|
if context is undefined:
|
|
return undefined
|
|
if callbk[0] is None: # pragma: optional cover
|
|
#Not an option, set full context
|
|
tcparams.setdefault(key, []).append((context.duplicate(), False))
|
|
elif callbk[0] == 'index':
|
|
tcparams.setdefault(key, []).append((index, False))
|
|
else:
|
|
# callbk is something link (opt, True|False)
|
|
opt, force_permissive = callbk
|
|
if opt._is_subdyn():
|
|
root = '.'.join(option.impl_getpath(context).split('.')[:-1])
|
|
name = opt.impl_getname() + option.impl_getsuffix()
|
|
path = root + '.' + name
|
|
opt = opt._impl_to_dyn(name, path)
|
|
else:
|
|
path = context.cfgimpl_get_description(
|
|
).impl_get_path_by_opt(opt)
|
|
# get value
|
|
value = context.getattr(path, force_permissive=True,
|
|
validate=False, returns_raise=True)
|
|
if isinstance(value, Exception):
|
|
if isinstance(value, PropertiesOptionError):
|
|
if force_permissive:
|
|
continue
|
|
err = ConfigError(_('unable to carry out a calculation'
|
|
', option {0} has properties: {1} '
|
|
'for: {2}').format(opt.impl_getname(),
|
|
value.proptype,
|
|
option.impl_getname()))
|
|
return err
|
|
else:
|
|
raise value
|
|
# convert to list, not modifie this multi
|
|
if value.__class__.__name__ == 'Multi':
|
|
has_option = True
|
|
value = list(value)
|
|
|
|
if opt != option and opt.impl_is_master_slaves() and \
|
|
opt.impl_get_master_slaves().in_same_group(option):
|
|
master_slave = True
|
|
is_multi = True
|
|
else:
|
|
is_multi = False
|
|
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 master_slave:
|
|
ret = []
|
|
args = []
|
|
kwargs = {}
|
|
for key, couples in tcparams.items():
|
|
for couple in couples:
|
|
value, ismulti = couple
|
|
if ismulti:
|
|
val = value[index]
|
|
else:
|
|
val = value
|
|
if key == '':
|
|
args.append(val)
|
|
else:
|
|
kwargs[key] = val
|
|
return calculate(callback, args, kwargs)
|
|
else:
|
|
# 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 == '':
|
|
args.append(couple[0])
|
|
else:
|
|
kwargs[key] = couple[0]
|
|
ret = calculate(callback, args, kwargs)
|
|
if not option.impl_is_optiondescription() and callback_params != {} and isinstance(ret, list) and \
|
|
option.impl_is_master_slaves('slave'):
|
|
if not has_option and index not in [None, undefined]:
|
|
if index < len(ret):
|
|
ret = ret[index]
|
|
else:
|
|
#FIXME really?
|
|
ret = None
|
|
else:
|
|
raise SlaveError(_("callback cannot return a list for a "
|
|
"slave option ({0})").format(option.impl_getname()))
|
|
return ret
|
|
|
|
|
|
def calculate(callback, args, kwargs):
|
|
"""wrapper that launches the 'callback'
|
|
|
|
:param callback: callback function
|
|
:param args: in the callback's arity, the unnamed parameters
|
|
:param kwargs: in the callback's arity, the named parameters
|
|
|
|
"""
|
|
try:
|
|
return callback(*args, **kwargs)
|
|
except ValueError as err:
|
|
return err
|