From a07e91615304b673eec90cd4a898d3410c51587a Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Thu, 7 Dec 2017 21:42:04 +0100 Subject: [PATCH] reorganisation --- tiramisu/config.py | 10 +- tiramisu/option/option.py | 294 +++++++++++++-------------- tiramisu/option/optiondescription.py | 11 +- tiramisu/setting.py | 4 +- tiramisu/value.py | 244 ++++++++++++---------- 5 files changed, 285 insertions(+), 278 deletions(-) diff --git a/tiramisu/config.py b/tiramisu/config.py index 5f090b5..4c8257e 100644 --- a/tiramisu/config.py +++ b/tiramisu/config.py @@ -87,12 +87,12 @@ class SubConfig(object): context_ = context() masterp = master.impl_getpath(context_) value = context_.cfgimpl_get_values().get_cached_value(master, - path=masterp, + masterp, + setting_properties, validate=validate, force_permissive=force_permissive, self_properties=undefined, - index=None, - setting_properties=setting_properties) + index=None) self._impl_length = len(value) def cfgimpl_get_length(self): @@ -467,9 +467,9 @@ class SubConfig(object): if returns_option is True: return option return self.cfgimpl_get_values().get_cached_value(option, - path=subpath, + subpath, + setting_properties, validate=validate, - setting_properties=setting_properties, force_permissive=force_permissive, index=index) diff --git a/tiramisu/option/option.py b/tiramisu/option/option.py index 600ab48..0e2389b 100644 --- a/tiramisu/option/option.py +++ b/tiramisu/option/option.py @@ -59,10 +59,21 @@ class Option(OnlyOption): '_choice_values_params', ) _empty = '' - def __init__(self, name, doc, default=undefined, 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, + def __init__(self, + name, + doc, + default=undefined, + 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__ @@ -91,9 +102,13 @@ class Option(OnlyOption): default = [] if validator is not None: if multi: # and validator_params is None: - validator_params = self._build_validator_params(validator, validator_params) + validator_params = self._build_validator_params(validator, + validator_params) - validate_callback(validator, validator_params, 'validator', self) + validate_callback(validator, + validator_params, + 'validator', + self) if validator_params is None: val_call = (validator,) else: @@ -110,22 +125,25 @@ class Option(OnlyOption): 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) + super(Option, self).__init__(name, + doc, + requires=requires, + properties=properties, + is_multi=is_multi) if is_multi and default_multi is not None: def test_multi_value(value): err = self._validate(value) if err: raise ValueError(_("invalid default_multi value {0} " - "for option {1}: {2}").format( - str(value), - self.impl_getname(), str(err))) + "for option {1}: {2}").format(str(value), + self.impl_getname(), + str(err))) if _multi is submulti: if not isinstance(default_multi, list): raise ValueError(_("invalid default_multi value {0} " - "for option {1}: must be a list for a submulti").format( - str(default_multi), - self.impl_getname())) + "for option {1}: must be a list for a submulti" + "").format(str(default_multi), + self.impl_getname())) for value in default_multi: test_multi_value(value) else: @@ -133,7 +151,8 @@ class Option(OnlyOption): _setattr(self, '_default_multi', default_multi) if unique is not undefined: _setattr(self, '_unique', unique) - err = self.impl_validate(default, is_multi=is_multi) + err = self.impl_validate(default, + is_multi=is_multi) if err: raise err if (is_multi and default != []) or \ @@ -142,11 +161,18 @@ class Option(OnlyOption): default = tuple(default) _setattr(self, '_default', default) - self.impl_set_callback(callback, callback_params, _init=True) + self.impl_set_callback(callback, + callback_params, + _init=True) def impl_is_multi(self): return getattr(self, '_multi', 1) != 1 + def _validate(self, + *args, + **kwargs): + pass + def _launch_consistency(self, current_opt, func, @@ -270,7 +296,6 @@ class Option(OnlyOption): def impl_validate(self, value, context=undefined, - validate=True, force_index=None, current_opt=undefined, is_multi=None, @@ -282,14 +307,11 @@ class Option(OnlyOption): :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 """ - if not validate: - return if current_opt is undefined: current_opt = self @@ -298,12 +320,13 @@ class Option(OnlyOption): display_warnings = display_warnings and (setting_properties is undefined or 'warnings' in setting_properties) def _is_not_unique(value): + #FIXME pourquoi la longueur doit etre egal ??? 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:]: raise ValueError(_('invalid value "{}", this value is already in "{}"' - '').format(val, - self.impl_get_display_name())) + '').format(val, + self.impl_get_display_name())) def calculation_validator(val, _index): @@ -323,115 +346,79 @@ class Option(OnlyOption): else: validator_params_ = {'': (val,)} # Raise ValueError if not valid - value = carry_out_calculation(current_opt, - context=context, - callback=validator, - callback_params=validator_params_, - setting_properties=setting_properties, - index=_index, - is_validator=True) - if isinstance(value, Exception): - return value + carry_out_calculation(current_opt, + context=context, + callback=validator, + callback_params=validator_params_, + setting_properties=setting_properties, + index=_index, + is_validator=True) def do_validation(_value, _index): - if _value is None: - error = 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}:' - ' {2}'.format(_value, - _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()) - raise 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, - display_warnings, - display_error, - setting_properties) - 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) + if isinstance(_value, list): # pragma: no cover + raise ValueError(_('invalid value "{}" for "{}" ' + 'which must not be a list').format(_value, + self.impl_get_display_name())) + is_warnings_only = getattr(self, '_warnings_only', False) + try: + if _value is not None: + if display_error: + # option validation + self._validate(_value, + context, + current_opt) + if ((display_error and not is_warnings_only) or + (display_warnings and is_warnings_only)): + calculation_validator(_value, + _index) + self._second_level_validation(_value, + is_warnings_only) + self._valid_consistency(current_opt, + _value, + context, + _index, + display_warnings, + display_error, + setting_properties) + except ValueError as err: + if debug: # pragma: no cover + log.debug('do_validation: value: {0}, index: {1}:' + ' {2}'.format(_value, + _index, + err), + exc_info=True) + if is_warnings_only: + msg = _('attention, "{0}" could be an invalid {1} for "{2}"' + '').format(_value, + self._display_name, + self.impl_get_display_name()) else: msg = _('"{0}" is an invalid {1} for "{2}"' - '').format(_value, self._display_name, + '').format(_value, + self._display_name, self.impl_get_display_name()) - raise ValueError(msg) + err_msg = '{0}'.format(err) + if err_msg: + msg += ', {}'.format(err_msg) + if is_warnings_only: + warnings.warn_explicit(ValueWarning(msg, self), + ValueWarning, + self.__class__.__name__, 0) + else: + raise ValueError(msg) if is_multi is None: is_multi = self.impl_is_multi() if not is_multi: - return do_validation(value, None) + do_validation(value, None) elif force_index is not None: if self.impl_is_submulti(): - err = _is_not_unique(value) - if err: - return err - if not isinstance(value, list): - raise ValueError(_('invalid value "{0}" for "{1}" which' - ' must be a list').format( - value, self.impl_get_display_name())) + _is_not_unique(value) for idx, val in enumerate(value): - if isinstance(val, list): # pragma: no cover - raise ValueError(_('invalid value "{}" for "{}" ' - 'which must not be a list').format(val, - self.impl_get_display_name())) - err = do_validation(val, force_index) - if err: - return err + do_validation(val, + force_index) 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: @@ -441,44 +428,37 @@ class Option(OnlyOption): lst = multi if value in lst: raise ValueError(_('invalid value "{}", this value is already' - ' in "{}"').format(value, - self.impl_get_display_name())) - return do_validation(value, force_index) + ' in "{}"').format(value, + self.impl_get_display_name())) + do_validation(value, + force_index) elif not isinstance(value, list): raise ValueError(_('invalid value "{0}" for "{1}" which ' - 'must be a list').format(value, - self.impl_getname())) + 'must be a list').format(value, + self.impl_getname())) elif self.impl_is_submulti(): for idx, val in enumerate(value): - err = _is_not_unique(val) - if err: - return err + _is_not_unique(val) if not isinstance(val, list): raise ValueError(_('invalid value "{0}" for "{1}" ' - 'which must be a list of list' - '').format(val, - self.impl_getname())) + 'which must be a list of list' + '').format(val, + self.impl_getname())) for slave_val in val: - err = do_validation(slave_val, - idx) - if err: - return err + do_validation(slave_val, + idx) else: - err = _is_not_unique(value) - if err: - return err + _is_not_unique(value) for idx, val in enumerate(value): - err = do_validation(val, - idx) - if err: - return err - return self._valid_consistency(current_opt, - None, - context, - None, - display_warnings, - display_error, - setting_properties) + do_validation(val, + idx) + #self._valid_consistency(current_opt, + # None, + # context, + # None, + # display_warnings, + # display_error, + # setting_properties) def impl_is_dynsymlinkoption(self): return False @@ -634,18 +614,16 @@ class Option(OnlyOption): suffix)) else: opts = all_cons_opts - err = opts[0]()._launch_consistency(self, - func, - option, - value, - context, - index, - opts, - warnings_only, - transitive, - setting_properties) - if err: - return err + opts[0]()._launch_consistency(self, + func, + option, + value, + context, + index, + opts, + warnings_only, + transitive, + setting_properties) def _cons_not_equal(self, current_opt, diff --git a/tiramisu/option/optiondescription.py b/tiramisu/option/optiondescription.py index 17d4487..df333bb 100644 --- a/tiramisu/option/optiondescription.py +++ b/tiramisu/option/optiondescription.py @@ -163,11 +163,12 @@ class CacheOptionDescription(BaseOption): raise ConfigError(_('a dynoption ({0}) cannot have ' 'force_store_value property').format(subpath)) if force_store_values and not config._impl_values._p_.hasvalue(subpath, session): - value = config.cfgimpl_get_values().get_cached_value(option, - path=subpath, - validate=False, - trusted_cached_properties=False, - validate_properties=True) + value = impl_build_force_store_values.getvalue(option, + subpath, + index=None, + setting_properties=undefined, + self_properties=undefined, + validate=False) value_set = True config._impl_values._p_.setvalue(subpath, value, owners.forced, None, session, False) diff --git a/tiramisu/setting.py b/tiramisu/setting.py index 71a076b..708878a 100644 --- a/tiramisu/setting.py +++ b/tiramisu/setting.py @@ -610,9 +610,9 @@ class Settings(object): #mandatory if 'mandatory' in properties or 'empty' in properties: value = self._getcontext().cfgimpl_get_values().get_cached_value(opt, - path=path, + path, + setting_properties, validate=False, - setting_properties=setting_properties, self_properties=self_properties, index=index) if not self.validate_mandatory(opt, diff --git a/tiramisu/value.py b/tiramisu/value.py index 02ee9d6..aa1edd2 100644 --- a/tiramisu/value.py +++ b/tiramisu/value.py @@ -16,13 +16,11 @@ # along with this program. If not, see . # ____________________________________________________________ from time import time -import sys import weakref -from .error import ConfigError, SlaveError, PropertiesOptionError +from .error import ConfigError, PropertiesOptionError from .setting import owners, expires_time, undefined, forbidden_owners from .autolib import carry_out_calculation from .i18n import _ -from .option import DynSymLinkOption, Option class Values(object): @@ -30,24 +28,29 @@ class Values(object): but the values are physicaly located here, in `Values`, wich is also responsible of a caching utility. """ - __slots__ = ('context', '_p_', '__weakref__') + __slots__ = ('context', + '_p_', + '__weakref__') - def __init__(self, context, storage): + def __init__(self, + context, + storage): """ Initializes the values's dict. :param context: the context is the home config's values + :param storage: where values or owners are stored """ self.context = weakref.ref(context) - # the storage type is dictionary or sqlite3 + # store the storage self._p_ = storage #______________________________________________________________________ # get context def _getcontext(self): - """context could be None, we need to test it + """context is a weakref so context could be None, we need to test it context is None only if all reference to `Config` object is deleted (for example we delete a `Config` and we manipulate a reference to old `SubConfig`, `Values`, `Multi` or `Settings`) @@ -62,16 +65,33 @@ class Values(object): def get_cached_value(self, opt, - path=None, + path, + setting_properties, validate=True, force_permissive=False, - trusted_cached_properties=True, - setting_properties=undefined, self_properties=undefined, index=None, - display_warnings=True): + display_warnings=True, + trusted_cached_properties=True): + """get value directly in cache if set + otherwise calculated value and set it in cache + + :param opt: the `Option` that we want to get value + :param path: the path of the `Option` + :param validate: the value must be valid + :param force_permissive: force permissive when check properties + :param setting_properties: global properties + :param self_properties: properties for this `Option` + :param index: index for a slave `Option` + :param display_warnings: display warnings or not + :param trusted_cached_properties: get value from cache but not store it to value + + :returns: value + """ ntime = None - if 'cache' in setting_properties and self._p_.hascache(path, index): + # try to retrive value in cache + if 'cache' in setting_properties and self._p_.hascache(path, + index): if 'expire' in setting_properties: ntime = int(time()) is_cached, value = self._p_.getcache(path, @@ -81,39 +101,17 @@ class Values(object): value = value[index] if is_cached: return value - val = self.get_validated_value(opt, - path, - validate, - setting_properties, - self_properties, - index=index, - display_warnings=display_warnings, - force_permissive=force_permissive) - if index is None and 'cache' in setting_properties and \ - validate and force_permissive is False \ - and trusted_cached_properties is True: - if 'expire' in setting_properties: - if ntime is None: - ntime = int(time()) - ntime = ntime + expires_time - self._p_.setcache(path, val, ntime, None) - return val - def get_validated_value(self, - opt, - path, - validate, - setting_properties, - self_properties=undefined, - index=None, - display_warnings=True, - force_permissive=False): - """same has getitem but don't touch the cache - index is None for slave value, if value returned is not a list, just return [] - """ - context = self._getcontext() - config_error = None - try: + # no cached value so get value + if validate and 'validator' in setting_properties: + value = self.get_validated_value(opt, + path, + setting_properties, + self_properties, + index=index, + display_warnings=display_warnings, + force_permissive=force_permissive) + else: value = self.getvalue(opt, path, index, @@ -121,42 +119,61 @@ class Values(object): self_properties, validate, force_permissive=force_permissive) - except ConfigError as value: - value_error = True - # For calculating properties, we need value (ie for mandatory - # value). - # If value is calculating with a PropertiesOptionError's option - # getvalue raise a ConfigError. - # We can not raise ConfigError if this option should raise - # PropertiesOptionError too. So we get config_error and raise - # ConfigError if properties did not raise. - config_error = value - # value is not set, for 'undefined' (cannot set None because of - # mandatory property) - value = undefined - else: - value_error = False - if validate: - err = opt.impl_validate(value, - context, - 'validator' in setting_properties, - force_index=index, - display_error=True, - display_warnings=False, - setting_properties=setting_properties) - if err: - config_error = err - value = None - if not value_error and validate and display_warnings: + # store value in cache + #FIXME pas de cache pour les slaves !!! + if index is None and 'cache' in setting_properties and \ + validate and force_permissive is False \ + and trusted_cached_properties is True: + if 'expire' in setting_properties: + if ntime is None: + ntime = int(time()) + ntime = ntime + expires_time + self._p_.setcache(path, value, ntime, None) + # and return it + return value + + def get_validated_value(self, + opt, + path, + setting_properties, + self_properties=undefined, + index=None, + display_warnings=True, + force_permissive=False): + """get value and validate it + index is None for slave value, if value returned is not a list, just return [] + + :param opt: the `Option` that we want to get value + :param path: the path of the `Option` + :param setting_properties: global properties + :param self_properties: properties for this `Option` + :param index: index for a slave `Option` + :param display_warnings: display warnings or not + :param force_permissive: force permissive when check properties + + :returns: value + """ + value = self.getvalue(opt, + path, + index, + setting_properties, + self_properties, + validate=True, + force_permissive=force_permissive) + context = self._getcontext() + opt.impl_validate(value, + context, + force_index=index, + display_error=True, + display_warnings=False, + setting_properties=setting_properties) + if display_warnings: opt.impl_validate(value, context, - 'validator' in setting_properties, force_index=index, display_error=False, display_warnings=display_warnings, setting_properties=setting_properties) - if config_error is not None: - raise config_error return value def getvalue(self, @@ -169,19 +186,20 @@ class Values(object): force_permissive=False): """actually retrieves the value - :param opt: the `option.Option()` object - :returns: the option's value (or the default value if not set) + :param opt: the `Option` that we want to get value + :param path: the path of the `Option` + :param index: index for a slave `Option` + :param setting_properties: global properties + :param self_properties: properties for this `Option` + :param validate: validate value + :param force_permissive: force permissive when check properties + + :returns: value """ - if self_properties is undefined: - settings = self._getcontext().cfgimpl_get_settings() - self_properties = settings.getproperties(opt, - path, - setting_properties=setting_properties, - index=index) - force_default = 'frozen' in self_properties and \ - 'force_default_on_freeze' in self_properties - # not default value - if index is None or not opt.impl_is_master_slaves('slave'): + # get owner and value from store + # index allowed only for slave + is_slave = opt.impl_is_master_slaves('slave') + if index is None or not is_slave: _index = None else: _index = index @@ -189,15 +207,25 @@ class Values(object): owners.default, index=_index, with_value=True) - is_default = owner == owners.default - if not is_default and not force_default: - if index is not None and not opt.impl_is_master_slaves('slave'): - if len(value) > index: - return value[index] - #value is smaller than expected - #so return default value - else: - return value + + if owner != owners.default: + # if a value is store in storage, check if not frozen + force_default_on_freeze + # if frozen + force_default_on_freeze => force default value + if self_properties is undefined: + settings = self._getcontext().cfgimpl_get_settings() + self_properties = settings.getproperties(opt, + path, + setting_properties=setting_properties, + index=index) + if not ('frozen' in self_properties and \ + 'force_default_on_freeze' in self_properties): + if index is not None and not is_slave: + if len(value) > index: + return value[index] + #value is smaller than expected + #so return default value + else: + return value return self._getdefaultvalue(opt, path, index, @@ -688,8 +716,8 @@ class Values(object): validate=False) fake_value.get_cached_value(opt, path, + setting_properties, index=index, - setting_properties=setting_properties, force_permissive=force_permissive) self._p_.resetvalue_index(path, index) @@ -703,7 +731,7 @@ class Values(object): current_value = self.get_cached_value(opt, path, - setting_properties=setting_properties, + setting_properties, force_permissive=force_permissive) current_value.pop(index) self.setvalue(opt, @@ -791,22 +819,22 @@ class Values(object): path, setting_properties=setting_properties) if 'mandatory' in self_properties or 'empty' in self_properties: - err = self.get_cached_value(opt, - path=path, - trusted_cached_properties=False, - force_permissive=True, - setting_properties=setting_properties, - self_properties=self_properties, - validate=True, - display_warnings=False) - if opt.impl_is_master_slaves('slave') and isinstance(err, list): - for val in err: + values = self.get_cached_value(opt, + path, + setting_properties, + trusted_cached_properties=False, + force_permissive=True, + self_properties=self_properties, + validate=True, + display_warnings=False) + if opt.impl_is_master_slaves('slave') and isinstance(values, list): + for val in values: ret = _is_properties_option(val, path) if ret is not None: yield ret break else: - ret = _is_properties_option(err, path) + ret = _is_properties_option(values, path) if ret is not None: yield ret