Merge branch 'master' into orm
Conflicts: test/test_config.py tiramisu/autolib.py tiramisu/option.py tiramisu/value.py
This commit is contained in:
@ -20,15 +20,17 @@
|
||||
# ____________________________________________________________
|
||||
"enables us to carry out a calculation and return an option's value"
|
||||
from tiramisu.error import PropertiesOptionError, ConfigError
|
||||
from tiramisu.setting import multitypes
|
||||
from tiramisu.i18n import _
|
||||
# ____________________________________________________________
|
||||
|
||||
|
||||
def carry_out_calculation(name, config, callback, callback_params,
|
||||
def carry_out_calculation(option, 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.impl_getname()`)
|
||||
:param name: the option
|
||||
:param config: the context config in order to have
|
||||
the whole options available
|
||||
:param callback: the name of the callback function
|
||||
@ -49,13 +51,13 @@ def carry_out_calculation(name, config, callback, callback_params,
|
||||
Values could have multiple values only when key is ''.
|
||||
|
||||
* if no callback_params:
|
||||
=> calculate()
|
||||
=> calculate(<function func at 0x2092320>, [], {})
|
||||
|
||||
* if callback_params={'': ('yes',)}
|
||||
=> calculate('yes')
|
||||
=> calculate(<function func at 0x2092320>, ['yes'], {})
|
||||
|
||||
* if callback_params={'value': ('yes',)}
|
||||
=> calculate(value='yes')
|
||||
=> calculate(<function func at 0x165b320>, [], {'value': 'yes'})
|
||||
|
||||
* if callback_params={'': ('yes', 'no')}
|
||||
=> calculate('yes', 'no')
|
||||
@ -63,58 +65,71 @@ def carry_out_calculation(name, config, callback, callback_params,
|
||||
* 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(11)
|
||||
=> calculate(<function func at 0x1cea320>, [11], {})
|
||||
|
||||
- a multi option:
|
||||
- a multi option and not master/slave:
|
||||
opt1 == [1, 2, 3]
|
||||
=> calculate(1)
|
||||
=> calculate(2)
|
||||
=> calculate(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(value=11)
|
||||
=> calculate(<function func at 0x17ff320>, [], {'value': 11})
|
||||
|
||||
- a multi option:
|
||||
opt1 == [1, 2, 3]
|
||||
=> calculate(value=1)
|
||||
=> calculate(value=2)
|
||||
=> calculate(value=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 == 11
|
||||
=> calculate(1, 11)
|
||||
=> calculate(2, 11)
|
||||
=> calculate(3, 11)
|
||||
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(1, 11)
|
||||
=> calculate(2, 12)
|
||||
=> calculate(3, 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]
|
||||
=> ConfigError()
|
||||
=> 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))}
|
||||
=> ConfigError()
|
||||
=> raises ValueError()
|
||||
|
||||
If index is not None, return a value, otherwise return:
|
||||
|
||||
@ -129,41 +144,42 @@ def carry_out_calculation(name, config, callback, callback_params,
|
||||
# multi's option should have same value for all option
|
||||
len_multi = None
|
||||
|
||||
if callback_params != []:
|
||||
for callbacks in callback_params:
|
||||
key = callbacks.name
|
||||
for callbk in callbacks.params:
|
||||
if callbk.option is not None:
|
||||
# callbk is something link (opt, True|False)
|
||||
option = callbk.get_option(config)
|
||||
force_permissive = callbk.force_permissive
|
||||
path = config.cfgimpl_get_description().impl_get_path_by_opt(
|
||||
option)
|
||||
# get value
|
||||
try:
|
||||
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.impl_getname(),
|
||||
err.proptype,
|
||||
name))
|
||||
is_multi = option.impl_is_multi()
|
||||
if is_multi:
|
||||
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.value, False))
|
||||
for key, callbacks in callback_params.items():
|
||||
for callbk in callbacks:
|
||||
if isinstance(callbk, tuple):
|
||||
# callbk is something link (opt, True|False)
|
||||
opt, force_permissive = callbk
|
||||
path = config.cfgimpl_get_description().impl_get_path_by_opt(
|
||||
opt)
|
||||
# get value
|
||||
try:
|
||||
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(opt._name,
|
||||
err.proptype,
|
||||
option._name))
|
||||
|
||||
is_multi = False
|
||||
if opt.impl_is_multi():
|
||||
#opt is master, search if option is a slave
|
||||
if opt.impl_get_multitype() == multitypes.master:
|
||||
if option in opt.impl_get_master_slaves():
|
||||
is_multi = True
|
||||
#opt is slave, search if option is an other slaves
|
||||
elif opt.impl_get_multitype() == multitypes.slave:
|
||||
if option in opt.impl_get_master_slaves().impl_get_master_slaves():
|
||||
is_multi = True
|
||||
if is_multi:
|
||||
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
|
||||
@ -171,16 +187,9 @@ def carry_out_calculation(name, config, callback, callback_params,
|
||||
if one_is_multi:
|
||||
ret = []
|
||||
if index:
|
||||
if index < len_multi:
|
||||
range_ = [index]
|
||||
else:
|
||||
range_ = []
|
||||
ret = None
|
||||
range_ = [index]
|
||||
else:
|
||||
if max_len and max_len < len_multi:
|
||||
range_ = range(max_len)
|
||||
else:
|
||||
range_ = range(len_multi)
|
||||
range_ = range(len_multi)
|
||||
for incr in range_:
|
||||
args = []
|
||||
kwargs = {}
|
||||
@ -199,10 +208,7 @@ def carry_out_calculation(name, config, callback, callback_params,
|
||||
if index:
|
||||
ret = calc
|
||||
else:
|
||||
if isinstance(calc, list):
|
||||
ret.extend(calc)
|
||||
else:
|
||||
ret.append(calc)
|
||||
ret.append(calc)
|
||||
return ret
|
||||
else:
|
||||
# no value is multi
|
||||
@ -216,7 +222,18 @@ def carry_out_calculation(name, config, callback, callback_params,
|
||||
args.append(couple[0])
|
||||
else:
|
||||
kwargs[key] = couple[0]
|
||||
return calculate(callback, args, kwargs)
|
||||
ret = calculate(callback, args, kwargs)
|
||||
if callback_params != {}:
|
||||
if isinstance(ret, list) and max_len:
|
||||
ret = ret[:max_len]
|
||||
if len(ret) < max_len:
|
||||
ret = ret + [None] * (max_len - len(ret))
|
||||
if isinstance(ret, list) and index:
|
||||
if len(ret) < index + 1:
|
||||
ret = None
|
||||
else:
|
||||
ret = ret[index]
|
||||
return ret
|
||||
|
||||
|
||||
def calculate(callback, args, kwargs):
|
||||
|
@ -253,7 +253,8 @@ class SubConfig(object):
|
||||
force_properties=force_properties,
|
||||
force_permissive=force_permissive)
|
||||
|
||||
def find(self, bytype=None, byname=None, byvalue=None, type_='option'):
|
||||
def find(self, bytype=None, byname=None, byvalue=None, type_='option',
|
||||
check_properties=True):
|
||||
"""
|
||||
finds a list of options recursively in the config
|
||||
|
||||
@ -265,11 +266,11 @@ class SubConfig(object):
|
||||
return self._cfgimpl_get_context()._find(bytype, byname, byvalue,
|
||||
first=False,
|
||||
type_=type_,
|
||||
_subpath=self.cfgimpl_get_path()
|
||||
)
|
||||
_subpath=self.cfgimpl_get_path(),
|
||||
check_properties=check_properties)
|
||||
|
||||
def find_first(self, bytype=None, byname=None, byvalue=None,
|
||||
type_='option', display_error=True):
|
||||
type_='option', display_error=True, check_properties=True):
|
||||
"""
|
||||
finds an option recursively in the config
|
||||
|
||||
@ -280,7 +281,8 @@ class SubConfig(object):
|
||||
"""
|
||||
return self._cfgimpl_get_context()._find(
|
||||
bytype, byname, byvalue, first=True, type_=type_,
|
||||
_subpath=self.cfgimpl_get_path(), display_error=display_error)
|
||||
_subpath=self.cfgimpl_get_path(), display_error=display_error,
|
||||
check_properties=check_properties)
|
||||
|
||||
def _find(self, bytype, byname, byvalue, first, type_='option',
|
||||
_subpath=None, check_properties=True, display_error=True):
|
||||
|
@ -47,9 +47,7 @@ forbidden_names = ('iter_all', 'iter_group', 'find', 'find_first',
|
||||
|
||||
def valid_name(name):
|
||||
"an option's name is a str and does not start with 'impl' or 'cfgimpl'"
|
||||
try:
|
||||
name = str(name)
|
||||
except:
|
||||
if not isinstance(name, str):
|
||||
return False
|
||||
if re.match(name_regexp, name) is None and not name.startswith('_') \
|
||||
and name not in forbidden_names \
|
||||
@ -636,7 +634,7 @@ class Option(BaseOption):
|
||||
else:
|
||||
validator_params = (FakeCallbackParam('', (FakeCallbackParamOption(value=val),)),)
|
||||
# Raise ValueError if not valid
|
||||
carry_out_calculation(self.impl_getname(), config=context,
|
||||
carry_out_calculation(self, config=context,
|
||||
callback=self._validator,
|
||||
callback_params=validator_params)
|
||||
|
||||
@ -674,17 +672,13 @@ class Option(BaseOption):
|
||||
do_validation(value, force_index)
|
||||
else:
|
||||
if not isinstance(value, list):
|
||||
raise ValueError(_("which must be a list").format(value,
|
||||
self.impl_getname()))
|
||||
raise ValueError(_("invalid value {0} for option {1} which must be a list").format(value, self.impl_getname()))
|
||||
for index, val in enumerate(value):
|
||||
do_validation(val, index)
|
||||
|
||||
def impl_getdefault(self, default_multi=False):
|
||||
def impl_getdefault(self):
|
||||
"accessing the default value"
|
||||
if not default_multi or not self.impl_is_multi():
|
||||
return self._default
|
||||
else:
|
||||
return self.getdefault_multi()
|
||||
return self._default
|
||||
|
||||
def impl_getdefault_multi(self):
|
||||
"accessing the default value for a multi"
|
||||
@ -940,7 +934,7 @@ class StrOption(Option):
|
||||
|
||||
|
||||
if sys.version_info[0] >= 3:
|
||||
#UnicodeOption is same has StrOption in python 3+
|
||||
#UnicodeOption is same as StrOption in python 3+
|
||||
class UnicodeOption(StrOption):
|
||||
__slots__ = tuple()
|
||||
pass
|
||||
@ -1022,6 +1016,12 @@ class IPOption(Option):
|
||||
warnings_only=warnings_only)
|
||||
|
||||
def _validate(self, value):
|
||||
# sometimes an ip term starts with a zero
|
||||
# but this does not fit in some case, for example bind does not like it
|
||||
for val in value.split('.'):
|
||||
if val.startswith("0") and len(val) > 1:
|
||||
raise ValueError(_('invalid IP'))
|
||||
# 'standard' validation
|
||||
try:
|
||||
IP('{0}/32'.format(value))
|
||||
except ValueError:
|
||||
@ -1533,7 +1533,6 @@ class OptionDescription(BaseOption):
|
||||
self._optiondescription_group_type = group_type
|
||||
if isinstance(group_type, groups.MasterGroupType):
|
||||
#if master (same name has group) is set
|
||||
identical_master_child_name = False
|
||||
#for collect all slaves
|
||||
slaves = []
|
||||
master = None
|
||||
@ -1549,8 +1548,7 @@ class OptionDescription(BaseOption):
|
||||
"in group {1}"
|
||||
": this option is not a multi"
|
||||
"").format(child.impl_getname(), self.impl_getname()))
|
||||
if child.impl_getname() == self.impl_getname():
|
||||
identical_master_child_name = True
|
||||
if child._name == self.impl_getname():
|
||||
child._multitype = multitypes.master
|
||||
master = child
|
||||
else:
|
||||
@ -1559,14 +1557,18 @@ class OptionDescription(BaseOption):
|
||||
raise ValueError(_('master group with wrong'
|
||||
' master name for {0}'
|
||||
).format(self.impl_getname()))
|
||||
if master._callback is not None and master._callback[1] is not None:
|
||||
for key, callbacks in master._callback[1].items():
|
||||
for callbk in callbacks:
|
||||
if isinstance(callbk, tuple):
|
||||
if callbk[0] in slaves:
|
||||
raise ValueError(_("callback of master's option shall "
|
||||
"not refered a slave's ones"))
|
||||
master._master_slaves = tuple(slaves)
|
||||
for child in self.impl_getchildren():
|
||||
if child != master:
|
||||
child._master_slaves = master
|
||||
child._multitype = multitypes.slave
|
||||
if not identical_master_child_name:
|
||||
raise ValueError(_("no child has same nom has master group"
|
||||
" for: {0}").format(self.impl_getname()))
|
||||
else:
|
||||
raise ValueError(_('group_type: {0}'
|
||||
' not allowed').format(group_type))
|
||||
|
@ -242,6 +242,12 @@ multitypes = MultiTypeModule()
|
||||
populate_multitypes()
|
||||
|
||||
|
||||
# ____________________________________________________________
|
||||
class Undefined():
|
||||
pass
|
||||
|
||||
|
||||
undefined = Undefined()
|
||||
# ____________________________________________________________
|
||||
class Property(object):
|
||||
"a property is responsible of the option's value access rules"
|
||||
@ -410,10 +416,11 @@ class Settings(object):
|
||||
"""
|
||||
# opt properties
|
||||
properties = copy(self._getproperties(opt_or_descr, path))
|
||||
# remove opt permissive
|
||||
properties -= self._p_.getpermissive(path)
|
||||
# remove global permissive if need
|
||||
self_properties = copy(self._getproperties())
|
||||
# remove opt permissive
|
||||
if force_permissive is True or 'permissive' in self_properties:
|
||||
properties -= self._p_.getpermissive(path)
|
||||
# remove global permissive if need
|
||||
if force_permissive is True or 'permissive' in self_properties:
|
||||
properties -= self._p_.getpermissive()
|
||||
if force_permissives is not None:
|
||||
|
@ -22,7 +22,7 @@ from copy import copy
|
||||
import sys
|
||||
import weakref
|
||||
from tiramisu.error import ConfigError, SlaveError
|
||||
from tiramisu.setting import owners, multitypes, expires_time
|
||||
from tiramisu.setting import owners, multitypes, expires_time, undefined
|
||||
from tiramisu.autolib import carry_out_calculation
|
||||
from tiramisu.i18n import _
|
||||
from tiramisu.option import SymLinkOption
|
||||
@ -137,7 +137,7 @@ class Values(object):
|
||||
callback, callback_params = opt.impl_get_callback()
|
||||
if callback_params is None:
|
||||
callback_params = {}
|
||||
return carry_out_calculation(opt.impl_getname(), config=self.context(),
|
||||
return carry_out_calculation(opt, config=self.context(),
|
||||
callback=callback,
|
||||
callback_params=callback_params,
|
||||
index=index, max_len=max_len)
|
||||
@ -452,8 +452,7 @@ class Multi(list):
|
||||
values._getcallback_value(slave, index=index),
|
||||
force=True)
|
||||
else:
|
||||
value_slave.append(slave.impl_getdefault_multi(),
|
||||
force=True)
|
||||
value_slave.append(undefined, force=True)
|
||||
|
||||
def __setitem__(self, index, value):
|
||||
self._validate(value, index)
|
||||
@ -461,7 +460,7 @@ class Multi(list):
|
||||
super(Multi, self).__setitem__(index, value)
|
||||
self.context().cfgimpl_get_values()._setvalue(self.opt, self.path, self)
|
||||
|
||||
def append(self, value, force=False):
|
||||
def append(self, value=undefined, force=False):
|
||||
"""the list value can be updated (appened)
|
||||
only if the option is a master
|
||||
"""
|
||||
@ -471,12 +470,14 @@ class Multi(list):
|
||||
" which is a slave").format(self.opt.impl_getname()))
|
||||
elif self.opt.impl_get_multitype() == multitypes.master:
|
||||
values = self.context().cfgimpl_get_values()
|
||||
if value is None and self.opt.impl_has_callback():
|
||||
if value is undefined and self.opt.impl_has_callback():
|
||||
value = values._getcallback_value(self.opt)
|
||||
#Force None il return a list
|
||||
if isinstance(value, list):
|
||||
value = None
|
||||
index = self.__len__()
|
||||
if value is undefined:
|
||||
value = self.opt.impl_getdefault_multi()
|
||||
self._validate(value, index)
|
||||
super(Multi, self).append(value)
|
||||
self.context().cfgimpl_get_values()._setvalue(self.opt, self.path,
|
||||
|
Reference in New Issue
Block a user