add SubMulti
This commit is contained in:
@ -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')
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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:
|
||||
|
Reference in New Issue
Block a user