simplify find() in api and PropertiesOptionError

This commit is contained in:
Emmanuel Garette 2018-04-10 22:42:20 +02:00
parent 5eb2f04202
commit 9e378faef0
11 changed files with 213 additions and 198 deletions

View File

@ -24,7 +24,7 @@ def return_calc_list(val):
return [val] return [val]
def return_error(): def return_error(*args, **kwargs):
raise Exception('test') raise Exception('test')
@ -83,6 +83,24 @@ def test_choiceoption_function_error():
raises(ConfigError, "api.option('choice').value.set('val1')") 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(): def test_choiceoption_calc_function():
choice = ChoiceOption('choice', "", values=return_calc_list, values_params={'': ('val1',)}) choice = ChoiceOption('choice', "", values=return_calc_list, values_params={'': ('val1',)})
odesc = OptionDescription('od', '', [choice]) odesc = OptionDescription('od', '', [choice])

View File

@ -195,6 +195,11 @@ def test_find_in_config():
assert len(ret) == 1 assert len(ret) == 1
_is_same_opt(ret[0].option.get(), api.option('gc.prop').option.get()) _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() api.property.read_write()
raises(AttributeError, "assert api.option.find('prop').option.get()") raises(AttributeError, "assert api.option.find('prop').option.get()")
ret = api.unrestraint.option.find(name='prop') ret = api.unrestraint.option.find(name='prop')

View File

@ -48,6 +48,11 @@ def make_metaconfig(double=False):
return api 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 meta dans une config
#FIXME ne pas mettre 2 OD differents dans un meta #FIXME ne pas mettre 2 OD differents dans un meta
def test_none(): def test_none():

View File

@ -10,6 +10,7 @@ from tiramisu import ChoiceOption, BoolOption, IntOption, FloatOption, \
getapi, undefined getapi, undefined
from tiramisu.api import TIRAMISU_VERSION from tiramisu.api import TIRAMISU_VERSION
from tiramisu.error import PropertiesOptionError, ConflictError, SlaveError, ConfigError from tiramisu.error import PropertiesOptionError, ConflictError, SlaveError, ConfigError
from tiramisu.i18n import _
def return_val(): def return_val():
@ -652,7 +653,13 @@ def test_consistency_master_and_slaves_master_mandatory_transitive():
maconfig = OptionDescription('rootconfig', '', [interface1, interface2]) maconfig = OptionDescription('rootconfig', '', [interface1, interface2])
api = getapi(Config(maconfig)) api = getapi(Config(maconfig))
api.property.read_write() 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()") raises(PropertiesOptionError, "api.option('val3.val3').value.get()")
assert list(api.value.mandatory_warnings()) == [] assert list(api.value.mandatory_warnings()) == []

View File

@ -3,6 +3,7 @@ from .autopath import do_autopath
do_autopath() do_autopath()
from copy import copy from copy import copy
from tiramisu.i18n import _
from tiramisu.setting import groups from tiramisu.setting import groups
from tiramisu import setting from tiramisu import setting
setting.expires_time = 1 setting.expires_time = 1
@ -93,16 +94,17 @@ def test_requires_invalid():
def test_requires_same_action(): def test_requires_same_action():
a = BoolOption('activate_service', '', True) activate_service = BoolOption('activate_service', '', True)
b = BoolOption('activate_service_web', '', True, activate_service_web = BoolOption('activate_service_web', '', True,
requires=[{'option': a, 'expected': False, 'action': 'new'}]) requires=[{'option': activate_service, 'expected': False,
'action': 'new'}])
d = IPOption('ip_address_service_web', '', ip_address_service_web = IPOption('ip_address_service_web', '',
requires=[{'option': b, 'expected': False, requires=[{'option': activate_service_web, 'expected': False,
'action': 'disabled', 'inverse': False, 'action': 'disabled', 'inverse': False,
'transitive': True, 'same_action': False}]) 'transitive': True, 'same_action': False}])
od = OptionDescription('service', '', [a, b, d]) od1 = OptionDescription('service', '', [activate_service, activate_service_web, ip_address_service_web])
api = getapi(Config(od)) api = getapi(Config(od1))
api.property.read_write() api.property.read_write()
api.property.add('new') api.property.add('new')
api.option('activate_service').value.get() api.option('activate_service').value.get()
@ -122,6 +124,8 @@ def test_requires_same_action():
api.option('ip_address_service_web').value.get() api.option('ip_address_service_web').value.get()
except PropertiesOptionError as err: except PropertiesOptionError as err:
props = err.proptype 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']) assert frozenset(props) == frozenset(['disabled'])

View File

@ -662,7 +662,6 @@ class TiramisuOption(CommonTiramisu):
for path in self.config_bag.config.find(byname=name, for path in self.config_bag.config.find(byname=name,
byvalue=value, byvalue=value,
bytype=None, bytype=None,
type_='path',
_subpath=self.path, _subpath=self.path,
config_bag=self.config_bag): config_bag=self.config_bag):
config_bag = self.config_bag.copy('nooption') config_bag = self.config_bag.copy('nooption')
@ -900,7 +899,6 @@ class TiramisuContextOption(TiramisuContext):
for path in self.config_bag.config.find(byname=name, for path in self.config_bag.config.find(byname=name,
byvalue=value, byvalue=value,
bytype=None, bytype=None,
type_='path',
#_subpath=self.path, #_subpath=self.path,
config_bag=self.config_bag): config_bag=self.config_bag):
config_bag = self.config_bag.copy('nooption') config_bag = self.config_bag.copy('nooption')

View File

@ -185,7 +185,7 @@ class SubConfig(object):
`setting.groups` `setting.groups`
""" """
if group_type is not None and not isinstance(group_type, 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)) raise TypeError(_("unknown group_type: {0}").format(group_type))
for child in self.cfgimpl_get_description().impl_getchildren(config_bag): for child in self.cfgimpl_get_description().impl_getchildren(config_bag):
if child.impl_is_optiondescription(): if child.impl_is_optiondescription():
@ -199,7 +199,7 @@ class SubConfig(object):
yield name, self.getattr(name, yield name, self.getattr(name,
None, None,
nconfig_bag) nconfig_bag)
except PropertiesOptionError: # pragma: optional cover except PropertiesOptionError:
pass pass
def cfgimpl_get_children(self, def cfgimpl_get_children(self,
@ -227,12 +227,12 @@ class SubConfig(object):
old `SubConfig`, `Values`, `Multi` or `Settings`) old `SubConfig`, `Values`, `Multi` or `Settings`)
""" """
context = self._impl_context() 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')) raise ConfigError(_('the context does not exist anymore'))
return context return context
def cfgimpl_get_description(self): 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' raise ConfigError(_('no option description found for this config'
' (may be GroupConfig)')) ' (may be GroupConfig)'))
else: else:
@ -252,7 +252,7 @@ class SubConfig(object):
_commit=True): _commit=True):
context = self.cfgimpl_get_context() context = self.cfgimpl_get_context()
if '.' in name: # pragma: optional cover if '.' in name:
# when set_value # when set_value
self, name = self.cfgimpl_get_home_by_path(name, self, name = self.cfgimpl_get_home_by_path(name,
config_bag) config_bag)
@ -281,7 +281,7 @@ class SubConfig(object):
name, name,
index, index,
config_bag): config_bag):
if '.' in name: # pragma: optional cover if '.' in name:
self, name = self.cfgimpl_get_home_by_path(name, self, name = self.cfgimpl_get_home_by_path(name,
config_bag) config_bag)
option = config_bag.option option = config_bag.option
@ -385,7 +385,6 @@ class SubConfig(object):
byname, byname,
byvalue, byvalue,
config_bag, config_bag,
type_='option',
_subpath=None, _subpath=None,
raise_if_not_found=True, raise_if_not_found=True,
only_path=undefined, only_path=undefined,
@ -397,8 +396,6 @@ class SubConfig(object):
:return: find list or an exception if nothing has been found :return: find list or an exception if nothing has been found
""" """
def _filter_by_value(sconfig_bag): def _filter_by_value(sconfig_bag):
if byvalue is undefined:
return True
try: try:
value = self.getattr(path, value = self.getattr(path,
None, None,
@ -410,9 +407,6 @@ class SubConfig(object):
else: else:
return value == byvalue 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 found = False
if only_path is not undefined: if only_path is not undefined:
options = [(only_path, only_option)] options = [(only_path, only_option)]
@ -424,10 +418,10 @@ class SubConfig(object):
for path, option in options: for path, option in options:
sconfig_bag = config_bag.copy('nooption') sconfig_bag = config_bag.copy('nooption')
sconfig_bag.option = option sconfig_bag.option = option
if not _filter_by_value(sconfig_bag): if byvalue is not undefined and not _filter_by_value(sconfig_bag):
continue continue
#remove option with propertyerror, ... elif sconfig_bag.validate_properties:
if sconfig_bag.validate_properties: #remove option with propertyerror, ...
try: try:
self.unwrap_from_path(path, self.unwrap_from_path(path,
sconfig_bag) sconfig_bag)
@ -436,18 +430,10 @@ class SubConfig(object):
sconfig_bag) sconfig_bag)
except PropertiesOptionError: except PropertiesOptionError:
continue continue
if type_ == 'value':
retval = self.getattr(path,
None,
sconfig_bag)
elif type_ == 'path':
retval = path
elif type_ == 'option':
retval = option
found = True found = True
yield retval yield path
return self._find_return_results(found, self._find_return_results(found,
raise_if_not_found) raise_if_not_found)
def _find_return_results(self, def _find_return_results(self,
found, found,
@ -502,7 +488,7 @@ class SubConfig(object):
pathsvalues = [] pathsvalues = []
if _currpath is None: if _currpath is None:
_currpath = [] _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 " raise ValueError(_("make_dict can't filtering with value without "
"option")) "option"))
context = self.cfgimpl_get_context() context = self.cfgimpl_get_context()
@ -510,7 +496,6 @@ class SubConfig(object):
for path in context.find(bytype=None, for path in context.find(bytype=None,
byname=withoption, byname=withoption,
byvalue=withvalue, byvalue=withvalue,
type_='path',
_subpath=self.cfgimpl_get_path(False), _subpath=self.cfgimpl_get_path(False),
config_bag=config_bag): config_bag=config_bag):
path = '.'.join(path.split('.')[:-1]) path = '.'.join(path.split('.')[:-1])
@ -526,7 +511,7 @@ class SubConfig(object):
break break
else: else:
tmypath = mypath + '.' tmypath = mypath + '.'
if not path.startswith(tmypath): # pragma: optional cover if not path.startswith(tmypath):
raise AttributeError(_('unexpected path {0}, ' raise AttributeError(_('unexpected path {0}, '
'should start with {1}' 'should start with {1}'
'').format(path, mypath)) '').format(path, mypath))
@ -751,7 +736,7 @@ class Config(_CommonConfig):
properties, permissives, values, session_id = get_storages(self, properties, permissives, values, session_id = get_storages(self,
session_id, session_id,
persistent) 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)) raise ValueError(_("invalid session ID: {0} for config").format(session_id))
self._impl_settings = Settings(self, self._impl_settings = Settings(self,
properties, properties,
@ -869,7 +854,15 @@ class GroupConfig(_CommonConfig):
nconfig_bag, nconfig_bag,
_commit=False) _commit=False)
except PropertiesOptionError as err: 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: except (ValueError, SlaveError) as err:
ret.append(err) ret.append(err)
if _commit: if _commit:
@ -896,7 +889,6 @@ class GroupConfig(_CommonConfig):
byvalue=undefined, byvalue=undefined,
byname=byname, byname=byname,
config_bag=config_bag, config_bag=config_bag,
type_='path',
raise_if_not_found=raise_if_not_found)) raise_if_not_found=raise_if_not_found))
byname = None byname = None
byoption = self.cfgimpl_get_description().impl_get_opt_by_path(bypath) byoption = self.cfgimpl_get_description().impl_get_opt_by_path(bypath)
@ -918,7 +910,6 @@ class GroupConfig(_CommonConfig):
next(child.find(None, next(child.find(None,
byname, byname,
byvalue, byvalue,
type_='path',
config_bag=config_bag, config_bag=config_bag,
raise_if_not_found=False, raise_if_not_found=False,
only_path=bypath, only_path=bypath,
@ -935,22 +926,13 @@ class GroupConfig(_CommonConfig):
def impl_getname(self): def impl_getname(self):
return self._impl_name 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, def getconfig(self,
name): name):
for child in self._impl_children: for child in self._impl_children:
if name == child.impl_getname(): if name == child.impl_getname():
return child return child
raise ConfigError(_('unknown config {}').format(name)) raise ConfigError(_('unknown config "{}"').format(name))
class MetaConfig(GroupConfig): class MetaConfig(GroupConfig):

View File

@ -55,27 +55,48 @@ def display_list(lst, separator='and', add_quote=False):
class PropertiesOptionError(AttributeError): class PropertiesOptionError(AttributeError):
"attempt to access to an option with a property that is not allowed" "attempt to access to an option with a property that is not allowed"
def __init__(self, def __init__(self,
msg, path,
index,
config_bag,
proptype, proptype,
settings=None, settings,
datas=None, opt_type=None,
option_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.proptype = proptype
self._settings = settings self._settings = settings
self._datas = datas self.msg = None
self._type = option_type super(PropertiesOptionError, self).__init__(None)
self._orig_opt = None
super(PropertiesOptionError, self).__init__(msg)
def set_orig_opt(self, opt): def set_orig_opt(self, opt):
self._orig_opt = opt self._orig_opt = opt
def __str__(self): def __str__(self):
#this part is a bit slow, so only execute when display #this part is a bit slow, so only execute when display
if self._settings is None: if self.msg:
req = {} return self.msg
else: req = self._settings.apply_requires(self._path,
req = self._settings.apply_requires(**self._datas) self._requires,
self._index,
True,
self._config_bag)
#if req != {} or self._orig_opt is not None: #if req != {} or self._orig_opt is not None:
if req != {}: if req != {}:
only_one = len(req) == 1 only_one = len(req) == 1
@ -91,17 +112,20 @@ class PropertiesOptionError(AttributeError):
else: else:
prop_msg = _('properties') prop_msg = _('properties')
if self._orig_opt: if self._orig_opt:
return str(_('cannot access to {0} "{1}" because "{2}" has {3} {4}' self.msg = str(_('cannot access to {0} "{1}" because "{2}" has {3} {4}'
'').format(self._type, '').format(self._opt_type,
self._orig_opt.impl_get_display_name(), self._orig_opt.impl_get_display_name(),
self._datas['config_bag'].option.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, prop_msg,
msg)) msg))
return str(_('cannot access to {0} "{1}" because has {2} {3}' del self._path, self._index, self._requires, self._opt_type, self._name, self._config_bag
'').format(self._type, del self._settings, self._orig_opt
self._datas['config_bag'].option.impl_get_display_name(), return self.msg
prop_msg,
msg))
#____________________________________________________________ #____________________________________________________________

View File

@ -25,7 +25,7 @@ from inspect import signature
from ..i18n import _ from ..i18n import _
from ..setting import undefined from ..setting import undefined
from ..error import ConfigError from ..error import ConfigError, display_list
STATIC_TUPLE = frozenset() STATIC_TUPLE = frozenset()
@ -162,7 +162,7 @@ class Base(object):
set_forbidden_properties = calc_properties & properties set_forbidden_properties = calc_properties & properties
if set_forbidden_properties != frozenset(): if set_forbidden_properties != frozenset():
raise ValueError(_('conflict: properties already set in ' 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 = object.__setattr__
_setattr(self, '_name', name) _setattr(self, '_name', name)
_setattr(self, '_informations', {'doc': doc}) _setattr(self, '_informations', {'doc': doc})
@ -249,10 +249,9 @@ class Base(object):
if calculator_args or calculator_kwargs: if calculator_args or calculator_kwargs:
# there is more args/kwargs than expected! # there is more args/kwargs than expected!
raise ConfigError(_('cannot find those arguments "{}" in function "{}" for "{}"' 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__, calculator.__name__,
self.impl_get_display_name())) self.impl_get_display_name()))
has_self = False
has_index = False has_index = False
if is_multi and func_args: if is_multi and func_args:
# there is extra args/kwargs # there is extra args/kwargs
@ -267,16 +266,13 @@ class Base(object):
has_index = True has_index = True
params.append(('index',)) params.append(('index',))
func_args.pop() 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) 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 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: if not has_index and 'index' in func_kwargs:
calculator_params['index'] = (('index',),) calculator_params['index'] = (('index',),)
return calculator_params return calculator_params
@ -573,8 +569,9 @@ def validate_requires_arg(new_option,
option = exp['option'] option = exp['option']
option._add_dependency(new_option) option._add_dependency(new_option)
if option is not None: if option is not None:
err = option._validate(exp['value'], undefined) try:
if err: option._validate(exp['value'], undefined)
except ValueError as err:
raise ValueError(_('malformed requirements expected value ' raise ValueError(_('malformed requirements expected value '
'must be valid for option {0}' 'must be valid for option {0}'
': {1}').format(name, err)) ': {1}').format(name, err))
@ -588,11 +585,13 @@ def validate_requires_arg(new_option,
else: else:
option = get_option(require) option = get_option(require)
if expected is not None: if expected is not None:
err = option._validate(expected, undefined) try:
if err: option._validate(expected, undefined)
except ValueError as err:
raise ValueError(_('malformed requirements expected value ' raise ValueError(_('malformed requirements expected value '
'must be valid for option {0}' 'must be valid for option {0}'
': {1}').format(name, err)) ': {1}').format(name, err))
option._add_dependency(new_option)
_set_expected(action, _set_expected(action,
inverse, inverse,
transitive, transitive,

View File

@ -373,6 +373,7 @@ class Settings(object):
apply_requires) apply_requires)
if apply_requires: if apply_requires:
props |= self.apply_requires(path, props |= self.apply_requires(path,
opt.impl_getrequires(),
index, index,
False, False,
config_bag) config_bag)
@ -405,9 +406,11 @@ class Settings(object):
def apply_requires(self, def apply_requires(self,
path, path,
current_requires,
index, index,
debug, readable,
config_bag): config_bag,
name=None):
"""carries out the jit (just in time) requirements between options """carries out the jit (just in time) requirements between options
a requirement is a tuple of this form that comes from the option's 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 :param path: the option's path in the config
:type path: str :type path: str
""" """
opt = config_bag.option #current_requires = opt.impl_getrequires()
current_requires = opt.impl_getrequires()
# filters the callbacks # filters the callbacks
if debug: if readable:
calc_properties = {} calc_properties = {}
else: else:
calc_properties = set() calc_properties = set()
@ -467,25 +469,21 @@ class Settings(object):
all_properties = None all_properties = None
for requires in current_requires: for requires in current_requires:
for require in requires: for require in requires:
exps, action, inverse, \ exps, action, inverse, transitive, same_action, operator = require
transitive, same_action, operator = require
breaked = False breaked = False
for exp in exps: for option, expected in exps:
option, expected = exp
reqpath = option.impl_getpath(context) 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 " raise RequirementError(_("malformed requirements "
"imbrication detected for option:" "imbrication detected for option:"
" '{0}' with requirement on: " " '{0}' with requirement on: "
"'{1}'").format(path, reqpath)) "'{1}'").format(path, reqpath))
if not option.impl_is_multi(): idx = None
idx = None is_indexed = False
is_indexed = False if option.impl_is_master_slaves('slave'):
elif option.impl_is_master_slaves('slave'):
idx = index idx = index
is_indexed = False elif option.impl_is_multi():
else:
idx = None
is_indexed = True is_indexed = True
sconfig_bag = config_bag.copy('nooption') sconfig_bag = config_bag.copy('nooption')
sconfig_bag.option = option sconfig_bag.option = option
@ -497,40 +495,44 @@ class Settings(object):
if is_indexed: if is_indexed:
value = value[index] value = value[index]
except PropertiesOptionError as err: except PropertiesOptionError as err:
properties = err.proptype
if not transitive: if not transitive:
if all_properties is None: if all_properties is None:
all_properties = [] all_properties = []
for requires_ in opt.impl_getrequires(): for requires_ in current_requires:
for require_ in requires_: for require_ in requires_:
all_properties.append(require_[1]) all_properties.append(require_[1])
if not set(err.proptype) - set(all_properties): if not set(properties) - set(all_properties):
continue continue
properties = err.proptype if same_action and action not in properties:
if same_action and action not in properties: # pragma: optional cover
if len(properties) == 1: if len(properties) == 1:
prop_msg = _('property') prop_msg = _('property')
else: else:
prop_msg = _('properties') prop_msg = _('properties')
raise RequirementError(_('cannot access to option "{0}" because ' raise RequirementError(_('cannot access to option "{0}" because '
'required option "{1}" has {2} {3}' 'required option "{1}" has {2} {3}'
'').format(opt.impl_get_display_name(), '').format(name,
option.impl_get_display_name(), option.impl_get_display_name(),
prop_msg, prop_msg,
display_list(list(properties)))) display_list(list(properties))))
orig_value = err # transitive action, add action
# 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):
if operator != 'and': if operator != 'and':
if debug: if readable:
if isinstance(orig_value, PropertiesOptionError): for msg in self.apply_requires(err.path,
for msg in orig_value._settings.apply_requires(**orig_value._datas).values(): err.requires,
calc_properties.setdefault(action, []).extend(msg) err.index,
else: 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: if not inverse:
msg = _('the value of "{0}" is {1}') msg = _('the value of "{0}" is {1}')
else: else:
@ -538,12 +540,12 @@ class Settings(object):
calc_properties.setdefault(action, []).append( calc_properties.setdefault(action, []).append(
msg.format(option.impl_get_display_name(), msg.format(option.impl_get_display_name(),
display_list(expected, 'or', add_quote=True))) display_list(expected, 'or', add_quote=True)))
else: else:
calc_properties.add(action) calc_properties.add(action)
breaked = True breaked = True
break break
elif operator == 'and': elif operator == 'and':
break break
else: else:
if operator == 'and': if operator == 'and':
calc_properties.add(action) calc_properties.add(action)
@ -691,11 +693,6 @@ class Settings(object):
config_bag) config_bag)
config_bag.properties = self_properties config_bag.properties = self_properties
properties = self_properties & config_bag.setting_properties - {'frozen', 'mandatory', 'empty'} 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 # remove permissive properties
if (config_bag.force_permissive is True or 'permissive' in config_bag.setting_properties) and 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() properties -= self.get_context_permissive()
# at this point an option should not remain in properties # at this point an option should not remain in properties
if properties != frozenset(): if properties != frozenset():
datas = {'path': path, raise PropertiesOptionError(path,
'config_bag': config_bag, index,
'index': index, config_bag,
'debug': True}
raise PropertiesOptionError(None,
properties, properties,
self, self)
datas,
opt_type)
def validate_mandatory(self, def validate_mandatory(self,
path, path,
@ -735,17 +728,15 @@ class Settings(object):
index=index): index=index):
is_mandatory = True is_mandatory = True
if is_mandatory: if is_mandatory:
datas = {'path': path, raise PropertiesOptionError(path,
'config_bag': config_bag, index,
'index': index, config_bag,
'debug': True}
raise PropertiesOptionError(None,
['mandatory'], ['mandatory'],
self, self)
datas,
'option')
def validate_frozen(self, def validate_frozen(self,
path,
index,
config_bag): config_bag):
if config_bag.setting_properties and \ if config_bag.setting_properties and \
('everything_frozen' in config_bag.setting_properties or ('everything_frozen' in config_bag.setting_properties or
@ -753,7 +744,11 @@ class Settings(object):
not ((config_bag.force_permissive is True or not ((config_bag.force_permissive is True or
'permissive' in config_bag.setting_properties) and 'permissive' in config_bag.setting_properties) and
'frozen' in self.get_context_permissive()): 'frozen' in self.get_context_permissive()):
return True raise PropertiesOptionError(path,
index,
config_bag,
['frozen'],
self)
return False return False
#____________________________________________________________ #____________________________________________________________
# read only/read write # read only/read write

View File

@ -56,7 +56,7 @@ class Values(object):
old `SubConfig`, `Values`, `Multi` or `Settings`) old `SubConfig`, `Values`, `Multi` or `Settings`)
""" """
context = self.context() context = self.context()
if context is None: if context is None: # pragma: no cover
raise ConfigError(_('the context does not exist anymore')) raise ConfigError(_('the context does not exist anymore'))
return context return context
@ -242,7 +242,7 @@ class Values(object):
# if value is a list and index is set # if value is a list and index is set
if opt.impl_is_submulti() and (value == [] or not isinstance(value[0], list)): 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 # return value only if it's a submulti and not a list of list
_reset_cache(value,) _reset_cache(value)
return value return value
if len(value) > index: if len(value) > index:
@ -251,28 +251,20 @@ class Values(object):
return value[index] return value[index]
# there is no calculate value for this index, # there is no calculate value for this index,
# so return an other default value # 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: else:
# not a list or index is None
if opt.impl_is_submulti(): if opt.impl_is_submulti():
# return a list of list for a submulti if isinstance(value, list):
value = [[value]] # value is a list, but no index specified
elif opt.impl_is_multi(): 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 # return a list for a multi
value = [value] value = [value]
_reset_cache(value) _reset_cache(value)
@ -375,16 +367,9 @@ class Values(object):
config_bag) config_bag)
config_bag.properties = self_properties config_bag.properties = self_properties
opt = config_bag.option opt = config_bag.option
if settings.validate_frozen(config_bag): settings.validate_frozen(path,
datas = {'path': path, index,
'config_bag': config_bag, config_bag)
'index': index,
'debug': True}
raise PropertiesOptionError(None,
['frozen'],
settings,
datas,
'option')
settings.validate_mandatory(path, settings.validate_mandatory(path,
index, index,
value, value,
@ -673,16 +658,9 @@ class Values(object):
None, None,
config_bag) config_bag)
config_bag.properties = self_properties config_bag.properties = self_properties
if settings.validate_frozen(config_bag): settings.validate_frozen(path,
datas = {'path': path, index,
'config_bag': config_bag, config_bag)
'index': index,
'debug': True}
raise PropertiesOptionError(None,
['frozen'],
settings,
datas,
'option')
#______________________________________________________________________ #______________________________________________________________________
# information # information