separate baseoption and option
This commit is contained in:
parent
3c9a759e2e
commit
635b71d291
|
@ -307,7 +307,7 @@ class SubConfig(object):
|
||||||
context=context)
|
context=context)
|
||||||
if isinstance(child, OptionDescription) or isinstance(child, SynDynOptionDescription):
|
if isinstance(child, OptionDescription) or isinstance(child, SynDynOptionDescription):
|
||||||
raise TypeError(_("can't assign to an OptionDescription")) # pragma: optional cover
|
raise TypeError(_("can't assign to an OptionDescription")) # pragma: optional cover
|
||||||
elif isinstance(child, SymLinkOption) and \
|
elif child._is_symlinkoption() and \
|
||||||
not isinstance(child, DynSymLinkOption): # pragma: no dynoptiondescription cover
|
not isinstance(child, DynSymLinkOption): # pragma: no dynoptiondescription cover
|
||||||
path = context.cfgimpl_get_description().impl_get_path_by_opt(
|
path = context.cfgimpl_get_description().impl_get_path_by_opt(
|
||||||
child._impl_getopt())
|
child._impl_getopt())
|
||||||
|
@ -382,7 +382,7 @@ class SubConfig(object):
|
||||||
setting_properties=_setting_properties,
|
setting_properties=_setting_properties,
|
||||||
self_properties=_self_properties,
|
self_properties=_self_properties,
|
||||||
index=index)
|
index=index)
|
||||||
elif isinstance(option, SymLinkOption): # pragma: no dynoptiondescription cover
|
elif option._is_symlinkoption(): # pragma: no dynoptiondescription cover
|
||||||
path = context.cfgimpl_get_description().impl_get_path_by_opt(
|
path = context.cfgimpl_get_description().impl_get_path_by_opt(
|
||||||
option._impl_getopt())
|
option._impl_getopt())
|
||||||
cfg = context.getattr(path, validate=validate,
|
cfg = context.getattr(path, validate=validate,
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
from .masterslave import MasterSlaves
|
from .masterslave import MasterSlaves
|
||||||
from .optiondescription import OptionDescription, DynOptionDescription, \
|
from .optiondescription import OptionDescription, DynOptionDescription, \
|
||||||
SynDynOptionDescription
|
SynDynOptionDescription
|
||||||
from .baseoption import Option, SymLinkOption, DynSymLinkOption, submulti
|
from .baseoption import SymLinkOption, DynSymLinkOption, submulti
|
||||||
|
from .option import Option
|
||||||
from .choiceoption import ChoiceOption
|
from .choiceoption import ChoiceOption
|
||||||
from .booloption import BoolOption
|
from .booloption import BoolOption
|
||||||
from .intoption import IntOption
|
from .intoption import IntOption
|
||||||
|
|
|
@ -20,14 +20,11 @@
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
import re
|
import re
|
||||||
from types import FunctionType
|
from types import FunctionType
|
||||||
import warnings
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from ..i18n import _
|
from ..i18n import _
|
||||||
from ..setting import log, undefined, debug
|
from ..setting import undefined
|
||||||
from ..autolib import carry_out_calculation
|
from ..error import ConfigError
|
||||||
from ..error import (ConfigError, ValueWarning, PropertiesOptionError,
|
|
||||||
display_list)
|
|
||||||
|
|
||||||
if sys.version_info[0] >= 3: # pragma: no cover
|
if sys.version_info[0] >= 3: # pragma: no cover
|
||||||
from inspect import signature
|
from inspect import signature
|
||||||
|
@ -36,16 +33,12 @@ else:
|
||||||
|
|
||||||
STATIC_TUPLE = tuple()
|
STATIC_TUPLE = tuple()
|
||||||
|
|
||||||
if sys.version_info[0] >= 3: # pragma: no cover
|
|
||||||
xrange = range
|
|
||||||
|
|
||||||
|
|
||||||
submulti = 2
|
submulti = 2
|
||||||
NAME_REGEXP = re.compile(r'^[a-z][a-zA-Z\d_]*$')
|
NAME_REGEXP = re.compile(r'^[a-z][a-zA-Z\d_]*$')
|
||||||
FORBIDDEN_NAMES = frozenset(['iter_all', 'iter_group', 'find', 'find_first',
|
FORBIDDEN_NAMES = frozenset(['iter_all', 'iter_group', 'find', 'find_first',
|
||||||
'make_dict', 'unwrap_from_path', 'read_only',
|
'make_dict', 'unwrap_from_path', 'read_only',
|
||||||
'read_write', 'getowner', 'set_contexts'])
|
'read_write', 'getowner', 'set_contexts'])
|
||||||
ALLOWED_CONST_LIST = ['_cons_not_equal']
|
|
||||||
|
|
||||||
|
|
||||||
def valid_name(name):
|
def valid_name(name):
|
||||||
|
@ -64,9 +57,10 @@ def validate_callback(callback, callback_params, type_, callbackoption):
|
||||||
"""
|
"""
|
||||||
def _validate_option(option):
|
def _validate_option(option):
|
||||||
#validate option
|
#validate option
|
||||||
if isinstance(option, SymLinkOption):
|
if hasattr(option, '_is_symlinkoption'):
|
||||||
|
if option._is_symlinkoption():
|
||||||
cur_opt = option._impl_getopt()
|
cur_opt = option._impl_getopt()
|
||||||
elif isinstance(option, Option):
|
else:
|
||||||
cur_opt = option
|
cur_opt = option
|
||||||
else:
|
else:
|
||||||
raise ValueError(_('{}_params must have an option'
|
raise ValueError(_('{}_params must have an option'
|
||||||
|
@ -205,7 +199,7 @@ class Base(object):
|
||||||
return validator_params
|
return validator_params
|
||||||
|
|
||||||
def _set_has_dependency(self):
|
def _set_has_dependency(self):
|
||||||
if not isinstance(self, SymLinkOption):
|
if not self._is_symlinkoption():
|
||||||
self._has_dependency = True
|
self._has_dependency = True
|
||||||
|
|
||||||
def impl_has_dependency(self):
|
def impl_has_dependency(self):
|
||||||
|
@ -399,633 +393,14 @@ class BaseOption(Base):
|
||||||
opt=self,
|
opt=self,
|
||||||
path=path)
|
path=path)
|
||||||
|
|
||||||
|
def _is_symlinkoption(self):
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
class OnlyOption(BaseOption):
|
class OnlyOption(BaseOption):
|
||||||
__slots__ = tuple()
|
__slots__ = tuple()
|
||||||
|
|
||||||
|
|
||||||
class Option(OnlyOption):
|
|
||||||
"""
|
|
||||||
Abstract base class for configuration option's.
|
|
||||||
|
|
||||||
Reminder: an Option object is **not** a container for the value.
|
|
||||||
"""
|
|
||||||
__slots__ = ('_extra',
|
|
||||||
'_warnings_only',
|
|
||||||
'_allow_empty_list',
|
|
||||||
#multi
|
|
||||||
'_multi',
|
|
||||||
'_unique',
|
|
||||||
#value
|
|
||||||
'_default',
|
|
||||||
'_default_multi',
|
|
||||||
#calcul
|
|
||||||
'_val_call',
|
|
||||||
#
|
|
||||||
'_master_slaves',
|
|
||||||
'_choice_values',
|
|
||||||
'_choice_values_params',
|
|
||||||
)
|
|
||||||
_empty = ''
|
|
||||||
def __init__(self, name, doc, default=None, default_multi=None,
|
|
||||||
requires=None, multi=False, unique=undefined, callback=None,
|
|
||||||
callback_params=None, validator=None, validator_params=None,
|
|
||||||
properties=None, warnings_only=False, extra=None,
|
|
||||||
allow_empty_list=undefined):
|
|
||||||
|
|
||||||
_setattr = object.__setattr__
|
|
||||||
if not multi and default_multi is not None:
|
|
||||||
raise ValueError(_("default_multi is set whereas multi is False"
|
|
||||||
" in option: {0}").format(name))
|
|
||||||
if multi is True:
|
|
||||||
is_multi = True
|
|
||||||
_multi = 0
|
|
||||||
elif multi is False:
|
|
||||||
is_multi = False
|
|
||||||
_multi = 1
|
|
||||||
elif multi is submulti:
|
|
||||||
is_multi = True
|
|
||||||
_multi = submulti
|
|
||||||
else:
|
|
||||||
raise ValueError(_('invalid multi value'))
|
|
||||||
if _multi != 1:
|
|
||||||
_setattr(self, '_multi', _multi)
|
|
||||||
if multi is not False and default is None:
|
|
||||||
default = []
|
|
||||||
if validator is not None:
|
|
||||||
if multi: # and validator_params is None:
|
|
||||||
validator_params = self._build_validator_params(validator, validator_params)
|
|
||||||
|
|
||||||
validate_callback(validator, validator_params, 'validator', self)
|
|
||||||
if validator_params is None:
|
|
||||||
val_call = (validator,)
|
|
||||||
else:
|
|
||||||
val_call = (validator, validator_params)
|
|
||||||
self._val_call = (val_call, None)
|
|
||||||
self._set_has_dependency()
|
|
||||||
if extra is not None:
|
|
||||||
_setattr(self, '_extra', extra)
|
|
||||||
if unique != undefined and not isinstance(unique, bool):
|
|
||||||
raise ValueError(_('unique must be a boolean'))
|
|
||||||
if not is_multi and unique is True:
|
|
||||||
raise ValueError(_('unique must be set only with multi value'))
|
|
||||||
if warnings_only is True:
|
|
||||||
_setattr(self, '_warnings_only', warnings_only)
|
|
||||||
if allow_empty_list is not undefined:
|
|
||||||
_setattr(self, '_allow_empty_list', allow_empty_list)
|
|
||||||
|
|
||||||
super(Option, self).__init__(name, doc, requires=requires,
|
|
||||||
properties=properties, is_multi=is_multi)
|
|
||||||
if is_multi and default_multi is not None:
|
|
||||||
err = self._validate(default_multi)
|
|
||||||
if err:
|
|
||||||
raise ValueError(_("invalid default_multi value {0} "
|
|
||||||
"for option {1}: {2}").format(
|
|
||||||
str(default_multi),
|
|
||||||
self.impl_getname(), str(err)))
|
|
||||||
_setattr(self, '_default_multi', default_multi)
|
|
||||||
if unique is not undefined:
|
|
||||||
_setattr(self, '_unique', unique)
|
|
||||||
err = self.impl_validate(default, is_multi=is_multi)
|
|
||||||
if err:
|
|
||||||
raise err
|
|
||||||
if (is_multi and default != []) or \
|
|
||||||
(not is_multi and default is not None):
|
|
||||||
if is_multi:
|
|
||||||
default = tuple(default)
|
|
||||||
_setattr(self, '_default', default)
|
|
||||||
|
|
||||||
self.impl_set_callback(callback, callback_params, _init=True)
|
|
||||||
|
|
||||||
def impl_is_multi(self):
|
|
||||||
return getattr(self, '_multi', 1) != 1
|
|
||||||
|
|
||||||
def _add_dependencies(self, option):
|
|
||||||
options = set(getattr(self, '_dependencies', tuple()))
|
|
||||||
options.add(option)
|
|
||||||
self._dependencies = tuple(options)
|
|
||||||
|
|
||||||
def _launch_consistency(self, current_opt, func, option, value, context,
|
|
||||||
index, submulti_index, opts, warnings_only,
|
|
||||||
transitive):
|
|
||||||
"""Launch consistency now
|
|
||||||
|
|
||||||
:param func: function name, this name should start with _cons_
|
|
||||||
:type func: `str`
|
|
||||||
:param option: option that value is changing
|
|
||||||
:type option: `tiramisu.option.Option`
|
|
||||||
:param value: new value of this option
|
|
||||||
:param context: Config's context, if None, check default value instead
|
|
||||||
:type context: `tiramisu.config.Config`
|
|
||||||
:param index: only for multi option, consistency should be launch for
|
|
||||||
specified index
|
|
||||||
:type index: `int`
|
|
||||||
:param opts: all options concerne by this consistency
|
|
||||||
:type 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 = []
|
|
||||||
all_cons_opts = []
|
|
||||||
val_consistencies = True
|
|
||||||
for opt in opts:
|
|
||||||
if (isinstance(opt, DynSymLinkOption) and option._dyn == opt._dyn) or \
|
|
||||||
option == opt:
|
|
||||||
# option is current option
|
|
||||||
# we have already value, so use it
|
|
||||||
all_cons_vals.append(value)
|
|
||||||
all_cons_opts.append(opt)
|
|
||||||
else:
|
|
||||||
#if context, calculate value, otherwise get default value
|
|
||||||
path = None
|
|
||||||
is_multi = opt.impl_is_multi() and not opt.impl_is_master_slaves()
|
|
||||||
if context is not undefined:
|
|
||||||
if isinstance(opt, DynSymLinkOption):
|
|
||||||
path = opt.impl_getpath(context)
|
|
||||||
else:
|
|
||||||
path = descr.impl_get_path_by_opt(opt)
|
|
||||||
if is_multi:
|
|
||||||
_index = None
|
|
||||||
else:
|
|
||||||
_index = index
|
|
||||||
opt_value = context.getattr(path, validate=False,
|
|
||||||
index=_index,
|
|
||||||
force_permissive=True,
|
|
||||||
returns_raise=True)
|
|
||||||
if isinstance(opt_value, Exception):
|
|
||||||
if isinstance(opt_value, PropertiesOptionError):
|
|
||||||
if debug: # pragma: no cover
|
|
||||||
log.debug('propertyerror in _launch_consistency: {0}'.format(opt_value))
|
|
||||||
if transitive:
|
|
||||||
opt_value.set_orig_opt(option)
|
|
||||||
return opt_value
|
|
||||||
else:
|
|
||||||
opt_value = None
|
|
||||||
else: # pragma: no cover
|
|
||||||
return opt_value
|
|
||||||
elif index is None:
|
|
||||||
opt_value = opt.impl_getdefault()
|
|
||||||
else:
|
|
||||||
opt_value = opt.impl_getdefault()[index]
|
|
||||||
|
|
||||||
if self.impl_is_multi() and index is None:
|
|
||||||
# only check propertyerror for master/slaves is transitive
|
|
||||||
val_consistencies = False
|
|
||||||
if is_multi and isinstance(opt_value, list):
|
|
||||||
all_cons_vals.extend(opt_value)
|
|
||||||
for len_ in xrange(len(opt_value)):
|
|
||||||
all_cons_opts.append(opt)
|
|
||||||
else:
|
|
||||||
all_cons_vals.append(opt_value)
|
|
||||||
all_cons_opts.append(opt)
|
|
||||||
|
|
||||||
if val_consistencies:
|
|
||||||
err = getattr(self, func)(current_opt, all_cons_opts, all_cons_vals, warnings_only)
|
|
||||||
if err:
|
|
||||||
if warnings_only:
|
|
||||||
msg = _('attention, "{0}" could be an invalid {1} for "{2}", {3}').format(
|
|
||||||
value, self._display_name, current_opt.impl_get_display_name(), err)
|
|
||||||
warnings.warn_explicit(ValueWarning(msg, self),
|
|
||||||
ValueWarning,
|
|
||||||
self.__class__.__name__, 0)
|
|
||||||
else:
|
|
||||||
return err
|
|
||||||
|
|
||||||
def impl_is_unique(self):
|
|
||||||
return getattr(self, '_unique', False)
|
|
||||||
|
|
||||||
def impl_get_validator(self):
|
|
||||||
val = getattr(self, '_val_call', (None,))[0]
|
|
||||||
if val is None:
|
|
||||||
ret_val = (None, {})
|
|
||||||
elif len(val) == 1:
|
|
||||||
ret_val = (val[0], {})
|
|
||||||
else:
|
|
||||||
ret_val = val
|
|
||||||
return ret_val
|
|
||||||
|
|
||||||
def impl_validate(self, value, context=undefined, validate=True,
|
|
||||||
force_index=None, force_submulti_index=None,
|
|
||||||
current_opt=undefined, is_multi=None,
|
|
||||||
display_error=True, display_warnings=True, multi=None,
|
|
||||||
setting_properties=undefined):
|
|
||||||
"""
|
|
||||||
:param value: the option's value
|
|
||||||
:param context: Config's context
|
|
||||||
:type context: :class:`tiramisu.config.Config`
|
|
||||||
: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
|
|
||||||
: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
|
|
||||||
if current_opt is undefined:
|
|
||||||
current_opt = self
|
|
||||||
|
|
||||||
if display_warnings and setting_properties is undefined and context is not undefined:
|
|
||||||
setting_properties = context.cfgimpl_get_settings()._getproperties(read_write=False)
|
|
||||||
display_warnings = display_warnings and (setting_properties is undefined or 'warnings' in setting_properties)
|
|
||||||
|
|
||||||
def _is_not_unique(value):
|
|
||||||
if display_error and self.impl_is_unique() and len(set(value)) != len(value):
|
|
||||||
for idx, val in enumerate(value):
|
|
||||||
if val in value[idx+1:]:
|
|
||||||
return ValueError(_('invalid value "{}", this value is already in "{}"').format(
|
|
||||||
val, self.impl_get_display_name()))
|
|
||||||
|
|
||||||
def calculation_validator(val, _index):
|
|
||||||
validator, validator_params = self.impl_get_validator()
|
|
||||||
if validator is not None:
|
|
||||||
if validator_params != {}:
|
|
||||||
validator_params_ = {}
|
|
||||||
for val_param, values in validator_params.items():
|
|
||||||
validator_params_[val_param] = values
|
|
||||||
#inject value in calculation
|
|
||||||
if '' in validator_params_:
|
|
||||||
lst = list(validator_params_[''])
|
|
||||||
lst.insert(0, val)
|
|
||||||
validator_params_[''] = tuple(lst)
|
|
||||||
else:
|
|
||||||
validator_params_[''] = (val,)
|
|
||||||
else:
|
|
||||||
validator_params_ = {'': (val,)}
|
|
||||||
# Raise ValueError if not valid
|
|
||||||
value = carry_out_calculation(current_opt, context=context,
|
|
||||||
callback=validator,
|
|
||||||
callback_params=validator_params_,
|
|
||||||
index=_index,
|
|
||||||
is_validator=True)
|
|
||||||
if isinstance(value, Exception):
|
|
||||||
return value
|
|
||||||
|
|
||||||
def do_validation(_value, _index, submulti_index):
|
|
||||||
if _value is None:
|
|
||||||
error = warning = None
|
|
||||||
else:
|
|
||||||
if display_error:
|
|
||||||
# option validation
|
|
||||||
err = self._validate(_value, context, current_opt)
|
|
||||||
if err:
|
|
||||||
if debug: # pragma: no cover
|
|
||||||
log.debug('do_validation: value: {0}, index: {1}, '
|
|
||||||
'submulti_index: {2}'.format(_value, _index,
|
|
||||||
submulti_index),
|
|
||||||
exc_info=True)
|
|
||||||
err_msg = '{0}'.format(err)
|
|
||||||
if err_msg:
|
|
||||||
msg = _('"{0}" is an invalid {1} for "{2}", {3}'
|
|
||||||
'').format(_value, self._display_name,
|
|
||||||
self.impl_get_display_name(), err_msg)
|
|
||||||
else:
|
|
||||||
msg = _('"{0}" is an invalid {1} for "{2}"'
|
|
||||||
'').format(_value, self._display_name,
|
|
||||||
self.impl_get_display_name())
|
|
||||||
return ValueError(msg)
|
|
||||||
error = None
|
|
||||||
is_warnings_only = getattr(self, '_warnings_only', False)
|
|
||||||
if ((display_error and not is_warnings_only) or
|
|
||||||
(display_warnings and is_warnings_only)):
|
|
||||||
error = calculation_validator(_value, _index)
|
|
||||||
if not error:
|
|
||||||
error = self._second_level_validation(_value, is_warnings_only)
|
|
||||||
if error:
|
|
||||||
if debug: # pragma: no cover
|
|
||||||
log.debug(_('do_validation for {0}: error in value').format(
|
|
||||||
self.impl_getname()), exc_info=True)
|
|
||||||
if is_warnings_only:
|
|
||||||
msg = _('attention, "{0}" could be an invalid {1} for "{2}", {3}').format(
|
|
||||||
_value, self._display_name, self.impl_get_display_name(), error)
|
|
||||||
warnings.warn_explicit(ValueWarning(msg, self),
|
|
||||||
ValueWarning,
|
|
||||||
self.__class__.__name__, 0)
|
|
||||||
error = None
|
|
||||||
if error is None:
|
|
||||||
# if context launch consistency validation
|
|
||||||
#if context is not undefined:
|
|
||||||
ret = self._valid_consistency(current_opt, _value, context,
|
|
||||||
_index, submulti_index, display_warnings,
|
|
||||||
display_error)
|
|
||||||
if isinstance(ret, ValueError):
|
|
||||||
error = ret
|
|
||||||
elif ret:
|
|
||||||
return ret
|
|
||||||
if error:
|
|
||||||
err_msg = '{0}'.format(error)
|
|
||||||
if err_msg:
|
|
||||||
msg = _('"{0}" is an invalid {1} for "{2}", {3}'
|
|
||||||
'').format(_value, self._display_name,
|
|
||||||
self.impl_get_display_name(), err_msg)
|
|
||||||
else:
|
|
||||||
msg = _('"{0}" is an invalid {1} for "{2}"'
|
|
||||||
'').format(_value, self._display_name,
|
|
||||||
self.impl_get_display_name())
|
|
||||||
return ValueError(msg)
|
|
||||||
|
|
||||||
if is_multi is None:
|
|
||||||
is_multi = self.impl_is_multi()
|
|
||||||
|
|
||||||
if not is_multi:
|
|
||||||
return do_validation(value, None, None)
|
|
||||||
elif force_index is not None:
|
|
||||||
if self.impl_is_submulti() and force_submulti_index is None:
|
|
||||||
err = _is_not_unique(value)
|
|
||||||
if err:
|
|
||||||
return err
|
|
||||||
if not isinstance(value, list):
|
|
||||||
return ValueError(_('invalid value "{0}" for "{1}" which'
|
|
||||||
' must be a list').format(
|
|
||||||
value, self.impl_get_display_name()))
|
|
||||||
for idx, val in enumerate(value):
|
|
||||||
if isinstance(val, list): # pragma: no cover
|
|
||||||
return ValueError(_('invalid value "{}" for "{}" '
|
|
||||||
'which must not be a list').format(val,
|
|
||||||
self.impl_get_display_name()))
|
|
||||||
err = do_validation(val, force_index, idx)
|
|
||||||
if err:
|
|
||||||
return err
|
|
||||||
else:
|
|
||||||
if multi is not None and self.impl_is_unique() and value in multi:
|
|
||||||
if not self.impl_is_submulti() and len(multi) - 1 >= force_index:
|
|
||||||
lst = list(multi)
|
|
||||||
lst.pop(force_index)
|
|
||||||
else:
|
|
||||||
lst = multi
|
|
||||||
if value in lst:
|
|
||||||
return ValueError(_('invalid value "{}", this value is already'
|
|
||||||
' in "{}"').format(value,
|
|
||||||
self.impl_get_display_name()))
|
|
||||||
return do_validation(value, force_index, force_submulti_index)
|
|
||||||
elif not isinstance(value, list):
|
|
||||||
return ValueError(_('invalid value "{0}" for "{1}" which '
|
|
||||||
'must be a list').format(value,
|
|
||||||
self.impl_getname()))
|
|
||||||
elif self.impl_is_submulti() and force_submulti_index is None:
|
|
||||||
for idx, val in enumerate(value):
|
|
||||||
err = _is_not_unique(val)
|
|
||||||
if err:
|
|
||||||
return err
|
|
||||||
if not isinstance(val, list):
|
|
||||||
return ValueError(_('invalid value "{0}" for "{1}" '
|
|
||||||
'which must be a list of list'
|
|
||||||
'').format(val,
|
|
||||||
self.impl_getname()))
|
|
||||||
for slave_idx, slave_val in enumerate(val):
|
|
||||||
err = do_validation(slave_val, idx, slave_idx)
|
|
||||||
if err:
|
|
||||||
return err
|
|
||||||
else:
|
|
||||||
err = _is_not_unique(value)
|
|
||||||
if err:
|
|
||||||
return err
|
|
||||||
for idx, val in enumerate(value):
|
|
||||||
err = do_validation(val, idx, force_submulti_index)
|
|
||||||
if err:
|
|
||||||
return err
|
|
||||||
return self._valid_consistency(current_opt, None, context,
|
|
||||||
None, None, display_warnings, display_error)
|
|
||||||
|
|
||||||
def impl_is_dynsymlinkoption(self):
|
|
||||||
return False
|
|
||||||
|
|
||||||
def impl_is_master_slaves(self, type_='both'):
|
|
||||||
"""FIXME
|
|
||||||
"""
|
|
||||||
master_slaves = self.impl_get_master_slaves()
|
|
||||||
if master_slaves is not None:
|
|
||||||
if type_ in ('both', 'master') and \
|
|
||||||
master_slaves.is_master(self):
|
|
||||||
return True
|
|
||||||
if type_ in ('both', 'slave') and \
|
|
||||||
not master_slaves.is_master(self):
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
def impl_get_master_slaves(self):
|
|
||||||
return getattr(self, '_master_slaves', None)
|
|
||||||
|
|
||||||
def impl_getdoc(self):
|
|
||||||
"accesses the Option's doc"
|
|
||||||
return self.impl_get_information('doc')
|
|
||||||
|
|
||||||
def _valid_consistencies(self, other_opts, init=True, func=None):
|
|
||||||
if self._is_subdyn():
|
|
||||||
dynod = self._subdyn
|
|
||||||
else:
|
|
||||||
dynod = None
|
|
||||||
if self.impl_is_submulti():
|
|
||||||
raise ConfigError(_('cannot add consistency with submulti option'))
|
|
||||||
is_multi = self.impl_is_multi()
|
|
||||||
for opt in other_opts:
|
|
||||||
if opt.impl_is_submulti():
|
|
||||||
raise ConfigError(_('cannot add consistency with submulti option'))
|
|
||||||
if not isinstance(opt, Option):
|
|
||||||
raise ConfigError(_('consistency must be set with an option'))
|
|
||||||
if opt._is_subdyn():
|
|
||||||
if dynod is None:
|
|
||||||
raise ConfigError(_('almost one option in consistency is '
|
|
||||||
'in a dynoptiondescription but not all'))
|
|
||||||
if dynod != opt._subdyn:
|
|
||||||
raise ConfigError(_('option in consistency must be in same'
|
|
||||||
' dynoptiondescription'))
|
|
||||||
dynod = opt._subdyn
|
|
||||||
elif dynod is not None:
|
|
||||||
raise ConfigError(_('almost one option in consistency is in a '
|
|
||||||
'dynoptiondescription but not all'))
|
|
||||||
if self is opt:
|
|
||||||
raise ConfigError(_('cannot add consistency with itself'))
|
|
||||||
if is_multi != opt.impl_is_multi():
|
|
||||||
raise ConfigError(_('every options in consistency must be '
|
|
||||||
'multi or none'))
|
|
||||||
if init:
|
|
||||||
# FIXME
|
|
||||||
if func != 'not_equal':
|
|
||||||
opt._set_has_dependency()
|
|
||||||
|
|
||||||
def impl_add_consistency(self, func, *other_opts, **params):
|
|
||||||
"""Add consistency means that value will be validate with other_opts
|
|
||||||
option's values.
|
|
||||||
|
|
||||||
:param func: function's name
|
|
||||||
:type func: `str`
|
|
||||||
:param other_opts: options used to validate value
|
|
||||||
:type other_opts: `list` of `tiramisu.option.Option`
|
|
||||||
:param params: extra params (warnings_only and transitive are allowed)
|
|
||||||
"""
|
|
||||||
if self.impl_is_readonly():
|
|
||||||
raise AttributeError(_("'{0}' ({1}) cannot add consistency, option is"
|
|
||||||
" read-only").format(
|
|
||||||
self.__class__.__name__,
|
|
||||||
self.impl_getname()))
|
|
||||||
self._valid_consistencies(other_opts, func=func)
|
|
||||||
func = '_cons_{0}'.format(func)
|
|
||||||
if func not in dir(self):
|
|
||||||
raise ConfigError(_('consistency {0} not available for this option').format(func))
|
|
||||||
all_cons_opts = tuple([self] + list(other_opts))
|
|
||||||
unknown_params = set(params.keys()) - set(['warnings_only', 'transitive'])
|
|
||||||
if unknown_params != set():
|
|
||||||
raise ValueError(_('unknow parameter {0} in consistency').format(unknown_params))
|
|
||||||
self._add_consistency(func, all_cons_opts, params)
|
|
||||||
#validate default value when add consistency
|
|
||||||
err = self.impl_validate(self.impl_getdefault())
|
|
||||||
if err:
|
|
||||||
self._del_consistency()
|
|
||||||
raise err
|
|
||||||
if func in ALLOWED_CONST_LIST:
|
|
||||||
for opt in all_cons_opts:
|
|
||||||
if getattr(opt, '_unique', undefined) == undefined:
|
|
||||||
opt._unique = True
|
|
||||||
if func != '_cons_not_equal':
|
|
||||||
#consistency could generate warnings or errors
|
|
||||||
self._set_has_dependency()
|
|
||||||
|
|
||||||
def _valid_consistency(self, option, value, context, index, submulti_idx,
|
|
||||||
display_warnings, display_error):
|
|
||||||
if context is not undefined:
|
|
||||||
descr = context.cfgimpl_get_description()
|
|
||||||
if descr._cache_consistencies is None:
|
|
||||||
return
|
|
||||||
#consistencies is something like [('_cons_not_equal', (opt1, opt2))]
|
|
||||||
if isinstance(option, DynSymLinkOption):
|
|
||||||
consistencies = descr._cache_consistencies.get(option._impl_getopt())
|
|
||||||
else:
|
|
||||||
consistencies = descr._cache_consistencies.get(option)
|
|
||||||
else:
|
|
||||||
consistencies = option._get_consistencies()
|
|
||||||
if consistencies is not None:
|
|
||||||
for func, all_cons_opts, params in consistencies:
|
|
||||||
warnings_only = params.get('warnings_only', False)
|
|
||||||
if (warnings_only and display_warnings) or (not warnings_only and display_error):
|
|
||||||
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])
|
|
||||||
namelen = len(option._impl_getopt().impl_getname())
|
|
||||||
suffix = option.impl_getname()[namelen:]
|
|
||||||
opts = []
|
|
||||||
for opt in all_cons_opts:
|
|
||||||
name = opt.impl_getname() + suffix
|
|
||||||
path = subpath + '.' + name
|
|
||||||
opts.append(opt._impl_to_dyn(name, path))
|
|
||||||
else:
|
|
||||||
opts = all_cons_opts
|
|
||||||
err = opts[0]._launch_consistency(self, func, option, value,
|
|
||||||
context, index, submulti_idx,
|
|
||||||
opts, warnings_only,
|
|
||||||
transitive)
|
|
||||||
if err:
|
|
||||||
return err
|
|
||||||
|
|
||||||
def _cons_not_equal(self, current_opt, opts, vals, warnings_only):
|
|
||||||
equal = set()
|
|
||||||
is_current = False
|
|
||||||
for idx_inf, val_inf in enumerate(vals):
|
|
||||||
for idx_sup, val_sup in enumerate(vals[idx_inf + 1:]):
|
|
||||||
if val_inf == val_sup is not None:
|
|
||||||
for opt_ in [opts[idx_inf], opts[idx_inf + idx_sup + 1]]:
|
|
||||||
if opt_ == current_opt:
|
|
||||||
is_current = True
|
|
||||||
else:
|
|
||||||
equal.add(opt_)
|
|
||||||
if equal:
|
|
||||||
if debug: # pragma: no cover
|
|
||||||
log.debug(_('_cons_not_equal: {} are not different').format(display_list(list(equal))))
|
|
||||||
if is_current:
|
|
||||||
if warnings_only:
|
|
||||||
msg = _('should be different from the value of {}')
|
|
||||||
else:
|
|
||||||
msg = _('must be different from the value of {}')
|
|
||||||
else:
|
|
||||||
if warnings_only:
|
|
||||||
msg = _('value for {} should be different')
|
|
||||||
else:
|
|
||||||
msg = _('value for {} must be different')
|
|
||||||
equal_name = []
|
|
||||||
for opt in equal:
|
|
||||||
equal_name.append(opt.impl_get_display_name())
|
|
||||||
return ValueError(msg.format(display_list(list(equal_name))))
|
|
||||||
|
|
||||||
def _second_level_validation(self, value, warnings_only):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def _impl_to_dyn(self, name, path):
|
|
||||||
return DynSymLinkOption(name, self, dyn=path)
|
|
||||||
|
|
||||||
def impl_getdefault_multi(self):
|
|
||||||
"accessing the default value for a multi"
|
|
||||||
return getattr(self, '_default_multi', None)
|
|
||||||
|
|
||||||
def _validate_callback(self, callback, callback_params):
|
|
||||||
"""callback_params:
|
|
||||||
* None
|
|
||||||
* {'': ((option, permissive),), 'ip': ((None,), (option, permissive))
|
|
||||||
"""
|
|
||||||
if callback is None:
|
|
||||||
return
|
|
||||||
default_multi = self.impl_getdefault_multi()
|
|
||||||
is_multi = self.impl_is_multi()
|
|
||||||
default = self.impl_getdefault()
|
|
||||||
if (not is_multi and (default is not None or default_multi is not None)) or \
|
|
||||||
(is_multi and (default != [] or default_multi is not None)):
|
|
||||||
raise ValueError(_("default value not allowed if option: {0} "
|
|
||||||
"is calculated").format(self.impl_getname()))
|
|
||||||
|
|
||||||
def impl_getdefault(self):
|
|
||||||
"accessing the default value"
|
|
||||||
is_multi = self.impl_is_multi()
|
|
||||||
default = getattr(self, '_default', undefined)
|
|
||||||
if default is undefined:
|
|
||||||
if is_multi:
|
|
||||||
default = []
|
|
||||||
else:
|
|
||||||
default = None
|
|
||||||
else:
|
|
||||||
if is_multi:
|
|
||||||
default = list(default)
|
|
||||||
return default
|
|
||||||
|
|
||||||
def _get_extra(self, key):
|
|
||||||
extra = self._extra
|
|
||||||
if isinstance(extra, tuple):
|
|
||||||
return extra[1][extra[0].index(key)]
|
|
||||||
else:
|
|
||||||
return extra[key]
|
|
||||||
|
|
||||||
def impl_is_submulti(self):
|
|
||||||
return getattr(self, '_multi', 1) == 2
|
|
||||||
|
|
||||||
def impl_allow_empty_list(self):
|
|
||||||
return getattr(self, '_allow_empty_list', undefined)
|
|
||||||
|
|
||||||
#____________________________________________________________
|
|
||||||
# consistency
|
|
||||||
def _add_consistency(self, func, all_cons_opts, params):
|
|
||||||
cons = (func, all_cons_opts, params)
|
|
||||||
consistencies = getattr(self, '_consistencies', None)
|
|
||||||
if consistencies is None:
|
|
||||||
self._consistencies = [cons]
|
|
||||||
else:
|
|
||||||
consistencies.append(cons)
|
|
||||||
|
|
||||||
def _del_consistency(self):
|
|
||||||
self._consistencies.pop(-1)
|
|
||||||
|
|
||||||
def _get_consistencies(self):
|
|
||||||
return getattr(self, '_consistencies', STATIC_TUPLE)
|
|
||||||
|
|
||||||
def _has_consistencies(self):
|
|
||||||
return hasattr(self, '_consistencies')
|
|
||||||
|
|
||||||
|
|
||||||
def validate_requires_arg(new_option, multi, requires, name):
|
def validate_requires_arg(new_option, multi, requires, name):
|
||||||
"""check malformed requirements
|
"""check malformed requirements
|
||||||
and tranform dict to internal tuple
|
and tranform dict to internal tuple
|
||||||
|
@ -1045,7 +420,7 @@ def validate_requires_arg(new_option, multi, requires, name):
|
||||||
|
|
||||||
def get_option(require):
|
def get_option(require):
|
||||||
option = require['option']
|
option = require['option']
|
||||||
if not isinstance(option, Option):
|
if not hasattr(option, '_is_symlinkoption'):
|
||||||
raise ValueError(_('malformed requirements '
|
raise ValueError(_('malformed requirements '
|
||||||
'must be an option in option {0}').format(name))
|
'must be an option in option {0}').format(name))
|
||||||
if not multi and option.impl_is_multi():
|
if not multi and option.impl_is_multi():
|
||||||
|
@ -1178,7 +553,8 @@ def validate_requires_arg(new_option, multi, requires, name):
|
||||||
class SymLinkOption(OnlyOption):
|
class SymLinkOption(OnlyOption):
|
||||||
|
|
||||||
def __init__(self, name, opt):
|
def __init__(self, name, opt):
|
||||||
if not isinstance(opt, Option):
|
if not isinstance(opt, OnlyOption) or \
|
||||||
|
opt._is_symlinkoption():
|
||||||
raise ValueError(_('malformed symlinkoption '
|
raise ValueError(_('malformed symlinkoption '
|
||||||
'must be an option '
|
'must be an option '
|
||||||
'for symlink {0}').format(name))
|
'for symlink {0}').format(name))
|
||||||
|
@ -1187,6 +563,9 @@ class SymLinkOption(OnlyOption):
|
||||||
_setattr(self, '_opt', opt)
|
_setattr(self, '_opt', opt)
|
||||||
opt._set_has_dependency()
|
opt._set_has_dependency()
|
||||||
|
|
||||||
|
def _is_symlinkoption(self):
|
||||||
|
return True
|
||||||
|
|
||||||
def __getattr__(self, name, context=undefined):
|
def __getattr__(self, name, context=undefined):
|
||||||
return getattr(self._impl_getopt(), name)
|
return getattr(self._impl_getopt(), name)
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
|
|
||||||
from ..setting import undefined
|
from ..setting import undefined
|
||||||
from ..i18n import _
|
from ..i18n import _
|
||||||
from .baseoption import Option
|
from .option import Option
|
||||||
|
|
||||||
|
|
||||||
class BoolOption(Option):
|
class BoolOption(Option):
|
||||||
|
|
|
@ -23,7 +23,7 @@ from IPy import IP
|
||||||
from ..error import ConfigError
|
from ..error import ConfigError
|
||||||
from ..setting import undefined
|
from ..setting import undefined
|
||||||
from ..i18n import _
|
from ..i18n import _
|
||||||
from .baseoption import Option
|
from .option import Option
|
||||||
|
|
||||||
|
|
||||||
class BroadcastOption(Option):
|
class BroadcastOption(Option):
|
||||||
|
|
|
@ -22,9 +22,10 @@ from types import FunctionType
|
||||||
|
|
||||||
from ..setting import undefined
|
from ..setting import undefined
|
||||||
from ..i18n import _
|
from ..i18n import _
|
||||||
from .baseoption import Option, validate_callback, display_list
|
from .baseoption import validate_callback
|
||||||
|
from .option import Option
|
||||||
from ..autolib import carry_out_calculation
|
from ..autolib import carry_out_calculation
|
||||||
from ..error import ConfigError
|
from ..error import ConfigError, display_list
|
||||||
|
|
||||||
|
|
||||||
class ChoiceOption(Option):
|
class ChoiceOption(Option):
|
||||||
|
|
|
@ -18,12 +18,11 @@
|
||||||
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
|
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
|
||||||
# the whole pypy projet is under MIT licence
|
# the whole pypy projet is under MIT licence
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
import re
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from ..setting import undefined
|
from ..setting import undefined
|
||||||
from ..i18n import _
|
from ..i18n import _
|
||||||
from .baseoption import Option
|
from .option import Option
|
||||||
|
|
||||||
|
|
||||||
class DateOption(Option):
|
class DateOption(Option):
|
||||||
|
|
|
@ -23,7 +23,7 @@ from IPy import IP
|
||||||
|
|
||||||
from ..setting import undefined
|
from ..setting import undefined
|
||||||
from ..i18n import _
|
from ..i18n import _
|
||||||
from .baseoption import Option
|
from .option import Option
|
||||||
|
|
||||||
|
|
||||||
class DomainnameOption(Option):
|
class DomainnameOption(Option):
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
|
|
||||||
from ..setting import undefined
|
from ..setting import undefined
|
||||||
from ..i18n import _
|
from ..i18n import _
|
||||||
from .baseoption import Option
|
from .option import Option
|
||||||
|
|
||||||
|
|
||||||
class FloatOption(Option):
|
class FloatOption(Option):
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
|
|
||||||
from ..setting import undefined
|
from ..setting import undefined
|
||||||
from ..i18n import _
|
from ..i18n import _
|
||||||
from .baseoption import Option
|
from .option import Option
|
||||||
|
|
||||||
|
|
||||||
class IntOption(Option):
|
class IntOption(Option):
|
||||||
|
|
|
@ -23,7 +23,7 @@ from IPy import IP
|
||||||
from ..error import ConfigError
|
from ..error import ConfigError
|
||||||
from ..setting import undefined
|
from ..setting import undefined
|
||||||
from ..i18n import _
|
from ..i18n import _
|
||||||
from .baseoption import Option
|
from .option import Option
|
||||||
|
|
||||||
|
|
||||||
class IPOption(Option):
|
class IPOption(Option):
|
||||||
|
|
|
@ -23,7 +23,7 @@ from IPy import IP
|
||||||
from ..error import ConfigError
|
from ..error import ConfigError
|
||||||
from ..setting import undefined
|
from ..setting import undefined
|
||||||
from ..i18n import _
|
from ..i18n import _
|
||||||
from .baseoption import Option
|
from .option import Option
|
||||||
|
|
||||||
|
|
||||||
class NetmaskOption(Option):
|
class NetmaskOption(Option):
|
||||||
|
|
|
@ -22,7 +22,7 @@ from IPy import IP
|
||||||
|
|
||||||
from ..setting import undefined
|
from ..setting import undefined
|
||||||
from ..i18n import _
|
from ..i18n import _
|
||||||
from .baseoption import Option
|
from .option import Option
|
||||||
|
|
||||||
|
|
||||||
class NetworkOption(Option):
|
class NetworkOption(Option):
|
||||||
|
|
|
@ -19,9 +19,642 @@
|
||||||
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
|
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
|
||||||
# the whole pypy projet is under MIT licence
|
# the whole pypy projet is under MIT licence
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
from ..setting import undefined
|
import warnings
|
||||||
|
import sys
|
||||||
|
|
||||||
from .baseoption import Option
|
from .baseoption import OnlyOption, submulti, DynSymLinkOption, validate_callback, STATIC_TUPLE
|
||||||
|
from ..i18n import _
|
||||||
|
from ..setting import log, undefined, debug
|
||||||
|
from ..autolib import carry_out_calculation
|
||||||
|
from ..error import (ConfigError, ValueWarning, PropertiesOptionError,
|
||||||
|
display_list)
|
||||||
|
|
||||||
|
ALLOWED_CONST_LIST = ['_cons_not_equal']
|
||||||
|
|
||||||
|
if sys.version_info[0] >= 3: # pragma: no cover
|
||||||
|
xrange = range
|
||||||
|
|
||||||
|
|
||||||
|
class Option(OnlyOption):
|
||||||
|
"""
|
||||||
|
Abstract base class for configuration option's.
|
||||||
|
|
||||||
|
Reminder: an Option object is **not** a container for the value.
|
||||||
|
"""
|
||||||
|
__slots__ = ('_extra',
|
||||||
|
'_warnings_only',
|
||||||
|
'_allow_empty_list',
|
||||||
|
#multi
|
||||||
|
'_multi',
|
||||||
|
'_unique',
|
||||||
|
#value
|
||||||
|
'_default',
|
||||||
|
'_default_multi',
|
||||||
|
#calcul
|
||||||
|
'_val_call',
|
||||||
|
#
|
||||||
|
'_master_slaves',
|
||||||
|
'_choice_values',
|
||||||
|
'_choice_values_params',
|
||||||
|
)
|
||||||
|
_empty = ''
|
||||||
|
def __init__(self, name, doc, default=None, default_multi=None,
|
||||||
|
requires=None, multi=False, unique=undefined, callback=None,
|
||||||
|
callback_params=None, validator=None, validator_params=None,
|
||||||
|
properties=None, warnings_only=False, extra=None,
|
||||||
|
allow_empty_list=undefined):
|
||||||
|
|
||||||
|
_setattr = object.__setattr__
|
||||||
|
if not multi and default_multi is not None:
|
||||||
|
raise ValueError(_("default_multi is set whereas multi is False"
|
||||||
|
" in option: {0}").format(name))
|
||||||
|
if multi is True:
|
||||||
|
is_multi = True
|
||||||
|
_multi = 0
|
||||||
|
elif multi is False:
|
||||||
|
is_multi = False
|
||||||
|
_multi = 1
|
||||||
|
elif multi is submulti:
|
||||||
|
is_multi = True
|
||||||
|
_multi = submulti
|
||||||
|
else:
|
||||||
|
raise ValueError(_('invalid multi value'))
|
||||||
|
if _multi != 1:
|
||||||
|
_setattr(self, '_multi', _multi)
|
||||||
|
if multi is not False and default is None:
|
||||||
|
default = []
|
||||||
|
if validator is not None:
|
||||||
|
if multi: # and validator_params is None:
|
||||||
|
validator_params = self._build_validator_params(validator, validator_params)
|
||||||
|
|
||||||
|
validate_callback(validator, validator_params, 'validator', self)
|
||||||
|
if validator_params is None:
|
||||||
|
val_call = (validator,)
|
||||||
|
else:
|
||||||
|
val_call = (validator, validator_params)
|
||||||
|
self._val_call = (val_call, None)
|
||||||
|
self._set_has_dependency()
|
||||||
|
if extra is not None:
|
||||||
|
_setattr(self, '_extra', extra)
|
||||||
|
if unique != undefined and not isinstance(unique, bool):
|
||||||
|
raise ValueError(_('unique must be a boolean'))
|
||||||
|
if not is_multi and unique is True:
|
||||||
|
raise ValueError(_('unique must be set only with multi value'))
|
||||||
|
if warnings_only is True:
|
||||||
|
_setattr(self, '_warnings_only', warnings_only)
|
||||||
|
if allow_empty_list is not undefined:
|
||||||
|
_setattr(self, '_allow_empty_list', allow_empty_list)
|
||||||
|
|
||||||
|
super(Option, self).__init__(name, doc, requires=requires,
|
||||||
|
properties=properties, is_multi=is_multi)
|
||||||
|
if is_multi and default_multi is not None:
|
||||||
|
err = self._validate(default_multi)
|
||||||
|
if err:
|
||||||
|
raise ValueError(_("invalid default_multi value {0} "
|
||||||
|
"for option {1}: {2}").format(
|
||||||
|
str(default_multi),
|
||||||
|
self.impl_getname(), str(err)))
|
||||||
|
_setattr(self, '_default_multi', default_multi)
|
||||||
|
if unique is not undefined:
|
||||||
|
_setattr(self, '_unique', unique)
|
||||||
|
err = self.impl_validate(default, is_multi=is_multi)
|
||||||
|
if err:
|
||||||
|
raise err
|
||||||
|
if (is_multi and default != []) or \
|
||||||
|
(not is_multi and default is not None):
|
||||||
|
if is_multi:
|
||||||
|
default = tuple(default)
|
||||||
|
_setattr(self, '_default', default)
|
||||||
|
|
||||||
|
self.impl_set_callback(callback, callback_params, _init=True)
|
||||||
|
|
||||||
|
def impl_is_multi(self):
|
||||||
|
return getattr(self, '_multi', 1) != 1
|
||||||
|
|
||||||
|
def _add_dependencies(self, option):
|
||||||
|
options = set(getattr(self, '_dependencies', tuple()))
|
||||||
|
options.add(option)
|
||||||
|
self._dependencies = tuple(options)
|
||||||
|
|
||||||
|
def _launch_consistency(self, current_opt, func, option, value, context,
|
||||||
|
index, submulti_index, opts, warnings_only,
|
||||||
|
transitive):
|
||||||
|
"""Launch consistency now
|
||||||
|
|
||||||
|
:param func: function name, this name should start with _cons_
|
||||||
|
:type func: `str`
|
||||||
|
:param option: option that value is changing
|
||||||
|
:type option: `tiramisu.option.Option`
|
||||||
|
:param value: new value of this option
|
||||||
|
:param context: Config's context, if None, check default value instead
|
||||||
|
:type context: `tiramisu.config.Config`
|
||||||
|
:param index: only for multi option, consistency should be launch for
|
||||||
|
specified index
|
||||||
|
:type index: `int`
|
||||||
|
:param opts: all options concerne by this consistency
|
||||||
|
:type 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 = []
|
||||||
|
all_cons_opts = []
|
||||||
|
val_consistencies = True
|
||||||
|
for opt in opts:
|
||||||
|
if (isinstance(opt, DynSymLinkOption) and option._dyn == opt._dyn) or \
|
||||||
|
option == opt:
|
||||||
|
# option is current option
|
||||||
|
# we have already value, so use it
|
||||||
|
all_cons_vals.append(value)
|
||||||
|
all_cons_opts.append(opt)
|
||||||
|
else:
|
||||||
|
#if context, calculate value, otherwise get default value
|
||||||
|
path = None
|
||||||
|
is_multi = opt.impl_is_multi() and not opt.impl_is_master_slaves()
|
||||||
|
if context is not undefined:
|
||||||
|
if isinstance(opt, DynSymLinkOption):
|
||||||
|
path = opt.impl_getpath(context)
|
||||||
|
else:
|
||||||
|
path = descr.impl_get_path_by_opt(opt)
|
||||||
|
if is_multi:
|
||||||
|
_index = None
|
||||||
|
else:
|
||||||
|
_index = index
|
||||||
|
opt_value = context.getattr(path, validate=False,
|
||||||
|
index=_index,
|
||||||
|
force_permissive=True,
|
||||||
|
returns_raise=True)
|
||||||
|
if isinstance(opt_value, Exception):
|
||||||
|
if isinstance(opt_value, PropertiesOptionError):
|
||||||
|
if debug: # pragma: no cover
|
||||||
|
log.debug('propertyerror in _launch_consistency: {0}'.format(opt_value))
|
||||||
|
if transitive:
|
||||||
|
opt_value.set_orig_opt(option)
|
||||||
|
return opt_value
|
||||||
|
else:
|
||||||
|
opt_value = None
|
||||||
|
else: # pragma: no cover
|
||||||
|
return opt_value
|
||||||
|
elif index is None:
|
||||||
|
opt_value = opt.impl_getdefault()
|
||||||
|
else:
|
||||||
|
opt_value = opt.impl_getdefault()[index]
|
||||||
|
|
||||||
|
if self.impl_is_multi() and index is None:
|
||||||
|
# only check propertyerror for master/slaves is transitive
|
||||||
|
val_consistencies = False
|
||||||
|
if is_multi and isinstance(opt_value, list):
|
||||||
|
all_cons_vals.extend(opt_value)
|
||||||
|
for len_ in xrange(len(opt_value)):
|
||||||
|
all_cons_opts.append(opt)
|
||||||
|
else:
|
||||||
|
all_cons_vals.append(opt_value)
|
||||||
|
all_cons_opts.append(opt)
|
||||||
|
|
||||||
|
if val_consistencies:
|
||||||
|
err = getattr(self, func)(current_opt, all_cons_opts, all_cons_vals, warnings_only)
|
||||||
|
if err:
|
||||||
|
if warnings_only:
|
||||||
|
msg = _('attention, "{0}" could be an invalid {1} for "{2}", {3}').format(
|
||||||
|
value, self._display_name, current_opt.impl_get_display_name(), err)
|
||||||
|
warnings.warn_explicit(ValueWarning(msg, self),
|
||||||
|
ValueWarning,
|
||||||
|
self.__class__.__name__, 0)
|
||||||
|
else:
|
||||||
|
return err
|
||||||
|
|
||||||
|
def impl_is_unique(self):
|
||||||
|
return getattr(self, '_unique', False)
|
||||||
|
|
||||||
|
def impl_get_validator(self):
|
||||||
|
val = getattr(self, '_val_call', (None,))[0]
|
||||||
|
if val is None:
|
||||||
|
ret_val = (None, {})
|
||||||
|
elif len(val) == 1:
|
||||||
|
ret_val = (val[0], {})
|
||||||
|
else:
|
||||||
|
ret_val = val
|
||||||
|
return ret_val
|
||||||
|
|
||||||
|
def impl_validate(self, value, context=undefined, validate=True,
|
||||||
|
force_index=None, force_submulti_index=None,
|
||||||
|
current_opt=undefined, is_multi=None,
|
||||||
|
display_error=True, display_warnings=True, multi=None,
|
||||||
|
setting_properties=undefined):
|
||||||
|
"""
|
||||||
|
:param value: the option's value
|
||||||
|
:param context: Config's context
|
||||||
|
:type context: :class:`tiramisu.config.Config`
|
||||||
|
: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
|
||||||
|
: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
|
||||||
|
if current_opt is undefined:
|
||||||
|
current_opt = self
|
||||||
|
|
||||||
|
if display_warnings and setting_properties is undefined and context is not undefined:
|
||||||
|
setting_properties = context.cfgimpl_get_settings()._getproperties(read_write=False)
|
||||||
|
display_warnings = display_warnings and (setting_properties is undefined or 'warnings' in setting_properties)
|
||||||
|
|
||||||
|
def _is_not_unique(value):
|
||||||
|
if display_error and self.impl_is_unique() and len(set(value)) != len(value):
|
||||||
|
for idx, val in enumerate(value):
|
||||||
|
if val in value[idx+1:]:
|
||||||
|
return ValueError(_('invalid value "{}", this value is already in "{}"').format(
|
||||||
|
val, self.impl_get_display_name()))
|
||||||
|
|
||||||
|
def calculation_validator(val, _index):
|
||||||
|
validator, validator_params = self.impl_get_validator()
|
||||||
|
if validator is not None:
|
||||||
|
if validator_params != {}:
|
||||||
|
validator_params_ = {}
|
||||||
|
for val_param, values in validator_params.items():
|
||||||
|
validator_params_[val_param] = values
|
||||||
|
#inject value in calculation
|
||||||
|
if '' in validator_params_:
|
||||||
|
lst = list(validator_params_[''])
|
||||||
|
lst.insert(0, val)
|
||||||
|
validator_params_[''] = tuple(lst)
|
||||||
|
else:
|
||||||
|
validator_params_[''] = (val,)
|
||||||
|
else:
|
||||||
|
validator_params_ = {'': (val,)}
|
||||||
|
# Raise ValueError if not valid
|
||||||
|
value = carry_out_calculation(current_opt, context=context,
|
||||||
|
callback=validator,
|
||||||
|
callback_params=validator_params_,
|
||||||
|
index=_index,
|
||||||
|
is_validator=True)
|
||||||
|
if isinstance(value, Exception):
|
||||||
|
return value
|
||||||
|
|
||||||
|
def do_validation(_value, _index, submulti_index):
|
||||||
|
if _value is None:
|
||||||
|
error = warning = None
|
||||||
|
else:
|
||||||
|
if display_error:
|
||||||
|
# option validation
|
||||||
|
err = self._validate(_value, context, current_opt)
|
||||||
|
if err:
|
||||||
|
if debug: # pragma: no cover
|
||||||
|
log.debug('do_validation: value: {0}, index: {1}, '
|
||||||
|
'submulti_index: {2}'.format(_value, _index,
|
||||||
|
submulti_index),
|
||||||
|
exc_info=True)
|
||||||
|
err_msg = '{0}'.format(err)
|
||||||
|
if err_msg:
|
||||||
|
msg = _('"{0}" is an invalid {1} for "{2}", {3}'
|
||||||
|
'').format(_value, self._display_name,
|
||||||
|
self.impl_get_display_name(), err_msg)
|
||||||
|
else:
|
||||||
|
msg = _('"{0}" is an invalid {1} for "{2}"'
|
||||||
|
'').format(_value, self._display_name,
|
||||||
|
self.impl_get_display_name())
|
||||||
|
return ValueError(msg)
|
||||||
|
error = None
|
||||||
|
is_warnings_only = getattr(self, '_warnings_only', False)
|
||||||
|
if ((display_error and not is_warnings_only) or
|
||||||
|
(display_warnings and is_warnings_only)):
|
||||||
|
error = calculation_validator(_value, _index)
|
||||||
|
if not error:
|
||||||
|
error = self._second_level_validation(_value, is_warnings_only)
|
||||||
|
if error:
|
||||||
|
if debug: # pragma: no cover
|
||||||
|
log.debug(_('do_validation for {0}: error in value').format(
|
||||||
|
self.impl_getname()), exc_info=True)
|
||||||
|
if is_warnings_only:
|
||||||
|
msg = _('attention, "{0}" could be an invalid {1} for "{2}", {3}').format(
|
||||||
|
_value, self._display_name, self.impl_get_display_name(), error)
|
||||||
|
warnings.warn_explicit(ValueWarning(msg, self),
|
||||||
|
ValueWarning,
|
||||||
|
self.__class__.__name__, 0)
|
||||||
|
error = None
|
||||||
|
if error is None:
|
||||||
|
# if context launch consistency validation
|
||||||
|
#if context is not undefined:
|
||||||
|
ret = self._valid_consistency(current_opt, _value, context,
|
||||||
|
_index, submulti_index, display_warnings,
|
||||||
|
display_error)
|
||||||
|
if isinstance(ret, ValueError):
|
||||||
|
error = ret
|
||||||
|
elif ret:
|
||||||
|
return ret
|
||||||
|
if error:
|
||||||
|
err_msg = '{0}'.format(error)
|
||||||
|
if err_msg:
|
||||||
|
msg = _('"{0}" is an invalid {1} for "{2}", {3}'
|
||||||
|
'').format(_value, self._display_name,
|
||||||
|
self.impl_get_display_name(), err_msg)
|
||||||
|
else:
|
||||||
|
msg = _('"{0}" is an invalid {1} for "{2}"'
|
||||||
|
'').format(_value, self._display_name,
|
||||||
|
self.impl_get_display_name())
|
||||||
|
return ValueError(msg)
|
||||||
|
|
||||||
|
if is_multi is None:
|
||||||
|
is_multi = self.impl_is_multi()
|
||||||
|
|
||||||
|
if not is_multi:
|
||||||
|
return do_validation(value, None, None)
|
||||||
|
elif force_index is not None:
|
||||||
|
if self.impl_is_submulti() and force_submulti_index is None:
|
||||||
|
err = _is_not_unique(value)
|
||||||
|
if err:
|
||||||
|
return err
|
||||||
|
if not isinstance(value, list):
|
||||||
|
return ValueError(_('invalid value "{0}" for "{1}" which'
|
||||||
|
' must be a list').format(
|
||||||
|
value, self.impl_get_display_name()))
|
||||||
|
for idx, val in enumerate(value):
|
||||||
|
if isinstance(val, list): # pragma: no cover
|
||||||
|
return ValueError(_('invalid value "{}" for "{}" '
|
||||||
|
'which must not be a list').format(val,
|
||||||
|
self.impl_get_display_name()))
|
||||||
|
err = do_validation(val, force_index, idx)
|
||||||
|
if err:
|
||||||
|
return err
|
||||||
|
else:
|
||||||
|
if multi is not None and self.impl_is_unique() and value in multi:
|
||||||
|
if not self.impl_is_submulti() and len(multi) - 1 >= force_index:
|
||||||
|
lst = list(multi)
|
||||||
|
lst.pop(force_index)
|
||||||
|
else:
|
||||||
|
lst = multi
|
||||||
|
if value in lst:
|
||||||
|
return ValueError(_('invalid value "{}", this value is already'
|
||||||
|
' in "{}"').format(value,
|
||||||
|
self.impl_get_display_name()))
|
||||||
|
return do_validation(value, force_index, force_submulti_index)
|
||||||
|
elif not isinstance(value, list):
|
||||||
|
return ValueError(_('invalid value "{0}" for "{1}" which '
|
||||||
|
'must be a list').format(value,
|
||||||
|
self.impl_getname()))
|
||||||
|
elif self.impl_is_submulti() and force_submulti_index is None:
|
||||||
|
for idx, val in enumerate(value):
|
||||||
|
err = _is_not_unique(val)
|
||||||
|
if err:
|
||||||
|
return err
|
||||||
|
if not isinstance(val, list):
|
||||||
|
return ValueError(_('invalid value "{0}" for "{1}" '
|
||||||
|
'which must be a list of list'
|
||||||
|
'').format(val,
|
||||||
|
self.impl_getname()))
|
||||||
|
for slave_idx, slave_val in enumerate(val):
|
||||||
|
err = do_validation(slave_val, idx, slave_idx)
|
||||||
|
if err:
|
||||||
|
return err
|
||||||
|
else:
|
||||||
|
err = _is_not_unique(value)
|
||||||
|
if err:
|
||||||
|
return err
|
||||||
|
for idx, val in enumerate(value):
|
||||||
|
err = do_validation(val, idx, force_submulti_index)
|
||||||
|
if err:
|
||||||
|
return err
|
||||||
|
return self._valid_consistency(current_opt, None, context,
|
||||||
|
None, None, display_warnings, display_error)
|
||||||
|
|
||||||
|
def impl_is_dynsymlinkoption(self):
|
||||||
|
return False
|
||||||
|
|
||||||
|
def impl_is_master_slaves(self, type_='both'):
|
||||||
|
"""FIXME
|
||||||
|
"""
|
||||||
|
master_slaves = self.impl_get_master_slaves()
|
||||||
|
if master_slaves is not None:
|
||||||
|
if type_ in ('both', 'master') and \
|
||||||
|
master_slaves.is_master(self):
|
||||||
|
return True
|
||||||
|
if type_ in ('both', 'slave') and \
|
||||||
|
not master_slaves.is_master(self):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def impl_get_master_slaves(self):
|
||||||
|
return getattr(self, '_master_slaves', None)
|
||||||
|
|
||||||
|
def impl_getdoc(self):
|
||||||
|
"accesses the Option's doc"
|
||||||
|
return self.impl_get_information('doc')
|
||||||
|
|
||||||
|
def _valid_consistencies(self, other_opts, init=True, func=None):
|
||||||
|
if self._is_subdyn():
|
||||||
|
dynod = self._subdyn
|
||||||
|
else:
|
||||||
|
dynod = None
|
||||||
|
if self.impl_is_submulti():
|
||||||
|
raise ConfigError(_('cannot add consistency with submulti option'))
|
||||||
|
is_multi = self.impl_is_multi()
|
||||||
|
for opt in other_opts:
|
||||||
|
if opt.impl_is_submulti():
|
||||||
|
raise ConfigError(_('cannot add consistency with submulti option'))
|
||||||
|
if not isinstance(opt, Option):
|
||||||
|
raise ConfigError(_('consistency must be set with an option'))
|
||||||
|
if opt._is_subdyn():
|
||||||
|
if dynod is None:
|
||||||
|
raise ConfigError(_('almost one option in consistency is '
|
||||||
|
'in a dynoptiondescription but not all'))
|
||||||
|
if dynod != opt._subdyn:
|
||||||
|
raise ConfigError(_('option in consistency must be in same'
|
||||||
|
' dynoptiondescription'))
|
||||||
|
dynod = opt._subdyn
|
||||||
|
elif dynod is not None:
|
||||||
|
raise ConfigError(_('almost one option in consistency is in a '
|
||||||
|
'dynoptiondescription but not all'))
|
||||||
|
if self is opt:
|
||||||
|
raise ConfigError(_('cannot add consistency with itself'))
|
||||||
|
if is_multi != opt.impl_is_multi():
|
||||||
|
raise ConfigError(_('every options in consistency must be '
|
||||||
|
'multi or none'))
|
||||||
|
if init:
|
||||||
|
# FIXME
|
||||||
|
if func != 'not_equal':
|
||||||
|
opt._set_has_dependency()
|
||||||
|
|
||||||
|
def impl_add_consistency(self, func, *other_opts, **params):
|
||||||
|
"""Add consistency means that value will be validate with other_opts
|
||||||
|
option's values.
|
||||||
|
|
||||||
|
:param func: function's name
|
||||||
|
:type func: `str`
|
||||||
|
:param other_opts: options used to validate value
|
||||||
|
:type other_opts: `list` of `tiramisu.option.Option`
|
||||||
|
:param params: extra params (warnings_only and transitive are allowed)
|
||||||
|
"""
|
||||||
|
if self.impl_is_readonly():
|
||||||
|
raise AttributeError(_("'{0}' ({1}) cannot add consistency, option is"
|
||||||
|
" read-only").format(
|
||||||
|
self.__class__.__name__,
|
||||||
|
self.impl_getname()))
|
||||||
|
self._valid_consistencies(other_opts, func=func)
|
||||||
|
func = '_cons_{0}'.format(func)
|
||||||
|
if func not in dir(self):
|
||||||
|
raise ConfigError(_('consistency {0} not available for this option').format(func))
|
||||||
|
all_cons_opts = tuple([self] + list(other_opts))
|
||||||
|
unknown_params = set(params.keys()) - set(['warnings_only', 'transitive'])
|
||||||
|
if unknown_params != set():
|
||||||
|
raise ValueError(_('unknow parameter {0} in consistency').format(unknown_params))
|
||||||
|
self._add_consistency(func, all_cons_opts, params)
|
||||||
|
#validate default value when add consistency
|
||||||
|
err = self.impl_validate(self.impl_getdefault())
|
||||||
|
if err:
|
||||||
|
self._del_consistency()
|
||||||
|
raise err
|
||||||
|
if func in ALLOWED_CONST_LIST:
|
||||||
|
for opt in all_cons_opts:
|
||||||
|
if getattr(opt, '_unique', undefined) == undefined:
|
||||||
|
opt._unique = True
|
||||||
|
if func != '_cons_not_equal':
|
||||||
|
#consistency could generate warnings or errors
|
||||||
|
self._set_has_dependency()
|
||||||
|
|
||||||
|
def _valid_consistency(self, option, value, context, index, submulti_idx,
|
||||||
|
display_warnings, display_error):
|
||||||
|
if context is not undefined:
|
||||||
|
descr = context.cfgimpl_get_description()
|
||||||
|
if descr._cache_consistencies is None:
|
||||||
|
return
|
||||||
|
#consistencies is something like [('_cons_not_equal', (opt1, opt2))]
|
||||||
|
if isinstance(option, DynSymLinkOption):
|
||||||
|
consistencies = descr._cache_consistencies.get(option._impl_getopt())
|
||||||
|
else:
|
||||||
|
consistencies = descr._cache_consistencies.get(option)
|
||||||
|
else:
|
||||||
|
consistencies = option._get_consistencies()
|
||||||
|
if consistencies is not None:
|
||||||
|
for func, all_cons_opts, params in consistencies:
|
||||||
|
warnings_only = params.get('warnings_only', False)
|
||||||
|
if (warnings_only and display_warnings) or (not warnings_only and display_error):
|
||||||
|
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])
|
||||||
|
namelen = len(option._impl_getopt().impl_getname())
|
||||||
|
suffix = option.impl_getname()[namelen:]
|
||||||
|
opts = []
|
||||||
|
for opt in all_cons_opts:
|
||||||
|
name = opt.impl_getname() + suffix
|
||||||
|
path = subpath + '.' + name
|
||||||
|
opts.append(opt._impl_to_dyn(name, path))
|
||||||
|
else:
|
||||||
|
opts = all_cons_opts
|
||||||
|
err = opts[0]._launch_consistency(self, func, option, value,
|
||||||
|
context, index, submulti_idx,
|
||||||
|
opts, warnings_only,
|
||||||
|
transitive)
|
||||||
|
if err:
|
||||||
|
return err
|
||||||
|
|
||||||
|
def _cons_not_equal(self, current_opt, opts, vals, warnings_only):
|
||||||
|
equal = set()
|
||||||
|
is_current = False
|
||||||
|
for idx_inf, val_inf in enumerate(vals):
|
||||||
|
for idx_sup, val_sup in enumerate(vals[idx_inf + 1:]):
|
||||||
|
if val_inf == val_sup is not None:
|
||||||
|
for opt_ in [opts[idx_inf], opts[idx_inf + idx_sup + 1]]:
|
||||||
|
if opt_ == current_opt:
|
||||||
|
is_current = True
|
||||||
|
else:
|
||||||
|
equal.add(opt_)
|
||||||
|
if equal:
|
||||||
|
if debug: # pragma: no cover
|
||||||
|
log.debug(_('_cons_not_equal: {} are not different').format(display_list(list(equal))))
|
||||||
|
if is_current:
|
||||||
|
if warnings_only:
|
||||||
|
msg = _('should be different from the value of {}')
|
||||||
|
else:
|
||||||
|
msg = _('must be different from the value of {}')
|
||||||
|
else:
|
||||||
|
if warnings_only:
|
||||||
|
msg = _('value for {} should be different')
|
||||||
|
else:
|
||||||
|
msg = _('value for {} must be different')
|
||||||
|
equal_name = []
|
||||||
|
for opt in equal:
|
||||||
|
equal_name.append(opt.impl_get_display_name())
|
||||||
|
return ValueError(msg.format(display_list(list(equal_name))))
|
||||||
|
|
||||||
|
def _second_level_validation(self, value, warnings_only):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _impl_to_dyn(self, name, path):
|
||||||
|
return DynSymLinkOption(name, self, dyn=path)
|
||||||
|
|
||||||
|
def impl_getdefault_multi(self):
|
||||||
|
"accessing the default value for a multi"
|
||||||
|
return getattr(self, '_default_multi', None)
|
||||||
|
|
||||||
|
def _validate_callback(self, callback, callback_params):
|
||||||
|
"""callback_params:
|
||||||
|
* None
|
||||||
|
* {'': ((option, permissive),), 'ip': ((None,), (option, permissive))
|
||||||
|
"""
|
||||||
|
if callback is None:
|
||||||
|
return
|
||||||
|
default_multi = self.impl_getdefault_multi()
|
||||||
|
is_multi = self.impl_is_multi()
|
||||||
|
default = self.impl_getdefault()
|
||||||
|
if (not is_multi and (default is not None or default_multi is not None)) or \
|
||||||
|
(is_multi and (default != [] or default_multi is not None)):
|
||||||
|
raise ValueError(_("default value not allowed if option: {0} "
|
||||||
|
"is calculated").format(self.impl_getname()))
|
||||||
|
|
||||||
|
def impl_getdefault(self):
|
||||||
|
"accessing the default value"
|
||||||
|
is_multi = self.impl_is_multi()
|
||||||
|
default = getattr(self, '_default', undefined)
|
||||||
|
if default is undefined:
|
||||||
|
if is_multi:
|
||||||
|
default = []
|
||||||
|
else:
|
||||||
|
default = None
|
||||||
|
else:
|
||||||
|
if is_multi:
|
||||||
|
default = list(default)
|
||||||
|
return default
|
||||||
|
|
||||||
|
def _get_extra(self, key):
|
||||||
|
extra = self._extra
|
||||||
|
if isinstance(extra, tuple):
|
||||||
|
return extra[1][extra[0].index(key)]
|
||||||
|
else:
|
||||||
|
return extra[key]
|
||||||
|
|
||||||
|
def impl_is_submulti(self):
|
||||||
|
return getattr(self, '_multi', 1) == 2
|
||||||
|
|
||||||
|
def impl_allow_empty_list(self):
|
||||||
|
return getattr(self, '_allow_empty_list', undefined)
|
||||||
|
|
||||||
|
#____________________________________________________________
|
||||||
|
# consistency
|
||||||
|
def _add_consistency(self, func, all_cons_opts, params):
|
||||||
|
cons = (func, all_cons_opts, params)
|
||||||
|
consistencies = getattr(self, '_consistencies', None)
|
||||||
|
if consistencies is None:
|
||||||
|
self._consistencies = [cons]
|
||||||
|
else:
|
||||||
|
consistencies.append(cons)
|
||||||
|
|
||||||
|
def _del_consistency(self):
|
||||||
|
self._consistencies.pop(-1)
|
||||||
|
|
||||||
|
def _get_consistencies(self):
|
||||||
|
return getattr(self, '_consistencies', STATIC_TUPLE)
|
||||||
|
|
||||||
|
def _has_consistencies(self):
|
||||||
|
return hasattr(self, '_consistencies')
|
||||||
|
|
||||||
|
|
||||||
class _RegexpOption(Option):
|
class _RegexpOption(Option):
|
||||||
|
|
|
@ -24,13 +24,14 @@ import re
|
||||||
|
|
||||||
from ..i18n import _
|
from ..i18n import _
|
||||||
from ..setting import groups, undefined, owners # , log
|
from ..setting import groups, undefined, owners # , log
|
||||||
from .baseoption import BaseOption, SymLinkOption, Option, ALLOWED_CONST_LIST
|
from .baseoption import BaseOption
|
||||||
|
from .option import Option, ALLOWED_CONST_LIST
|
||||||
from . import MasterSlaves
|
from . import MasterSlaves
|
||||||
from ..error import ConfigError, ConflictError
|
from ..error import ConfigError, ConflictError
|
||||||
from ..autolib import carry_out_calculation
|
from ..autolib import carry_out_calculation
|
||||||
|
|
||||||
|
|
||||||
name_regexp = re.compile(r'^[a-zA-Z\d\-_]*$')
|
NAME_REGEXP = re.compile(r'^[a-zA-Z\d\-_]*$')
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
if sys.version_info[0] >= 3: # pragma: no cover
|
if sys.version_info[0] >= 3: # pragma: no cover
|
||||||
|
@ -76,7 +77,7 @@ class CacheOptionDescription(BaseOption):
|
||||||
option._dependencies = tuple(options)
|
option._dependencies = tuple(options)
|
||||||
option._set_readonly(True)
|
option._set_readonly(True)
|
||||||
is_multi = option.impl_is_multi()
|
is_multi = option.impl_is_multi()
|
||||||
if not isinstance(option, SymLinkOption) and 'force_store_value' in option.impl_getproperties():
|
if not option._is_symlinkoption() and 'force_store_value' in option.impl_getproperties():
|
||||||
force_store_values.append((subpath, option))
|
force_store_values.append((subpath, option))
|
||||||
for func, all_cons_opts, params in option._get_consistencies():
|
for func, all_cons_opts, params in option._get_consistencies():
|
||||||
option._valid_consistencies(all_cons_opts[1:], init=False)
|
option._valid_consistencies(all_cons_opts[1:], init=False)
|
||||||
|
@ -458,7 +459,7 @@ class OptionDescription(OptionDescriptionWalk):
|
||||||
if isinstance(group_type, groups.MasterGroupType):
|
if isinstance(group_type, groups.MasterGroupType):
|
||||||
children = self.impl_getchildren()
|
children = self.impl_getchildren()
|
||||||
for child in children:
|
for child in children:
|
||||||
if isinstance(child, SymLinkOption): # pragma: optional cover
|
if child._is_symlinkoption(): # pragma: optional cover
|
||||||
raise ValueError(_("master group {0} shall not have "
|
raise ValueError(_("master group {0} shall not have "
|
||||||
"a symlinkoption").format(self.impl_getname()))
|
"a symlinkoption").format(self.impl_getname()))
|
||||||
if not isinstance(child, Option): # pragma: optional cover
|
if not isinstance(child, Option): # pragma: optional cover
|
||||||
|
@ -490,7 +491,7 @@ class OptionDescription(OptionDescriptionWalk):
|
||||||
if len(values) > len(set(values)):
|
if len(values) > len(set(values)):
|
||||||
raise ConfigError(_('DynOptionDescription callback return not unique value'))
|
raise ConfigError(_('DynOptionDescription callback return not unique value'))
|
||||||
for val in values:
|
for val in values:
|
||||||
if not isinstance(val, str) or re.match(name_regexp, val) is None:
|
if not isinstance(val, str) or re.match(NAME_REGEXP, val) is None:
|
||||||
raise ValueError(_("invalid suffix: {0} for option").format(val))
|
raise ValueError(_("invalid suffix: {0} for option").format(val))
|
||||||
return values
|
return values
|
||||||
|
|
||||||
|
@ -507,7 +508,7 @@ class DynOptionDescription(OptionDescription):
|
||||||
'dynoptiondescription'))
|
'dynoptiondescription'))
|
||||||
for chld in child._impl_getchildren():
|
for chld in child._impl_getchildren():
|
||||||
chld._impl_setsubdyn(self)
|
chld._impl_setsubdyn(self)
|
||||||
if isinstance(child, SymLinkOption):
|
if child._is_symlinkoption():
|
||||||
raise ConfigError(_('cannot set symlinkoption in a '
|
raise ConfigError(_('cannot set symlinkoption in a '
|
||||||
'dynoptiondescription'))
|
'dynoptiondescription'))
|
||||||
child._impl_setsubdyn(self)
|
child._impl_setsubdyn(self)
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
|
|
||||||
from ..setting import undefined
|
from ..setting import undefined
|
||||||
from ..i18n import _
|
from ..i18n import _
|
||||||
from .baseoption import Option
|
from .option import Option
|
||||||
|
|
||||||
|
|
||||||
class PasswordOption(Option):
|
class PasswordOption(Option):
|
||||||
|
|
|
@ -23,7 +23,7 @@ import sys
|
||||||
|
|
||||||
from ..setting import undefined
|
from ..setting import undefined
|
||||||
from ..i18n import _
|
from ..i18n import _
|
||||||
from .baseoption import Option
|
from .option import Option
|
||||||
|
|
||||||
|
|
||||||
class PortOption(Option):
|
class PortOption(Option):
|
||||||
|
|
|
@ -22,7 +22,7 @@ import sys
|
||||||
|
|
||||||
from ..setting import undefined
|
from ..setting import undefined
|
||||||
from ..i18n import _
|
from ..i18n import _
|
||||||
from .baseoption import Option
|
from .option import Option
|
||||||
|
|
||||||
|
|
||||||
class StrOption(Option):
|
class StrOption(Option):
|
||||||
|
|
|
@ -22,7 +22,7 @@ import re
|
||||||
|
|
||||||
from ..setting import undefined
|
from ..setting import undefined
|
||||||
from ..i18n import _
|
from ..i18n import _
|
||||||
from .baseoption import Option
|
from .option import Option
|
||||||
from .domainnameoption import DomainnameOption
|
from .domainnameoption import DomainnameOption
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -22,8 +22,7 @@ from .error import ConfigError, SlaveError, PropertiesOptionError
|
||||||
from .setting import owners, expires_time, undefined
|
from .setting import owners, expires_time, undefined
|
||||||
from .autolib import carry_out_calculation
|
from .autolib import carry_out_calculation
|
||||||
from .i18n import _
|
from .i18n import _
|
||||||
from .option import SymLinkOption, DynSymLinkOption, Option
|
from .option import DynSymLinkOption, Option
|
||||||
i_i = 0
|
|
||||||
|
|
||||||
|
|
||||||
class Values(object):
|
class Values(object):
|
||||||
|
@ -497,7 +496,7 @@ class Values(object):
|
||||||
was present
|
was present
|
||||||
:returns: a `setting.owners.Owner` object
|
:returns: a `setting.owners.Owner` object
|
||||||
"""
|
"""
|
||||||
if isinstance(opt, SymLinkOption) and \
|
if opt._is_symlinkoption() and \
|
||||||
not isinstance(opt, DynSymLinkOption):
|
not isinstance(opt, DynSymLinkOption):
|
||||||
opt = opt._impl_getopt()
|
opt = opt._impl_getopt()
|
||||||
path = opt.impl_getpath(self._getcontext())
|
path = opt.impl_getpath(self._getcontext())
|
||||||
|
@ -647,7 +646,7 @@ class Values(object):
|
||||||
for path in _mandatory_warnings(opt, currpath + [name]):
|
for path in _mandatory_warnings(opt, currpath + [name]):
|
||||||
yield path
|
yield path
|
||||||
else:
|
else:
|
||||||
if isinstance(opt, SymLinkOption) and \
|
if opt._is_symlinkoption() and \
|
||||||
not isinstance(opt, DynSymLinkOption):
|
not isinstance(opt, DynSymLinkOption):
|
||||||
continue
|
continue
|
||||||
self_properties = settings._getproperties(opt, path,
|
self_properties = settings._getproperties(opt, path,
|
||||||
|
|
Loading…
Reference in New Issue