From 635b71d291867a3dc43885c06c406f2127125f7d Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Mon, 24 Jul 2017 20:39:01 +0200 Subject: [PATCH] separate baseoption and option --- tiramisu/config.py | 4 +- tiramisu/option/__init__.py | 3 +- tiramisu/option/baseoption.py | 655 +-------------------------- tiramisu/option/booloption.py | 2 +- tiramisu/option/broadcastoption.py | 2 +- tiramisu/option/choiceoption.py | 5 +- tiramisu/option/dateoption.py | 3 +- tiramisu/option/domainnameoption.py | 2 +- tiramisu/option/floatoption.py | 2 +- tiramisu/option/intoption.py | 2 +- tiramisu/option/ipoption.py | 2 +- tiramisu/option/netmaskoption.py | 2 +- tiramisu/option/networkoption.py | 2 +- tiramisu/option/option.py | 637 +++++++++++++++++++++++++- tiramisu/option/optiondescription.py | 13 +- tiramisu/option/passwordoption.py | 2 +- tiramisu/option/portoption.py | 2 +- tiramisu/option/stroption.py | 2 +- tiramisu/option/urloption.py | 2 +- tiramisu/value.py | 7 +- 20 files changed, 682 insertions(+), 669 deletions(-) diff --git a/tiramisu/config.py b/tiramisu/config.py index 6ab6474..0625d46 100644 --- a/tiramisu/config.py +++ b/tiramisu/config.py @@ -307,7 +307,7 @@ class SubConfig(object): context=context) if isinstance(child, OptionDescription) or isinstance(child, SynDynOptionDescription): 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 path = context.cfgimpl_get_description().impl_get_path_by_opt( child._impl_getopt()) @@ -382,7 +382,7 @@ class SubConfig(object): setting_properties=_setting_properties, self_properties=_self_properties, 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( option._impl_getopt()) cfg = context.getattr(path, validate=validate, diff --git a/tiramisu/option/__init__.py b/tiramisu/option/__init__.py index 2437d3d..e4ad0fc 100644 --- a/tiramisu/option/__init__.py +++ b/tiramisu/option/__init__.py @@ -1,7 +1,8 @@ from .masterslave import MasterSlaves from .optiondescription import OptionDescription, DynOptionDescription, \ SynDynOptionDescription -from .baseoption import Option, SymLinkOption, DynSymLinkOption, submulti +from .baseoption import SymLinkOption, DynSymLinkOption, submulti +from .option import Option from .choiceoption import ChoiceOption from .booloption import BoolOption from .intoption import IntOption diff --git a/tiramisu/option/baseoption.py b/tiramisu/option/baseoption.py index 4db060d..912ba52 100644 --- a/tiramisu/option/baseoption.py +++ b/tiramisu/option/baseoption.py @@ -20,14 +20,11 @@ # ____________________________________________________________ import re from types import FunctionType -import warnings import sys from ..i18n import _ -from ..setting import log, undefined, debug -from ..autolib import carry_out_calculation -from ..error import (ConfigError, ValueWarning, PropertiesOptionError, - display_list) +from ..setting import undefined +from ..error import ConfigError if sys.version_info[0] >= 3: # pragma: no cover from inspect import signature @@ -36,16 +33,12 @@ else: STATIC_TUPLE = tuple() -if sys.version_info[0] >= 3: # pragma: no cover - xrange = range - submulti = 2 NAME_REGEXP = re.compile(r'^[a-z][a-zA-Z\d_]*$') FORBIDDEN_NAMES = frozenset(['iter_all', 'iter_group', 'find', 'find_first', 'make_dict', 'unwrap_from_path', 'read_only', 'read_write', 'getowner', 'set_contexts']) -ALLOWED_CONST_LIST = ['_cons_not_equal'] def valid_name(name): @@ -64,10 +57,11 @@ def validate_callback(callback, callback_params, type_, callbackoption): """ def _validate_option(option): #validate option - if isinstance(option, SymLinkOption): - cur_opt = option._impl_getopt() - elif isinstance(option, Option): - cur_opt = option + if hasattr(option, '_is_symlinkoption'): + if option._is_symlinkoption(): + cur_opt = option._impl_getopt() + else: + cur_opt = option else: raise ValueError(_('{}_params must have an option' ' not a {} for first argument' @@ -205,7 +199,7 @@ class Base(object): return validator_params def _set_has_dependency(self): - if not isinstance(self, SymLinkOption): + if not self._is_symlinkoption(): self._has_dependency = True def impl_has_dependency(self): @@ -399,633 +393,14 @@ class BaseOption(Base): opt=self, path=path) + def _is_symlinkoption(self): + return False + class OnlyOption(BaseOption): __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): """check malformed requirements and tranform dict to internal tuple @@ -1045,7 +420,7 @@ def validate_requires_arg(new_option, multi, requires, name): def get_option(require): option = require['option'] - if not isinstance(option, Option): + if not hasattr(option, '_is_symlinkoption'): raise ValueError(_('malformed requirements ' 'must be an option in option {0}').format(name)) if not multi and option.impl_is_multi(): @@ -1178,7 +553,8 @@ def validate_requires_arg(new_option, multi, requires, name): class SymLinkOption(OnlyOption): def __init__(self, name, opt): - if not isinstance(opt, Option): + if not isinstance(opt, OnlyOption) or \ + opt._is_symlinkoption(): raise ValueError(_('malformed symlinkoption ' 'must be an option ' 'for symlink {0}').format(name)) @@ -1187,6 +563,9 @@ class SymLinkOption(OnlyOption): _setattr(self, '_opt', opt) opt._set_has_dependency() + def _is_symlinkoption(self): + return True + def __getattr__(self, name, context=undefined): return getattr(self._impl_getopt(), name) diff --git a/tiramisu/option/booloption.py b/tiramisu/option/booloption.py index ed6581f..49f3a54 100644 --- a/tiramisu/option/booloption.py +++ b/tiramisu/option/booloption.py @@ -21,7 +21,7 @@ from ..setting import undefined from ..i18n import _ -from .baseoption import Option +from .option import Option class BoolOption(Option): diff --git a/tiramisu/option/broadcastoption.py b/tiramisu/option/broadcastoption.py index 175fd0e..c6170dd 100644 --- a/tiramisu/option/broadcastoption.py +++ b/tiramisu/option/broadcastoption.py @@ -23,7 +23,7 @@ from IPy import IP from ..error import ConfigError from ..setting import undefined from ..i18n import _ -from .baseoption import Option +from .option import Option class BroadcastOption(Option): diff --git a/tiramisu/option/choiceoption.py b/tiramisu/option/choiceoption.py index eeffc53..32895c3 100644 --- a/tiramisu/option/choiceoption.py +++ b/tiramisu/option/choiceoption.py @@ -22,9 +22,10 @@ from types import FunctionType from ..setting import undefined 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 ..error import ConfigError +from ..error import ConfigError, display_list class ChoiceOption(Option): diff --git a/tiramisu/option/dateoption.py b/tiramisu/option/dateoption.py index 55c9304..b368827 100644 --- a/tiramisu/option/dateoption.py +++ b/tiramisu/option/dateoption.py @@ -18,12 +18,11 @@ # the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/ # the whole pypy projet is under MIT licence # ____________________________________________________________ -import re from datetime import datetime from ..setting import undefined from ..i18n import _ -from .baseoption import Option +from .option import Option class DateOption(Option): diff --git a/tiramisu/option/domainnameoption.py b/tiramisu/option/domainnameoption.py index 765f5cb..dfe3552 100644 --- a/tiramisu/option/domainnameoption.py +++ b/tiramisu/option/domainnameoption.py @@ -23,7 +23,7 @@ from IPy import IP from ..setting import undefined from ..i18n import _ -from .baseoption import Option +from .option import Option class DomainnameOption(Option): diff --git a/tiramisu/option/floatoption.py b/tiramisu/option/floatoption.py index 2eea4fa..9d2c6fc 100644 --- a/tiramisu/option/floatoption.py +++ b/tiramisu/option/floatoption.py @@ -21,7 +21,7 @@ from ..setting import undefined from ..i18n import _ -from .baseoption import Option +from .option import Option class FloatOption(Option): diff --git a/tiramisu/option/intoption.py b/tiramisu/option/intoption.py index 9ffcc51..fb47ef6 100644 --- a/tiramisu/option/intoption.py +++ b/tiramisu/option/intoption.py @@ -21,7 +21,7 @@ from ..setting import undefined from ..i18n import _ -from .baseoption import Option +from .option import Option class IntOption(Option): diff --git a/tiramisu/option/ipoption.py b/tiramisu/option/ipoption.py index 346eaec..c100494 100644 --- a/tiramisu/option/ipoption.py +++ b/tiramisu/option/ipoption.py @@ -23,7 +23,7 @@ from IPy import IP from ..error import ConfigError from ..setting import undefined from ..i18n import _ -from .baseoption import Option +from .option import Option class IPOption(Option): diff --git a/tiramisu/option/netmaskoption.py b/tiramisu/option/netmaskoption.py index daa65f6..dcd9ef0 100644 --- a/tiramisu/option/netmaskoption.py +++ b/tiramisu/option/netmaskoption.py @@ -23,7 +23,7 @@ from IPy import IP from ..error import ConfigError from ..setting import undefined from ..i18n import _ -from .baseoption import Option +from .option import Option class NetmaskOption(Option): diff --git a/tiramisu/option/networkoption.py b/tiramisu/option/networkoption.py index f891c4c..75f9e17 100644 --- a/tiramisu/option/networkoption.py +++ b/tiramisu/option/networkoption.py @@ -22,7 +22,7 @@ from IPy import IP from ..setting import undefined from ..i18n import _ -from .baseoption import Option +from .option import Option class NetworkOption(Option): diff --git a/tiramisu/option/option.py b/tiramisu/option/option.py index 9545e49..2b550e2 100644 --- a/tiramisu/option/option.py +++ b/tiramisu/option/option.py @@ -19,9 +19,642 @@ # the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/ # 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): diff --git a/tiramisu/option/optiondescription.py b/tiramisu/option/optiondescription.py index 9780828..d6d9e3b 100644 --- a/tiramisu/option/optiondescription.py +++ b/tiramisu/option/optiondescription.py @@ -24,13 +24,14 @@ import re from ..i18n import _ 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 ..error import ConfigError, ConflictError 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 if sys.version_info[0] >= 3: # pragma: no cover @@ -76,7 +77,7 @@ class CacheOptionDescription(BaseOption): option._dependencies = tuple(options) option._set_readonly(True) 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)) for func, all_cons_opts, params in option._get_consistencies(): option._valid_consistencies(all_cons_opts[1:], init=False) @@ -458,7 +459,7 @@ class OptionDescription(OptionDescriptionWalk): if isinstance(group_type, groups.MasterGroupType): children = self.impl_getchildren() 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 " "a symlinkoption").format(self.impl_getname())) if not isinstance(child, Option): # pragma: optional cover @@ -490,7 +491,7 @@ class OptionDescription(OptionDescriptionWalk): if len(values) > len(set(values)): raise ConfigError(_('DynOptionDescription callback return not unique value')) 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)) return values @@ -507,7 +508,7 @@ class DynOptionDescription(OptionDescription): 'dynoptiondescription')) for chld in child._impl_getchildren(): chld._impl_setsubdyn(self) - if isinstance(child, SymLinkOption): + if child._is_symlinkoption(): raise ConfigError(_('cannot set symlinkoption in a ' 'dynoptiondescription')) child._impl_setsubdyn(self) diff --git a/tiramisu/option/passwordoption.py b/tiramisu/option/passwordoption.py index 57e5a2d..15b8a86 100644 --- a/tiramisu/option/passwordoption.py +++ b/tiramisu/option/passwordoption.py @@ -21,7 +21,7 @@ from ..setting import undefined from ..i18n import _ -from .baseoption import Option +from .option import Option class PasswordOption(Option): diff --git a/tiramisu/option/portoption.py b/tiramisu/option/portoption.py index db851b0..c810d36 100644 --- a/tiramisu/option/portoption.py +++ b/tiramisu/option/portoption.py @@ -23,7 +23,7 @@ import sys from ..setting import undefined from ..i18n import _ -from .baseoption import Option +from .option import Option class PortOption(Option): diff --git a/tiramisu/option/stroption.py b/tiramisu/option/stroption.py index 9a8c884..c4b79ee 100644 --- a/tiramisu/option/stroption.py +++ b/tiramisu/option/stroption.py @@ -22,7 +22,7 @@ import sys from ..setting import undefined from ..i18n import _ -from .baseoption import Option +from .option import Option class StrOption(Option): diff --git a/tiramisu/option/urloption.py b/tiramisu/option/urloption.py index 5574641..65daf6f 100644 --- a/tiramisu/option/urloption.py +++ b/tiramisu/option/urloption.py @@ -22,7 +22,7 @@ import re from ..setting import undefined from ..i18n import _ -from .baseoption import Option +from .option import Option from .domainnameoption import DomainnameOption diff --git a/tiramisu/value.py b/tiramisu/value.py index dcb226d..4bd0939 100644 --- a/tiramisu/value.py +++ b/tiramisu/value.py @@ -22,8 +22,7 @@ from .error import ConfigError, SlaveError, PropertiesOptionError from .setting import owners, expires_time, undefined from .autolib import carry_out_calculation from .i18n import _ -from .option import SymLinkOption, DynSymLinkOption, Option -i_i = 0 +from .option import DynSymLinkOption, Option class Values(object): @@ -497,7 +496,7 @@ class Values(object): was present :returns: a `setting.owners.Owner` object """ - if isinstance(opt, SymLinkOption) and \ + if opt._is_symlinkoption() and \ not isinstance(opt, DynSymLinkOption): opt = opt._impl_getopt() path = opt.impl_getpath(self._getcontext()) @@ -647,7 +646,7 @@ class Values(object): for path in _mandatory_warnings(opt, currpath + [name]): yield path else: - if isinstance(opt, SymLinkOption) and \ + if opt._is_symlinkoption() and \ not isinstance(opt, DynSymLinkOption): continue self_properties = settings._getproperties(opt, path,