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> Sun Oct 26 08:50:38 2014 +0200 Emmanuel Garette <egarette@cadoles.com>
* if option is frozen with force_default_on_freeze property, owner * if option is frozen with force_default_on_freeze property, owner
must be 'default' check property when tried to change 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.config import Config
from tiramisu.option import IPOption, NetworkOption, NetmaskOption, IntOption,\ from tiramisu.option import IPOption, NetworkOption, NetmaskOption, IntOption,\
BroadcastOption, SymLinkOption, OptionDescription BroadcastOption, SymLinkOption, OptionDescription
from tiramisu.error import ConfigError, ValueWarning from tiramisu.error import ConfigError, ValueWarning, PropertiesOptionError
import warnings import warnings
@ -27,6 +27,13 @@ def test_consistency_not_exists():
raises(ConfigError, "a.impl_add_consistency('not_exists', b)") 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(): def test_consistency_warnings_only():
a = IntOption('a', '') a = IntOption('a', '')
b = IntOption('b', '') b = IntOption('b', '')
@ -392,6 +399,26 @@ def test_consistency_permissive():
c.a = 1 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): def return_val(*args, **kwargs):
return '192.168.1.1' return '192.168.1.1'

View file

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

View file

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