This commit is contained in:
Emmanuel Garette 2018-09-12 21:05:14 +02:00
parent 10aaf2219f
commit cd7977eae6
13 changed files with 140 additions and 81 deletions

View file

@ -6,8 +6,9 @@ do_autopath()
from py.test import raises from py.test import raises
from tiramisu.error import APIError from tiramisu.error import APIError, ConfigError
from tiramisu import IntOption, OptionDescription, Config from tiramisu import IntOption, OptionDescription, Config
from tiramisu.setting import groups
def a_func(): def a_func():
@ -113,6 +114,39 @@ def test_unknown_option():
raises(AttributeError, "api.option('od.unknown.suboption').value.get()") raises(AttributeError, "api.option('od.unknown.suboption').value.get()")
def test_optiondescription_group():
groups.notfamily = groups.GroupType('notfamily')
i = IntOption('test', '')
i2 = IntOption('test', '')
od1 = OptionDescription('od', '', [i])
od1.impl_set_group_type(groups.family)
od3 = OptionDescription('od2', '', [i2])
od3.impl_set_group_type(groups.notfamily)
od2 = OptionDescription('od', '', [od1, od3])
api = Config(od2)
assert len(list(api.option.list('optiondescription'))) == 2
assert len(list(api.option.list('optiondescription', group_type=groups.family))) == 1
assert len(list(api.option.list('optiondescription', group_type=groups.notfamily))) == 1
def test_optiondescription_group_redefined():
try:
groups.notfamily = groups.GroupType('notfamily')
except:
pass
i = IntOption('test', '')
od1 = OptionDescription('od', '', [i])
od1.impl_set_group_type(groups.family)
raises(ValueError, "od1.impl_set_group_type(groups.notfamily)")
def test_optiondescription_group_masterslave():
i = IntOption('test', '')
od1 = OptionDescription('od', '', [i])
raises(ConfigError, "od1.impl_set_group_type(groups.master)")
def test_asign_optiondescription(): def test_asign_optiondescription():
i = IntOption('test', '') i = IntOption('test', '')
od1 = OptionDescription('od', '', [i]) od1 = OptionDescription('od', '', [i])

View file

@ -241,6 +241,20 @@ def test_callback_params_without_callback():
raises(ValueError, "StrOption('val2', '', callback_params=Params(ParamValue('yes')))") raises(ValueError, "StrOption('val2', '', callback_params=Params(ParamValue('yes')))")
def test_params():
raises(ValueError, "Params([ParamContext()])")
raises(ValueError, "Params('str')")
raises(ValueError, "Params(('str',))")
raises(ValueError, "Params(kwargs=[ParamContext()])")
raises(ValueError, "Params(kwargs={'a': 'str'})")
def test_param_option():
val1 = StrOption('val1', "")
raises(ValueError, "ParamOption('str')")
raises(ValueError, "ParamOption(val1, 'str')")
def test_callback_invalid(): def test_callback_invalid():
raises(ValueError, 'val1 = StrOption("val1", "", callback="string")') raises(ValueError, 'val1 = StrOption("val1", "", callback="string")')
raises(ValueError, 'val1 = StrOption("val1", "", callback=return_val, callback_params="string")') raises(ValueError, 'val1 = StrOption("val1", "", callback=return_val, callback_params="string")')

View file

@ -415,6 +415,17 @@ def test_consistency_ip_netmask():
api.option('b').value.set('255.255.255.0') api.option('b').value.set('255.255.255.0')
raises(ValueError, "api.option('a').value.set('192.168.1.0')") raises(ValueError, "api.option('a').value.set('192.168.1.0')")
raises(ValueError, "api.option('a').value.set('192.168.1.255')") raises(ValueError, "api.option('a').value.set('192.168.1.255')")
api.option('a').value.reset()
api.option('b').value.reset()
api.option('a').value.set('192.168.1.255')
raises(ValueError, "api.option('b').value.set('255.255.255.0')")
def test_consistency_ip_netmask_invalid():
a = IPOption('a', '')
b = NetmaskOption('b', '')
od = OptionDescription('od', '', [a, b])
raises(ConfigError, "b.impl_add_consistency('ip_netmask')")
def test_consistency_network_netmask(): def test_consistency_network_netmask():
@ -431,6 +442,13 @@ def test_consistency_network_netmask():
raises(ValueError, "api.option('a').value.set('192.168.1.1')") raises(ValueError, "api.option('a').value.set('192.168.1.1')")
def test_consistency_network_netmask_invalid():
a = NetworkOption('a', '')
b = NetmaskOption('b', '')
od = OptionDescription('od', '', [a, b])
raises(ConfigError, "b.impl_add_consistency('network_netmask')")
def test_consistency_ip_in_network(): def test_consistency_ip_in_network():
a = NetworkOption('a', '') a = NetworkOption('a', '')
b = NetmaskOption('b', '') b = NetmaskOption('b', '')
@ -452,26 +470,13 @@ def test_consistency_ip_in_network():
assert len(w) == 1 assert len(w) == 1
# needs 3 arguments, not 2 def test_consistency_ip_in_network_invalid():
#def test_consistency_ip_in_network_len_error(): a = NetworkOption('a', '')
# a = NetworkOption('a', '') b = NetmaskOption('b', '')
# b = NetmaskOption('b', '') c = IPOption('c', '')
# c = IPOption('c', '') d = IPOption('d', '')
# od = OptionDescription('od', '', [a, b, c]) od = OptionDescription('od', '', [a, b, c, d])
# raises(ConfigError, "c.impl_add_consistency('in_network', a)") raises(ConfigError, "c.impl_add_consistency('in_network', a)")
# needs 2 arguments, not 3
#def test_consistency_ip_netmask_network_error():
# a = IPOption('a', '')
# b = NetworkOption('b', '')
# c = NetmaskOption('c', '')
# od = OptionDescription('od', '', [a, b, c])
# c.impl_add_consistency('ip_netmask', a, b)
# api = Config(od)
# api.option('a').value.set('192.168.1.1')
# api.option('b').value.set('192.168.1.0')
# raises(ConfigError, "api.option('c').value.set('255.255.255.0')")
def test_consistency_ip_netmask_error_multi(): def test_consistency_ip_netmask_error_multi():

View file

@ -112,6 +112,17 @@ def test_setowner_for_value():
assert api.option('dummy').owner.get() == owners.new2 assert api.option('dummy').owner.get() == owners.new2
def test_setowner_forbidden():
gcdummy = BoolOption('dummy', 'dummy', default=False)
descr = OptionDescription('tiramisu', '', [gcdummy])
api = Config(descr)
assert api.option('dummy').value.get() is False
assert api.option('dummy').owner.get() == 'default'
raises(ValueError, "api.owner.set('default')")
api.option('dummy').value.set(False)
raises(ValueError, "api.option('dummy').owner.set('default')")
def test_setowner_read_only(): def test_setowner_read_only():
gcdummy = BoolOption('dummy', 'dummy', default=False) gcdummy = BoolOption('dummy', 'dummy', default=False)
descr = OptionDescription('tiramisu', '', [gcdummy]) descr = OptionDescription('tiramisu', '', [gcdummy])

View file

@ -49,7 +49,8 @@ class BroadcastOption(Option):
current_opt, current_opt,
opts, opts,
vals, vals,
warnings_only): warnings_only,
context):
if len(vals) != 3: if len(vals) != 3:
raise ConfigError(_('invalid len for vals')) raise ConfigError(_('invalid len for vals'))
if None in vals: if None in vals:

View file

@ -85,7 +85,6 @@ class ChoiceOption(Option):
current_opt=undefined): current_opt=undefined):
if current_opt is undefined: if current_opt is undefined:
current_opt = self current_opt = self
#FIXME cache? but in context...
values = self._choice_values values = self._choice_values
if isinstance(values, FunctionType): if isinstance(values, FunctionType):
if option_bag is undefined: if option_bag is undefined:

View file

@ -101,7 +101,10 @@ class IPOption(Option):
current_opt, current_opt,
opts, opts,
vals, vals,
warnings_only): warnings_only,
context):
if len(vals) != 3 and context is undefined:
raise ConfigError(_('ip_network needs an IP, a network and a netmask'))
if len(vals) != 3 or None in vals: if len(vals) != 3 or None in vals:
return return
ip, network, netmask = vals ip, network, netmask = vals
@ -117,4 +120,5 @@ class IPOption(Option):
opts[2]._cons_ip_netmask(current_opt, opts[2]._cons_ip_netmask(current_opt,
(opts[2], opts[0]), (opts[2], opts[0]),
(netmask, ip), (netmask, ip),
warnings_only) warnings_only,
context)

View file

@ -50,9 +50,12 @@ class NetmaskOption(Option):
current_opt, current_opt,
opts, opts,
vals, vals,
warnings_only): warnings_only,
context):
#opts must be (netmask, network) options #opts must be (netmask, network) options
if len(vals) != 2 or None in vals: if context is undefined and len(vals) != 2:
raise ConfigError(_('network_netmask needs a network and a netmask'))
if None in vals or len(vals) != 2:
return return
return self.__cons_netmask(current_opt, return self.__cons_netmask(current_opt,
opts, opts,
@ -66,9 +69,12 @@ class NetmaskOption(Option):
current_opt, current_opt,
opts, opts,
vals, vals,
warnings_only): warnings_only,
context):
#opts must be (netmask, ip) options #opts must be (netmask, ip) options
if len(vals) != 2 or None in vals: if context is undefined and len(vals) != 2:
raise ConfigError(_('ip_netmask needs an IP and a netmask'))
if None in vals or len(vals) != 2:
return return
self.__cons_netmask(current_opt, self.__cons_netmask(current_opt,
opts, opts,
@ -86,8 +92,6 @@ class NetmaskOption(Option):
make_net, make_net,
warnings_only, warnings_only,
typ): typ):
if len(opts) != 2:
raise ConfigError(_('invalid len for opts'))
msg = None msg = None
try: try:
ip = IP('{0}/{1}'.format(val_ipnetwork, val_netmask), make_net=make_net) ip = IP('{0}/{1}'.format(val_ipnetwork, val_netmask), make_net=make_net)
@ -99,7 +103,7 @@ class NetmaskOption(Option):
msg = _('this is a network with netmask "{0}" ("{1}")') msg = _('this is a network with netmask "{0}" ("{1}")')
else: else:
msg = _('this is a network with {2} "{0}" ("{1}")') msg = _('this is a network with {2} "{0}" ("{1}")')
if ip.broadcast() == val_ip: elif ip.broadcast() == val_ip:
if current_opt == opts[1]: if current_opt == opts[1]:
msg = _('this is a broadcast with netmask "{0}" ("{1}")') msg = _('this is a broadcast with netmask "{0}" ("{1}")')
else: else:

View file

@ -207,8 +207,9 @@ class Option(OnlyOption):
return return
def _is_not_unique(value): def _is_not_unique(value):
#FIXME pourquoi la longueur doit etre egal ? # if set(value) has not same length than value
if check_error and self.impl_is_unique() and len(set(value)) != len(value): if check_error and self.impl_is_unique() and \
len(set(value)) != len(value):
for idx, val in enumerate(value): for idx, val in enumerate(value):
if val in value[idx+1:]: if val in value[idx+1:]:
raise ValueError(_('invalid value "{}", this value is already in "{}"' raise ValueError(_('invalid value "{}", this value is already in "{}"'
@ -243,7 +244,6 @@ class Option(OnlyOption):
if isinstance(_value, list): # pragma: no cover if isinstance(_value, list): # pragma: no cover
raise ValueError(_('which must not be a list').format(_value, raise ValueError(_('which must not be a list').format(_value,
self.impl_get_display_name())) self.impl_get_display_name()))
#FIXME a revoir ...
if _value is not None: if _value is not None:
if check_error: if check_error:
# option validation # option validation
@ -271,8 +271,6 @@ class Option(OnlyOption):
self.__class__.__name__, 0) self.__class__.__name__, 0)
else: else:
raise err raise err
#if is_multi is None:
# is_multi = self.impl_is_multi()
try: try:
val = value val = value
if not self.impl_is_multi(): if not self.impl_is_multi():
@ -332,8 +330,6 @@ class Option(OnlyOption):
return False return False
def impl_is_master_slaves(self, type_='both'): def impl_is_master_slaves(self, type_='both'):
"""FIXME
"""
master_slaves = self.impl_get_master_slaves() master_slaves = self.impl_get_master_slaves()
if master_slaves is not None: if master_slaves is not None:
if type_ in ('both', 'master') and \ if type_ in ('both', 'master') and \
@ -654,7 +650,8 @@ class Option(OnlyOption):
getattr(self, func)(current_opt, getattr(self, func)(current_opt,
all_cons_opts, all_cons_opts,
values, values,
warnings_only) warnings_only,
context)
except ValueError as err: except ValueError as err:
if warnings_only: if warnings_only:
msg = _('attention, "{0}" could be an invalid {1} for "{2}", {3}' msg = _('attention, "{0}" could be an invalid {1} for "{2}", {3}'
@ -672,7 +669,8 @@ class Option(OnlyOption):
current_opt, current_opt,
opts, opts,
vals, vals,
warnings_only): warnings_only,
context):
equal = [] equal = []
is_current = False is_current = False
for idx_inf, val_inf in enumerate(vals): for idx_inf, val_inf in enumerate(vals):

View file

@ -74,6 +74,15 @@ class CacheOptionDescription(BaseOption):
if not option.impl_is_symlinkoption(): if not option.impl_is_symlinkoption():
properties = option.impl_getproperties() properties = option.impl_getproperties()
if 'force_store_value' in properties: if 'force_store_value' in properties:
if option.impl_is_master_slaves('slave'):
# problem with index
raise ConfigError(_('the slave "{0}" cannot have '
'"force_store_value" property').format(
option.impl_get_display_name()))
if option.issubdyn():
raise ConfigError(_('the dynoption "{0}" cannot have '
'"force_store_value" property').format(
option.impl_get_display_name()))
force_store_values.append((subpath, option)) force_store_values.append((subpath, option))
if 'force_default_on_freeze' in properties and \ if 'force_default_on_freeze' in properties and \
'frozen' not in properties and \ 'frozen' not in properties and \
@ -163,15 +172,6 @@ class CacheOptionDescription(BaseOption):
value_setted = False value_setted = False
values = context.cfgimpl_get_values() values = context.cfgimpl_get_values()
for subpath, option in self._cache_force_store_values: for subpath, option in self._cache_force_store_values:
if option.impl_is_master_slaves('slave'):
# problem with index
raise ConfigError(_('the slave "{0}" cannot have '
'"force_store_value" property').format(
option.impl_get_display_name()))
if option.issubdyn():
raise ConfigError(_('the dynoption "{0}" cannot have '
'"force_store_value" property').format(
option.impl_get_display_name()))
if not values._p_.hasvalue(subpath): if not values._p_.hasvalue(subpath):
config_bag = ConfigBag(context=context) config_bag = ConfigBag(context=context)
option_bag = OptionBag() option_bag = OptionBag()
@ -429,12 +429,6 @@ class OptionDescription(OptionDescriptionWalk):
def impl_getdoc(self): def impl_getdoc(self):
return self.impl_get_information('doc') return self.impl_get_information('doc')
def impl_validate(self,
*args,
**kwargs):
"""usefull for OptionDescription"""
pass
# ____________________________________________________________ # ____________________________________________________________
def impl_set_group_type(self, def impl_set_group_type(self,
group_type): group_type):
@ -444,8 +438,8 @@ class OptionDescription(OptionDescriptionWalk):
that lives in `setting.groups` that lives in `setting.groups`
""" """
if self._group_type != groups.default: if self._group_type != groups.default:
raise TypeError(_('cannot change group_type if already set ' raise ValueError(_('cannot change group_type if already set '
'(old {0}, new {1})').format(self._group_type, '(old {0}, new {1})').format(self._group_type,
group_type)) group_type))
if not isinstance(group_type, groups.GroupType): if not isinstance(group_type, groups.GroupType):
raise ValueError(_('group_type: {0}' raise ValueError(_('group_type: {0}'

View file

@ -785,6 +785,9 @@ class Settings(object):
def setowner(self, def setowner(self,
owner): owner):
":param owner: sets the default value for owner at the Config level" ":param owner: sets the default value for owner at the Config level"
if owner in forbidden_owners:
raise ValueError(_('set owner "{0}" is forbidden').format(str(owner)))
self._owner = owner self._owner = owner
def getowner(self): def getowner(self):

View file

@ -19,7 +19,7 @@ from time import time
from .cache.dictionary import Cache as DictCache from .cache.dictionary import Cache as DictCache
def _display_classname(obj): def _display_classname(obj): # pragma: no cover
return(obj.__class__.__name__.lower()) return(obj.__class__.__name__.lower())
DEBUG = False DEBUG = False
@ -38,12 +38,12 @@ class Cache(DictCache):
if slave, add index if slave, add index
""" """
if 'cache' in props or 'cache' in self_props: if 'cache' in props or 'cache' in self_props:
if DEBUG: if DEBUG: # pragma: no cover
print('setcache {} with index {} and value {} in {} ({})'.format(path, index, val, print('setcache {} with index {} and value {} in {} ({})'.format(path, index, val,
_display_classname(self), _display_classname(self),
id(self))) id(self)))
self._setcache(path, index, val, time()) self._setcache(path, index, val, time())
elif DEBUG: elif DEBUG: # pragma: no cover
print('not setcache {} with index {} and value {} and props {} and {} in {} ({})'.format(path, print('not setcache {} with index {} and value {} and props {} and {} in {} ({})'.format(path,
index, index,
val, val,
@ -60,7 +60,7 @@ class Cache(DictCache):
self_props, self_props,
type_): type_):
no_cache = False, None no_cache = False, None
if 'cache' in props: if 'cache' in props or type_ == 'context_props':
indexed = self._getcache(path, index) indexed = self._getcache(path, index)
if indexed is None: if indexed is None:
return no_cache return no_cache
@ -79,22 +79,22 @@ class Cache(DictCache):
'expire' in self_props): 'expire' in self_props):
ntime = int(time()) ntime = int(time())
if timestamp + expires_time >= ntime: if timestamp + expires_time >= ntime:
if DEBUG: if DEBUG: # pragma: no cover
print('getcache in cache (1)', path, value, _display_classname(self), print('getcache in cache (1)', path, value, _display_classname(self),
id(self), index) id(self), index)
return True, value return True, value
else: else:
if DEBUG: if DEBUG: # pragma: no cover
print('getcache expired value for path {} < {}'.format( print('getcache expired value for path {} < {}'.format(
timestamp + expires_time, ntime)) timestamp + expires_time, ntime))
# if expired, remove from cache # if expired, remove from cache
#self.delcache(path) #self.delcache(path)
else: else:
if DEBUG: if DEBUG: # pragma: no cover
print('getcache in cache (2)', path, value, _display_classname(self), print('getcache in cache (2)', path, value, _display_classname(self),
id(self), index) id(self), index)
return True, value return True, value
if DEBUG: if DEBUG: # pragma: no cover
print('getcache {} with index {} not in {} cache'.format(path, index, print('getcache {} with index {} not in {} cache'.format(path, index,
_display_classname(self))) _display_classname(self)))
return no_cache return no_cache
@ -102,14 +102,14 @@ class Cache(DictCache):
def delcache(self, path): def delcache(self, path):
"""remove cache for a specified path """remove cache for a specified path
""" """
if DEBUG: if DEBUG: # pragma: no cover
print('delcache', path, _display_classname(self), id(self)) print('delcache', path, _display_classname(self), id(self))
if path in self._cache: if path in self._cache:
self._delcache(path) self._delcache(path)
def reset_all_cache(self): def reset_all_cache(self):
"empty the cache" "empty the cache"
if DEBUG: if DEBUG: # pragma: no cover
print('reset_all_cache', _display_classname(self), id(self)) print('reset_all_cache', _display_classname(self), id(self))
self._reset_all_cache() self._reset_all_cache()
@ -118,6 +118,6 @@ class Cache(DictCache):
please only use it in test purpose please only use it in test purpose
example: {'path1': {'index1': ('value1', 'time1')}, 'path2': {'index2': ('value2', 'time2', )}} example: {'path1': {'index1': ('value1', 'time1')}, 'path2': {'index2': ('value2', 'time2', )}}
""" """
if DEBUG: if DEBUG: # pragma: no cover
print('get_chached {} for {} ({})'.format(self._cache, _display_classname(self), id(self))) print('get_chached {} for {} ({})'.format(self._cache, _display_classname(self), id(self)))
return self._get_cached() return self._get_cached()

View file

@ -109,19 +109,11 @@ class Values(object):
owners.default, owners.default,
index=_index, index=_index,
with_value=True) with_value=True)
if owner != owners.default and not ('frozen' in option_bag.properties and \
if owner != owners.default: 'force_default_on_freeze' in option_bag.properties):
# if a value is store in storage, check if not frozen + force_default_on_freeze # if a value is store in storage, check if not frozen + force_default_on_freeze
# if frozen + force_default_on_freeze => force default value # if frozen + force_default_on_freeze => force default value
if not ('frozen' in option_bag.properties and \ return value
'force_default_on_freeze' in option_bag.properties):
if index is not None and not is_slave:
if len(value) > index:
return value[index]
#value is smaller than expected
#so return default value
else:
return value
return self.getdefaultvalue(option_bag) return self.getdefaultvalue(option_bag)
def getdefaultvalue(self, def getdefaultvalue(self,
@ -415,7 +407,7 @@ class Values(object):
raise ConfigError(_("can't set owner for the symlinkoption \"{}\"" raise ConfigError(_("can't set owner for the symlinkoption \"{}\""
"").format(opt.impl_get_display_name())) "").format(opt.impl_get_display_name()))
if owner in forbidden_owners: if owner in forbidden_owners:
raise ConfigError(_('set owner "{0}" is forbidden').format(str(owner))) raise ValueError(_('set owner "{0}" is forbidden').format(str(owner)))
if not self._p_.hasvalue(option_bag.path): if not self._p_.hasvalue(option_bag.path):
raise ConfigError(_('no value for {0} cannot change owner to {1}' raise ConfigError(_('no value for {0} cannot change owner to {1}'