propertyerror are transitive in consistency, now it's possible to set non-transitive consistency

This commit is contained in:
Emmanuel Garette 2014-12-01 22:58:53 +01:00
parent 2ccf92f879
commit 7646071efd
4 changed files with 92 additions and 42 deletions

View file

@ -1,3 +1,7 @@
Mon Dec 1 22:58:13 2014 +0200 Emmanuel Garette <egarette@cadoles.com>
* propertyerror are transitive in consistency, now it's possible to set
non-transitive consistency
Sun Oct 26 08:50:38 2014 +0200 Emmanuel Garette <egarette@cadoles.com>
* if option is frozen with force_default_on_freeze property, owner
must be 'default' check property when tried to change owner

View file

@ -5,7 +5,7 @@ from tiramisu.setting import owners, groups
from tiramisu.config import Config
from tiramisu.option import IPOption, NetworkOption, NetmaskOption, IntOption,\
BroadcastOption, SymLinkOption, OptionDescription
from tiramisu.error import ConfigError, ValueWarning
from tiramisu.error import ConfigError, ValueWarning, PropertiesOptionError
import warnings
@ -27,6 +27,13 @@ def test_consistency_not_exists():
raises(ConfigError, "a.impl_add_consistency('not_exists', b)")
def test_consistency_unknown_params():
a = IntOption('a', '')
b = IntOption('b', '')
od = OptionDescription('od', '', [a, b])
raises(ValueError, "a.impl_add_consistency('not_equal', b, unknown=False)")
def test_consistency_warnings_only():
a = IntOption('a', '')
b = IntOption('b', '')
@ -392,6 +399,26 @@ def test_consistency_permissive():
c.a = 1
def test_consistency_disabled():
a = IntOption('a', '')
b = IntOption('b', '', properties=('disabled',))
od = OptionDescription('od', '', [a, b])
a.impl_add_consistency('not_equal', b)
c = Config(od)
c.read_write()
raises(PropertiesOptionError, "c.a = 1")
def test_consistency_disabled_transitive():
a = IntOption('a', '')
b = IntOption('b', '', properties=('disabled',))
od = OptionDescription('od', '', [a, b])
a.impl_add_consistency('not_equal', b, transitive=False)
c = Config(od)
c.read_write()
c.a = 1
def return_val(*args, **kwargs):
return '192.168.1.1'

View file

@ -25,7 +25,7 @@ import warnings
from tiramisu.i18n import _
from tiramisu.setting import log, undefined
from tiramisu.autolib import carry_out_calculation
from tiramisu.error import ConfigError, ValueWarning
from tiramisu.error import ConfigError, ValueWarning, PropertiesOptionError
from tiramisu.storage import get_storages_option
@ -403,7 +403,8 @@ class Option(OnlyOption):
_empty = ''
def _launch_consistency(self, func, option, value, context, index,
submulti_index, all_cons_opts, warnings_only):
submulti_index, all_cons_opts, warnings_only,
transitive):
"""Launch consistency now
:param func: function name, this name should start with _cons_
@ -420,47 +421,55 @@ class Option(OnlyOption):
:type all_cons_opts: `list` of `tiramisu.option.Option`
:param warnings_only: specific raise error for warning
:type warnings_only: `boolean`
:param transitive: propertyerror is transitive
:type transitive: `boolean`
"""
if context is not undefined:
descr = context.cfgimpl_get_description()
all_cons_vals = []
for opt in all_cons_opts:
#get value
if (isinstance(opt, DynSymLinkOption) and option._dyn == opt._dyn) or \
option == opt:
opt_value = value
else:
#if context, calculate value, otherwise get default value
if context is not undefined:
if isinstance(opt, DynSymLinkOption):
path = opt.impl_getpath(context)
else:
path = descr.impl_get_path_by_opt(opt)
opt_value = context.getattr(path, validate=False,
force_permissive=True)
try:
#get value
if (isinstance(opt, DynSymLinkOption) and option._dyn == opt._dyn) or \
option == opt:
opt_value = value
else:
opt_value = opt.impl_getdefault()
#if context, calculate value, otherwise get default value
if context is not undefined:
if isinstance(opt, DynSymLinkOption):
path = opt.impl_getpath(context)
else:
path = descr.impl_get_path_by_opt(opt)
opt_value = context.getattr(path, validate=False,
force_permissive=True)
else:
opt_value = opt.impl_getdefault()
#append value
if not self.impl_is_multi() or (isinstance(opt, DynSymLinkOption)
and option._dyn == opt._dyn) or \
option == opt:
all_cons_vals.append(opt_value)
elif self.impl_is_submulti():
try:
all_cons_vals.append(opt_value[index][submulti_index])
except IndexError:
#value is not already set, could be higher index
#so return if no value
return
else:
try:
all_cons_vals.append(opt_value[index])
except IndexError:
#value is not already set, could be higher index
#so return if no value
return
#append value
if not self.impl_is_multi() or (isinstance(opt, DynSymLinkOption)
and option._dyn == opt._dyn) or \
option == opt:
all_cons_vals.append(opt_value)
elif self.impl_is_submulti():
try:
all_cons_vals.append(opt_value[index][submulti_index])
except IndexError:
#value is not already set, could be higher index
#so return if no value
return
else:
try:
all_cons_vals.append(opt_value[index])
except IndexError:
#value is not already set, could be higher index
#so return if no value
return
except PropertiesOptionError as err:
if transitive:
raise err
else:
pass
getattr(self, func)(all_cons_opts, all_cons_vals, warnings_only)
def impl_validate(self, value, context=undefined, validate=True,
@ -636,14 +645,22 @@ class Option(OnlyOption):
:type func: `str`
:param other_opts: options used to validate value
:type other_opts: `list` of `tiramisu.option.Option`
:param params: extra params (only warnings_only are allowed)
:param params: extra params (warnings_only and transitive are allowed)
"""
if self.impl_is_readonly(): # pragma: optional cover
raise AttributeError(_("'{0}' ({1}) cannot add consistency, option is"
" read-only").format(
self.__class__.__name__,
self.impl_getname()))
warnings_only = params.get('warnings_only', False)
warnings_only = False
transitive = True
for key, value in params.items():
if key == 'warnings_only':
warnings_only = value
elif key == 'transitive':
transitive = value
else:
raise ValueError(_('unknow parameter {0} in consistency').format(key))
if self._is_subdyn():
dynod = self._impl_getsubdyn()
else:
@ -678,16 +695,17 @@ class Option(OnlyOption):
if not self.impl_is_submulti():
self._launch_consistency(func, self, val, undefined, idx,
None, all_cons_opts,
warnings_only)
warnings_only, transitive)
else:
for slave_idx, val in enumerate(value):
self._launch_consistency(func, self, val, None,
idx, slave_idx,
all_cons_opts,
warnings_only)
warnings_only, transitive)
else:
self._launch_consistency(func, self, value, undefined, None,
None, all_cons_opts, warnings_only)
None, all_cons_opts, warnings_only,
transitive)
self._add_consistency(func, all_cons_opts, params)
self.impl_validate(self.impl_getdefault())

View file

@ -175,6 +175,7 @@ class OptionDescription(BaseOption, StorageOptionDescription):
if consistencies is not None:
for func, all_cons_opts, params in consistencies:
warnings_only = params.get('warnings_only', False)
transitive = params.get('transitive', True)
#all_cons_opts[0] is the option where func is set
if isinstance(option, DynSymLinkOption):
subpath = '.'.join(option._dyn.split('.')[:-1])
@ -190,7 +191,7 @@ class OptionDescription(BaseOption, StorageOptionDescription):
try:
opts[0]._launch_consistency(func, option, value, context,
index, submulti_idx, opts,
warnings_only)
warnings_only, transitive)
except ValueError as err:
if warnings_only:
raise ValueWarning(err.message, option)