add SubMulti

This commit is contained in:
2014-04-25 22:57:08 +02:00
parent b6a0f188b2
commit 9112a8c5b0
13 changed files with 909 additions and 86 deletions

View File

@ -1,6 +1,6 @@
from .masterslave import MasterSlaves
from .optiondescription import OptionDescription
from .baseoption import Option, SymLinkOption
from .baseoption import Option, SymLinkOption, submulti
from .option import (ChoiceOption, BoolOption, IntOption, FloatOption,
StrOption, UnicodeOption, IPOption, PortOption,
NetworkOption, NetmaskOption, BroadcastOption,
@ -13,4 +13,4 @@ __all__ = ('MasterSlaves', 'OptionDescription', 'Option', 'SymLinkOption',
'StrOption', 'UnicodeOption', 'IPOption', 'PortOption',
'NetworkOption', 'NetmaskOption', 'BroadcastOption',
'DomainnameOption', 'EmailOption', 'URLOption', 'UsernameOption',
'FilenameOption')
'FilenameOption', 'submulti')

View File

@ -32,6 +32,14 @@ from tiramisu.storage import get_storages_option
StorageBase = get_storages_option('base')
class SubMulti(object):
pass
submulti = SubMulti()
name_regexp = re.compile(r'^\d+')
forbidden_names = ('iter_all', 'iter_group', 'find', 'find_first',
'make_dict', 'unwrap_from_path', 'read_only',
@ -123,7 +131,7 @@ class Base(StorageBase):
"for option {1}: {2}").format(
str(default_multi), name, err))
self._multi = multi
if self._multi:
if self._multi is not False:
if default is None:
default = []
self._default_multi = default_multi
@ -414,7 +422,7 @@ class Option(OnlyOption):
return self._requires
def _launch_consistency(self, func, option, value, context, index,
all_cons_opts, warnings_only):
submulti_index, all_cons_opts, warnings_only):
"""Launch consistency now
:param func: function name, this name should start with _cons_
@ -452,17 +460,24 @@ class Option(OnlyOption):
#append value
if not self.impl_is_multi() 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:
#value is not already set, could be higher index
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
getattr(self, func)(all_cons_opts, all_cons_vals, warnings_only)
def impl_validate(self, value, context=None, validate=True,
force_index=None):
force_index=None, force_submulti_index=None):
"""
:param value: the option's value
:param context: Config's context
@ -470,8 +485,11 @@ class Option(OnlyOption):
:param validate: if true enables ``self._validator`` validation
:type validate: boolean
:param force_index: if multi, value has to be a list
not if force_index is not None
not if force_index is not None
:type force_index: integer
:param force_submulti_index: if submulti, value has to be a list
not if force_submulti_index is not None
:type force_submulti_index: integer
"""
if not validate:
return
@ -496,15 +514,17 @@ class Option(OnlyOption):
callback=self._validator,
callback_params=validator_params)
def do_validation(_value, _index=None):
def do_validation(_value, _index, submulti_index):
if _value is None:
return
# option validation
try:
self._validate(_value)
except ValueError as err:
log.debug('do_validation: value: {0} index: {1}'.format(
_value, _index), exc_info=True)
log.debug('do_validation: value: {0}, index: {1}, '
'submulti_index: {2}'.format(_value, _index,
submulti_index),
exc_info=True)
raise ValueError(_('invalid value for option {0}: {1}'
'').format(self.impl_getname(), err))
error = None
@ -514,7 +534,8 @@ class Option(OnlyOption):
val_validator(_value)
# if not context launch consistency validation
if context is not None:
descr._valid_consistency(self, _value, context, _index)
descr._valid_consistency(self, _value, context, _index,
submulti_index)
self._second_level_validation(_value, self._warnings_only)
except ValueError as error:
log.debug(_('do_validation for {0}: error in value').format(
@ -530,7 +551,8 @@ class Option(OnlyOption):
try:
# if context launch consistency validation
if context is not None:
descr._valid_consistency(self, _value, context, _index)
descr._valid_consistency(self, _value, context, _index,
submulti_index)
except ValueError as error:
log.debug(_('do_validation for {0}: error in consistency').format(
self.impl_getname()), exc_info=True)
@ -553,13 +575,34 @@ class Option(OnlyOption):
if context is not None:
descr = context.cfgimpl_get_description()
if not self._multi or force_index is not None:
do_validation(value, force_index)
if not self.impl_is_multi():
do_validation(value, None, None)
elif force_index is not None:
if self.impl_is_submulti() and force_submulti_index is None:
if not isinstance(value, list):
raise ValueError(_("invalid value {0} for option {1} which"
" must be a list").format(
value, self.impl_getname()))
for idx, val in enumerate(value):
do_validation(val, force_index, idx)
else:
do_validation(value, force_index, force_submulti_index)
else:
if not isinstance(value, list):
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)
raise ValueError(_("invalid value {0} for option {1} which "
"must be a list").format(value,
self.impl_getname()))
for idx, val in enumerate(value):
if self.impl_is_submulti() and force_submulti_index is None:
if not isinstance(val, list):
raise ValueError(_("invalid value {0} for option {1} "
"which must be a list of list"
"").format(value,
self.impl_getname()))
for slave_idx, slave_val in enumerate(val):
do_validation(slave_val, idx, slave_idx)
else:
do_validation(val, idx, force_submulti_index)
def impl_getdefault(self):
"accessing the default value"
@ -615,7 +658,10 @@ class Option(OnlyOption):
# return value
def impl_is_multi(self):
return self._multi
return self._multi is True or self._multi is submulti
def impl_is_submulti(self):
return self._multi is submulti
def impl_add_consistency(self, func, *other_opts, **params):
"""Add consistency means that value will be validate with other_opts
@ -647,10 +693,18 @@ class Option(OnlyOption):
if value is not None:
if self.impl_is_multi():
for idx, val in enumerate(value):
self._launch_consistency(func, self, val, None,
idx, all_cons_opts, warnings_only)
if not self.impl_is_submulti():
self._launch_consistency(func, self, val, None, idx,
None, all_cons_opts,
warnings_only)
else:
for slave_idx, val in enumerate(value):
self._launch_consistency(func, self, val, None,
idx, slave_idx,
all_cons_opts,
warnings_only)
else:
self._launch_consistency(func, self, value, None,
self._launch_consistency(func, self, value, None, None,
None, all_cons_opts, warnings_only)
self._add_consistency(func, all_cons_opts, params)
self.impl_validate(self.impl_getdefault())
@ -808,7 +862,8 @@ def validate_requires_arg(requires, name):
'must be an option in option {0}').format(name))
if option.impl_is_multi():
raise ValueError(_('malformed requirements option {0} '
'must not be a multi').format(name))
'must not be a multi for {1}').format(
option.impl_getname(), name))
if expected is not None:
try:
option._validate(expected)

View File

@ -20,7 +20,7 @@
# the whole pypy projet is under MIT licence
# ____________________________________________________________
from tiramisu.i18n import _
from tiramisu.setting import log
from tiramisu.setting import log, undefined
from tiramisu.error import SlaveError, ConfigError
from .baseoption import SymLinkOption, Option
@ -87,18 +87,21 @@ class MasterSlaves(object):
pass
def getitem(self, values, opt, path, validate, force_permissive,
force_properties, validate_properties):
force_properties, validate_properties, slave_path=undefined,
slave_value=undefined):
if opt == self.master:
return self._getmaster(values, opt, path, validate,
force_permissive, force_properties,
validate_properties)
validate_properties, slave_path,
slave_value)
else:
return self._getslave(values, opt, path, validate,
force_permissive, force_properties,
validate_properties)
def _getmaster(self, values, opt, path, validate, force_permissive,
force_properties, validate_properties):
force_properties, validate_properties, c_slave_path,
c_slave_value):
value = values._get_validated_value(opt, path, validate,
force_permissive,
force_properties,
@ -108,12 +111,15 @@ class MasterSlaves(object):
for slave in self.slaves:
try:
slave_path = values._get_opt_path(slave)
slave_value = values._get_validated_value(slave,
slave_path,
False,
False,
None, False,
None) # not undefined
if c_slave_path == slave_path:
slave_value = c_slave_value
else:
slave_value = values._get_validated_value(slave,
slave_path,
False,
False,
None, False,
None) # not undefined
slavelen = len(slave_value)
self.validate_slave_length(masterlen, slavelen, slave._name)
except ConfigError:
@ -146,10 +152,11 @@ class MasterSlaves(object):
self.validate_slave_length(self.get_length(values), len(value),
opt._name, setitem=True)
def get_length(self, values, validate=True):
def get_length(self, values, validate=True, slave_path=undefined,
slave_value=undefined):
masterp = values._get_opt_path(self.master)
return len(self.getitem(values, self.master, masterp, validate, False,
None, True))
None, True, slave_path, slave_value))
def validate_slave_length(self, masterlen, valuelen, name, setitem=False):
if valuelen > masterlen or (valuelen < masterlen and setitem):
@ -183,11 +190,11 @@ class MasterSlaves(object):
list is greater than master: raise SlaveError
"""
#if slave, had values until master's one
masterlen = self.get_length(values, validate)
path = values._get_opt_path(opt)
masterlen = self.get_length(values, validate, path, value)
valuelen = len(value)
if validate:
self.validate_slave_length(masterlen, valuelen, opt._name)
path = values._get_opt_path(opt)
if valuelen < masterlen:
for num in range(0, masterlen - valuelen):
index = valuelen + num

View File

@ -134,7 +134,8 @@ class IPOption(Option):
callback_params=None, validator=None, validator_params=None,
properties=None, private_only=False, allow_reserved=False,
warnings_only=False):
self._extra = {'_private_only': private_only, '_allow_reserved': allow_reserved}
self._extra = {'_private_only': private_only,
'_allow_reserved': allow_reserved}
super(IPOption, self).__init__(name, doc, default=default,
default_multi=default_multi,
callback=callback,

View File

@ -21,7 +21,7 @@
from copy import copy
from tiramisu.i18n import _
from tiramisu.setting import groups, log
from tiramisu.setting import groups # , log
from .baseoption import BaseOption
from . import MasterSlaves
from tiramisu.error import ConfigError, ConflictError, ValueWarning
@ -162,7 +162,7 @@ class OptionDescription(BaseOption, StorageOptionDescription):
def impl_get_group_type(self):
return self._group_type
def _valid_consistency(self, option, value, context, index):
def _valid_consistency(self, option, value, context, index, submulti_idx):
if self._cache_consistencies is None:
return True
#consistencies is something like [('_cons_not_equal', (opt1, opt2))]
@ -175,6 +175,7 @@ class OptionDescription(BaseOption, StorageOptionDescription):
all_cons_opts[0]._launch_consistency(func, option,
value,
context, index,
submulti_idx,
all_cons_opts,
warnings_only)
except ValueError as err: