diff --git a/test/test_choice_option.py b/test/test_choice_option.py index 680eec3..f6ac630 100644 --- a/test/test_choice_option.py +++ b/test/test_choice_option.py @@ -24,7 +24,7 @@ def return_calc_list(val): return [val] -def return_error(): +def return_error(*args, **kwargs): raise Exception('test') @@ -83,6 +83,24 @@ def test_choiceoption_function_error(): raises(ConfigError, "api.option('choice').value.set('val1')") +def test_choiceoption_function_error_args(): + choice = ChoiceOption('choice', '', values=return_error, values_params={'': ('val1',)}) + odesc = OptionDescription('od', '', [choice]) + cfg = Config(odesc) + api = getapi(cfg) + api.property.read_write() + raises(ConfigError, "api.option('choice').value.set('val1')") + + +def test_choiceoption_function_error_kwargs(): + choice = ChoiceOption('choice', '', values=return_error, values_params={'kwargs': ('val1',)}) + odesc = OptionDescription('od', '', [choice]) + cfg = Config(odesc) + api = getapi(cfg) + api.property.read_write() + raises(ConfigError, "api.option('choice').value.set('val1')") + + def test_choiceoption_calc_function(): choice = ChoiceOption('choice', "", values=return_calc_list, values_params={'': ('val1',)}) odesc = OptionDescription('od', '', [choice]) diff --git a/test/test_config_api.py b/test/test_config_api.py index 1da2b68..2f01c3f 100644 --- a/test/test_config_api.py +++ b/test/test_config_api.py @@ -195,6 +195,11 @@ def test_find_in_config(): assert len(ret) == 1 _is_same_opt(ret[0].option.get(), api.option('gc.prop').option.get()) # + ret = api.option.find('prop', value=None) + ret = api.option.find('prop') + assert len(ret) == 1 + _is_same_opt(ret[0].option.get(), api.option('gc.prop').option.get()) + # api.property.read_write() raises(AttributeError, "assert api.option.find('prop').option.get()") ret = api.unrestraint.option.find(name='prop') diff --git a/test/test_metaconfig.py b/test/test_metaconfig.py index 8020552..c3da53e 100644 --- a/test/test_metaconfig.py +++ b/test/test_metaconfig.py @@ -48,6 +48,11 @@ def make_metaconfig(double=False): return api +def test_unknown_config(): + api = make_metaconfig() + raises(ConfigError, "api.config('unknown')") + + #FIXME ne pas mettre 2 meta dans une config #FIXME ne pas mettre 2 OD differents dans un meta def test_none(): diff --git a/test/test_option_callback.py b/test/test_option_callback.py index 6162a72..e7a47ef 100644 --- a/test/test_option_callback.py +++ b/test/test_option_callback.py @@ -10,6 +10,7 @@ from tiramisu import ChoiceOption, BoolOption, IntOption, FloatOption, \ getapi, undefined from tiramisu.api import TIRAMISU_VERSION from tiramisu.error import PropertiesOptionError, ConflictError, SlaveError, ConfigError +from tiramisu.i18n import _ def return_val(): @@ -652,7 +653,13 @@ def test_consistency_master_and_slaves_master_mandatory_transitive(): maconfig = OptionDescription('rootconfig', '', [interface1, interface2]) api = getapi(Config(maconfig)) api.property.read_write() - raises(PropertiesOptionError, "api.option('val1.val1').value.get()") + err = None + try: + api.option('val1.val1').value.get() + except PropertiesOptionError as error: + err = error + assert err, 'should raises' + assert str(err) == str(_('cannot access to {0} "{1}" because "{2}" has {3} {4}').format('option', 'val1', 'val2', 'property', '"disabled"')) raises(PropertiesOptionError, "api.option('val3.val3').value.get()") assert list(api.value.mandatory_warnings()) == [] diff --git a/test/test_requires.py b/test/test_requires.py index 5fefded..04f2b10 100644 --- a/test/test_requires.py +++ b/test/test_requires.py @@ -3,6 +3,7 @@ from .autopath import do_autopath do_autopath() from copy import copy +from tiramisu.i18n import _ from tiramisu.setting import groups from tiramisu import setting setting.expires_time = 1 @@ -93,16 +94,17 @@ def test_requires_invalid(): def test_requires_same_action(): - a = BoolOption('activate_service', '', True) - b = BoolOption('activate_service_web', '', True, - requires=[{'option': a, 'expected': False, 'action': 'new'}]) + activate_service = BoolOption('activate_service', '', True) + activate_service_web = BoolOption('activate_service_web', '', True, + requires=[{'option': activate_service, 'expected': False, + 'action': 'new'}]) - d = IPOption('ip_address_service_web', '', - requires=[{'option': b, 'expected': False, - 'action': 'disabled', 'inverse': False, - 'transitive': True, 'same_action': False}]) - od = OptionDescription('service', '', [a, b, d]) - api = getapi(Config(od)) + ip_address_service_web = IPOption('ip_address_service_web', '', + requires=[{'option': activate_service_web, 'expected': False, + 'action': 'disabled', 'inverse': False, + 'transitive': True, 'same_action': False}]) + od1 = OptionDescription('service', '', [activate_service, activate_service_web, ip_address_service_web]) + api = getapi(Config(od1)) api.property.read_write() api.property.add('new') api.option('activate_service').value.get() @@ -122,6 +124,8 @@ def test_requires_same_action(): api.option('ip_address_service_web').value.get() except PropertiesOptionError as err: props = err.proptype + submsg = '"disabled" (' + _('the value of "{0}" is {1}').format('activate_service', '"False"') + ')' + assert str(err) == str(_('cannot access to {0} "{1}" because has {2} {3}').format('option', 'ip_address_service_web', 'property', submsg)) assert frozenset(props) == frozenset(['disabled']) diff --git a/tiramisu/api.py b/tiramisu/api.py index 2940224..24b240e 100644 --- a/tiramisu/api.py +++ b/tiramisu/api.py @@ -662,7 +662,6 @@ class TiramisuOption(CommonTiramisu): for path in self.config_bag.config.find(byname=name, byvalue=value, bytype=None, - type_='path', _subpath=self.path, config_bag=self.config_bag): config_bag = self.config_bag.copy('nooption') @@ -900,7 +899,6 @@ class TiramisuContextOption(TiramisuContext): for path in self.config_bag.config.find(byname=name, byvalue=value, bytype=None, - type_='path', #_subpath=self.path, config_bag=self.config_bag): config_bag = self.config_bag.copy('nooption') diff --git a/tiramisu/config.py b/tiramisu/config.py index d76d4b2..e92c9cb 100644 --- a/tiramisu/config.py +++ b/tiramisu/config.py @@ -185,7 +185,7 @@ class SubConfig(object): `setting.groups` """ if group_type is not None and not isinstance(group_type, - groups.GroupType): # pragma: optional cover + groups.GroupType): raise TypeError(_("unknown group_type: {0}").format(group_type)) for child in self.cfgimpl_get_description().impl_getchildren(config_bag): if child.impl_is_optiondescription(): @@ -199,7 +199,7 @@ class SubConfig(object): yield name, self.getattr(name, None, nconfig_bag) - except PropertiesOptionError: # pragma: optional cover + except PropertiesOptionError: pass def cfgimpl_get_children(self, @@ -227,12 +227,12 @@ class SubConfig(object): old `SubConfig`, `Values`, `Multi` or `Settings`) """ context = self._impl_context() - if context is None: # pragma: optional cover + if context is None: # pragma: no cover raise ConfigError(_('the context does not exist anymore')) return context def cfgimpl_get_description(self): - if self._impl_descr is None: # pragma: optional cover + if self._impl_descr is None: raise ConfigError(_('no option description found for this config' ' (may be GroupConfig)')) else: @@ -252,7 +252,7 @@ class SubConfig(object): _commit=True): context = self.cfgimpl_get_context() - if '.' in name: # pragma: optional cover + if '.' in name: # when set_value self, name = self.cfgimpl_get_home_by_path(name, config_bag) @@ -281,7 +281,7 @@ class SubConfig(object): name, index, config_bag): - if '.' in name: # pragma: optional cover + if '.' in name: self, name = self.cfgimpl_get_home_by_path(name, config_bag) option = config_bag.option @@ -385,7 +385,6 @@ class SubConfig(object): byname, byvalue, config_bag, - type_='option', _subpath=None, raise_if_not_found=True, only_path=undefined, @@ -397,8 +396,6 @@ class SubConfig(object): :return: find list or an exception if nothing has been found """ def _filter_by_value(sconfig_bag): - if byvalue is undefined: - return True try: value = self.getattr(path, None, @@ -410,9 +407,6 @@ class SubConfig(object): else: return value == byvalue - if type_ not in ('option', 'path', 'value'): # pragma: optional cover - raise ValueError(_('unknown type_ type {0}' - 'for find').format(type_)) found = False if only_path is not undefined: options = [(only_path, only_option)] @@ -424,10 +418,10 @@ class SubConfig(object): for path, option in options: sconfig_bag = config_bag.copy('nooption') sconfig_bag.option = option - if not _filter_by_value(sconfig_bag): + if byvalue is not undefined and not _filter_by_value(sconfig_bag): continue - #remove option with propertyerror, ... - if sconfig_bag.validate_properties: + elif sconfig_bag.validate_properties: + #remove option with propertyerror, ... try: self.unwrap_from_path(path, sconfig_bag) @@ -436,18 +430,10 @@ class SubConfig(object): sconfig_bag) except PropertiesOptionError: continue - if type_ == 'value': - retval = self.getattr(path, - None, - sconfig_bag) - elif type_ == 'path': - retval = path - elif type_ == 'option': - retval = option found = True - yield retval - return self._find_return_results(found, - raise_if_not_found) + yield path + self._find_return_results(found, + raise_if_not_found) def _find_return_results(self, found, @@ -502,7 +488,7 @@ class SubConfig(object): pathsvalues = [] if _currpath is None: _currpath = [] - if withoption is None and withvalue is not undefined: # pragma: optional cover + if withoption is None and withvalue is not undefined: raise ValueError(_("make_dict can't filtering with value without " "option")) context = self.cfgimpl_get_context() @@ -510,7 +496,6 @@ class SubConfig(object): for path in context.find(bytype=None, byname=withoption, byvalue=withvalue, - type_='path', _subpath=self.cfgimpl_get_path(False), config_bag=config_bag): path = '.'.join(path.split('.')[:-1]) @@ -526,7 +511,7 @@ class SubConfig(object): break else: tmypath = mypath + '.' - if not path.startswith(tmypath): # pragma: optional cover + if not path.startswith(tmypath): raise AttributeError(_('unexpected path {0}, ' 'should start with {1}' '').format(path, mypath)) @@ -751,7 +736,7 @@ class Config(_CommonConfig): properties, permissives, values, session_id = get_storages(self, session_id, persistent) - if not valid_name(session_id): # pragma: optional cover + if not valid_name(session_id): raise ValueError(_("invalid session ID: {0} for config").format(session_id)) self._impl_settings = Settings(self, properties, @@ -869,7 +854,15 @@ class GroupConfig(_CommonConfig): nconfig_bag, _commit=False) except PropertiesOptionError as err: - ret.append(PropertiesOptionError(str(err), err.proptype)) + ret.append(PropertiesOptionError(err._path, + err._index, + err._config_bag, + err.proptype, + err._settings, + err._opt_type, + err._requires, + err._name, + err._orig_opt)) except (ValueError, SlaveError) as err: ret.append(err) if _commit: @@ -896,7 +889,6 @@ class GroupConfig(_CommonConfig): byvalue=undefined, byname=byname, config_bag=config_bag, - type_='path', raise_if_not_found=raise_if_not_found)) byname = None byoption = self.cfgimpl_get_description().impl_get_opt_by_path(bypath) @@ -918,7 +910,6 @@ class GroupConfig(_CommonConfig): next(child.find(None, byname, byvalue, - type_='path', config_bag=config_bag, raise_if_not_found=False, only_path=bypath, @@ -935,22 +926,13 @@ class GroupConfig(_CommonConfig): def impl_getname(self): return self._impl_name -# def __str__(self): -# ret = '' -# for child in self._impl_children: -# ret += "({0})\n".format(child._impl_name) -# if self._impl_descr is not None: -# ret += super(GroupConfig, self).__str__() -# return ret -# -# __repr__ = __str__ def getconfig(self, name): for child in self._impl_children: if name == child.impl_getname(): return child - raise ConfigError(_('unknown config {}').format(name)) + raise ConfigError(_('unknown config "{}"').format(name)) class MetaConfig(GroupConfig): diff --git a/tiramisu/error.py b/tiramisu/error.py index aad4d1a..f278148 100644 --- a/tiramisu/error.py +++ b/tiramisu/error.py @@ -55,27 +55,48 @@ def display_list(lst, separator='and', add_quote=False): class PropertiesOptionError(AttributeError): "attempt to access to an option with a property that is not allowed" def __init__(self, - msg, + path, + index, + config_bag, proptype, - settings=None, - datas=None, - option_type=None): + settings, + opt_type=None, + requires=None, + name=None, + orig_opt=None): + self._path = path + self._index = index + if opt_type: + self._opt_type = opt_type + self._requires = requires + self._name = name + self._orig_opt = orig_opt + else: + if config_bag.option.impl_is_optiondescription(): + self._opt_type = 'optiondescription' + else: + self._opt_type = 'option' + self._requires = config_bag.option.impl_getrequires() + self._name = config_bag.option.impl_get_display_name() + self._orig_opt = None + self._config_bag = config_bag.copy('nooption') self.proptype = proptype self._settings = settings - self._datas = datas - self._type = option_type - self._orig_opt = None - super(PropertiesOptionError, self).__init__(msg) + self.msg = None + super(PropertiesOptionError, self).__init__(None) def set_orig_opt(self, opt): self._orig_opt = opt def __str__(self): #this part is a bit slow, so only execute when display - if self._settings is None: - req = {} - else: - req = self._settings.apply_requires(**self._datas) + if self.msg: + return self.msg + req = self._settings.apply_requires(self._path, + self._requires, + self._index, + True, + self._config_bag) #if req != {} or self._orig_opt is not None: if req != {}: only_one = len(req) == 1 @@ -91,17 +112,20 @@ class PropertiesOptionError(AttributeError): else: prop_msg = _('properties') if self._orig_opt: - return str(_('cannot access to {0} "{1}" because "{2}" has {3} {4}' - '').format(self._type, - self._orig_opt.impl_get_display_name(), - self._datas['config_bag'].option.impl_get_display_name(), + self.msg = str(_('cannot access to {0} "{1}" because "{2}" has {3} {4}' + '').format(self._opt_type, + self._orig_opt.impl_get_display_name(), + self._name, + prop_msg, + msg)) + self.msg = str(_('cannot access to {0} "{1}" because has {2} {3}' + '').format(self._opt_type, + self._name, prop_msg, msg)) - return str(_('cannot access to {0} "{1}" because has {2} {3}' - '').format(self._type, - self._datas['config_bag'].option.impl_get_display_name(), - prop_msg, - msg)) + del self._path, self._index, self._requires, self._opt_type, self._name, self._config_bag + del self._settings, self._orig_opt + return self.msg #____________________________________________________________ diff --git a/tiramisu/option/baseoption.py b/tiramisu/option/baseoption.py index 0727a34..3188623 100644 --- a/tiramisu/option/baseoption.py +++ b/tiramisu/option/baseoption.py @@ -25,7 +25,7 @@ from inspect import signature from ..i18n import _ from ..setting import undefined -from ..error import ConfigError +from ..error import ConfigError, display_list STATIC_TUPLE = frozenset() @@ -162,7 +162,7 @@ class Base(object): set_forbidden_properties = calc_properties & properties if set_forbidden_properties != frozenset(): raise ValueError(_('conflict: properties already set in ' - 'requirement {0}').format(list(set_forbidden_properties))) + 'requirement {0}').format(display_list(list(set_forbidden_properties)))) _setattr = object.__setattr__ _setattr(self, '_name', name) _setattr(self, '_informations', {'doc': doc}) @@ -249,10 +249,9 @@ class Base(object): if calculator_args or calculator_kwargs: # there is more args/kwargs than expected! raise ConfigError(_('cannot find those arguments "{}" in function "{}" for "{}"' - '').format(list(calculator_args | calculator_kwargs), + '').format(display_list(list(calculator_args | calculator_kwargs)), calculator.__name__, self.impl_get_display_name())) - has_self = False has_index = False if is_multi and func_args: # there is extra args/kwargs @@ -267,16 +266,13 @@ class Base(object): has_index = True params.append(('index',)) func_args.pop() - if func_args: - raise ConfigError(_('missing those arguements "{}" in function "{}" for "{}"' - '').format(list(func_args), - calculator.__name__, - self.impl_get_display_name())) calculator_params[''] = tuple(params) + if func_args: + raise ConfigError(_('missing those arguments "{}" in function "{}" for "{}"' + '').format(display_list(list(func_args)), + calculator.__name__, + self.impl_get_display_name())) if not self.impl_is_optiondescription() and self.impl_is_multi(): - if add_value and not has_self and 'self' in func_kwargs: - # only for validator - calculator_params['self'] = (self, False) if not has_index and 'index' in func_kwargs: calculator_params['index'] = (('index',),) return calculator_params @@ -573,8 +569,9 @@ def validate_requires_arg(new_option, option = exp['option'] option._add_dependency(new_option) if option is not None: - err = option._validate(exp['value'], undefined) - if err: + try: + option._validate(exp['value'], undefined) + except ValueError as err: raise ValueError(_('malformed requirements expected value ' 'must be valid for option {0}' ': {1}').format(name, err)) @@ -588,11 +585,13 @@ def validate_requires_arg(new_option, else: option = get_option(require) if expected is not None: - err = option._validate(expected, undefined) - if err: + try: + option._validate(expected, undefined) + except ValueError as err: raise ValueError(_('malformed requirements expected value ' 'must be valid for option {0}' ': {1}').format(name, err)) + option._add_dependency(new_option) _set_expected(action, inverse, transitive, diff --git a/tiramisu/setting.py b/tiramisu/setting.py index e1a8b8f..83e39c8 100644 --- a/tiramisu/setting.py +++ b/tiramisu/setting.py @@ -373,6 +373,7 @@ class Settings(object): apply_requires) if apply_requires: props |= self.apply_requires(path, + opt.impl_getrequires(), index, False, config_bag) @@ -405,9 +406,11 @@ class Settings(object): def apply_requires(self, path, + current_requires, index, - debug, - config_bag): + readable, + config_bag, + name=None): """carries out the jit (just in time) requirements between options a requirement is a tuple of this form that comes from the option's @@ -451,11 +454,10 @@ class Settings(object): :param path: the option's path in the config :type path: str """ - opt = config_bag.option - current_requires = opt.impl_getrequires() + #current_requires = opt.impl_getrequires() # filters the callbacks - if debug: + if readable: calc_properties = {} else: calc_properties = set() @@ -467,25 +469,21 @@ class Settings(object): all_properties = None for requires in current_requires: for require in requires: - exps, action, inverse, \ - transitive, same_action, operator = require + exps, action, inverse, transitive, same_action, operator = require breaked = False - for exp in exps: - option, expected = exp + for option, expected in exps: reqpath = option.impl_getpath(context) - if reqpath == path or reqpath.startswith(path + '.'): # pragma: optional cover + #FIXME c'est un peut tard ! + if reqpath == path or reqpath.startswith(path + '.'): raise RequirementError(_("malformed requirements " "imbrication detected for option:" " '{0}' with requirement on: " "'{1}'").format(path, reqpath)) - if not option.impl_is_multi(): - idx = None - is_indexed = False - elif option.impl_is_master_slaves('slave'): + idx = None + is_indexed = False + if option.impl_is_master_slaves('slave'): idx = index - is_indexed = False - else: - idx = None + elif option.impl_is_multi(): is_indexed = True sconfig_bag = config_bag.copy('nooption') sconfig_bag.option = option @@ -497,40 +495,44 @@ class Settings(object): if is_indexed: value = value[index] except PropertiesOptionError as err: + properties = err.proptype if not transitive: if all_properties is None: all_properties = [] - for requires_ in opt.impl_getrequires(): + for requires_ in current_requires: for require_ in requires_: all_properties.append(require_[1]) - if not set(err.proptype) - set(all_properties): + if not set(properties) - set(all_properties): continue - properties = err.proptype - if same_action and action not in properties: # pragma: optional cover + if same_action and action not in properties: if len(properties) == 1: prop_msg = _('property') else: prop_msg = _('properties') raise RequirementError(_('cannot access to option "{0}" because ' 'required option "{1}" has {2} {3}' - '').format(opt.impl_get_display_name(), + '').format(name, option.impl_get_display_name(), prop_msg, display_list(list(properties)))) - orig_value = err - # transitive action, force expected - value = expected[0] - inverse = False - else: - orig_value = value - if (not inverse and value in expected or - inverse and value not in expected): + # transitive action, add action if operator != 'and': - if debug: - if isinstance(orig_value, PropertiesOptionError): - for msg in orig_value._settings.apply_requires(**orig_value._datas).values(): - calc_properties.setdefault(action, []).extend(msg) - else: + if readable: + for msg in self.apply_requires(err.path, + err.requires, + err.index, + True, + err.config_bag).values(): + calc_properties.setdefault(action, []).extend(msg) + else: + calc_properties.add(action) + breaked = True + break + else: + if (not inverse and value in expected or + inverse and value not in expected): + if operator != 'and': + if readable: if not inverse: msg = _('the value of "{0}" is {1}') else: @@ -538,12 +540,12 @@ class Settings(object): calc_properties.setdefault(action, []).append( msg.format(option.impl_get_display_name(), display_list(expected, 'or', add_quote=True))) - else: - calc_properties.add(action) - breaked = True - break - elif operator == 'and': - break + else: + calc_properties.add(action) + breaked = True + break + elif operator == 'and': + break else: if operator == 'and': calc_properties.add(action) @@ -691,11 +693,6 @@ class Settings(object): config_bag) config_bag.properties = self_properties properties = self_properties & config_bag.setting_properties - {'frozen', 'mandatory', 'empty'} - if not opt.impl_is_optiondescription(): - opt_type = 'option' - else: - opt_type = 'optiondescription' - # remove permissive properties if (config_bag.force_permissive is True or 'permissive' in config_bag.setting_properties) and properties: @@ -703,15 +700,11 @@ class Settings(object): properties -= self.get_context_permissive() # at this point an option should not remain in properties if properties != frozenset(): - datas = {'path': path, - 'config_bag': config_bag, - 'index': index, - 'debug': True} - raise PropertiesOptionError(None, + raise PropertiesOptionError(path, + index, + config_bag, properties, - self, - datas, - opt_type) + self) def validate_mandatory(self, path, @@ -735,17 +728,15 @@ class Settings(object): index=index): is_mandatory = True if is_mandatory: - datas = {'path': path, - 'config_bag': config_bag, - 'index': index, - 'debug': True} - raise PropertiesOptionError(None, + raise PropertiesOptionError(path, + index, + config_bag, ['mandatory'], - self, - datas, - 'option') + self) def validate_frozen(self, + path, + index, config_bag): if config_bag.setting_properties and \ ('everything_frozen' in config_bag.setting_properties or @@ -753,7 +744,11 @@ class Settings(object): not ((config_bag.force_permissive is True or 'permissive' in config_bag.setting_properties) and 'frozen' in self.get_context_permissive()): - return True + raise PropertiesOptionError(path, + index, + config_bag, + ['frozen'], + self) return False #____________________________________________________________ # read only/read write diff --git a/tiramisu/value.py b/tiramisu/value.py index cabe51d..966a70c 100644 --- a/tiramisu/value.py +++ b/tiramisu/value.py @@ -56,7 +56,7 @@ class Values(object): old `SubConfig`, `Values`, `Multi` or `Settings`) """ context = self.context() - if context is None: + if context is None: # pragma: no cover raise ConfigError(_('the context does not exist anymore')) return context @@ -242,7 +242,7 @@ class Values(object): # if value is a list and index is set if opt.impl_is_submulti() and (value == [] or not isinstance(value[0], list)): # return value only if it's a submulti and not a list of list - _reset_cache(value,) + _reset_cache(value) return value if len(value) > index: @@ -251,28 +251,20 @@ class Values(object): return value[index] # there is no calculate value for this index, # so return an other default value - elif isinstance(value, list): - # value is a list, but no index specified - if opt.impl_is_submulti() and (value != [] and not isinstance(value[0], list)): - # if submulti, return a list of value - value = [value] - _reset_cache(value) - return value - # otherwise just return the value - return value - elif index is not None: - # if not list but with index - if opt.impl_is_submulti(): - # if submulti, return a list of value - value = [value] - _reset_cache(value) - return value else: - # not a list or index is None if opt.impl_is_submulti(): - # return a list of list for a submulti - value = [[value]] - elif opt.impl_is_multi(): + if isinstance(value, list): + # value is a list, but no index specified + if (value != [] and not isinstance(value[0], list)): + # if submulti, return a list of value + value = [value] + elif index is not None: + # if submulti, return a list of value + value = [value] + else: + # return a list of list for a submulti + value = [[value]] + elif opt.impl_is_multi() and not isinstance(value, list) and index is None: # return a list for a multi value = [value] _reset_cache(value) @@ -375,16 +367,9 @@ class Values(object): config_bag) config_bag.properties = self_properties opt = config_bag.option - if settings.validate_frozen(config_bag): - datas = {'path': path, - 'config_bag': config_bag, - 'index': index, - 'debug': True} - raise PropertiesOptionError(None, - ['frozen'], - settings, - datas, - 'option') + settings.validate_frozen(path, + index, + config_bag) settings.validate_mandatory(path, index, value, @@ -673,16 +658,9 @@ class Values(object): None, config_bag) config_bag.properties = self_properties - if settings.validate_frozen(config_bag): - datas = {'path': path, - 'config_bag': config_bag, - 'index': index, - 'debug': True} - raise PropertiesOptionError(None, - ['frozen'], - settings, - datas, - 'option') + settings.validate_frozen(path, + index, + config_bag) #______________________________________________________________________ # information