to_dict improvment and add display_name parameter to change impl_get_display_name function

This commit is contained in:
Emmanuel Garette 2019-07-26 08:54:01 +02:00
parent 35ef218c9c
commit 34d71901d0
9 changed files with 167 additions and 99 deletions

View File

@ -565,7 +565,7 @@ def test_mandatory_warnings_validate_empty():
cfg = Config(descr) cfg = Config(descr)
cfg.option('str').value.set('') cfg.option('str').value.set('')
cfg.property.read_only() cfg.property.read_only()
assert list(cfg.value.mandatory()) == ['str', 'str1', 'str3', 'unicode1'] assert list(cfg.value.mandatory()) == ['str', 'str1', 'str3']
def test_mandatory_warnings_requires(): def test_mandatory_warnings_requires():

View File

@ -180,10 +180,17 @@ def test_consistency_not_equal_many_opts(config_type):
# #
cfg.option('a').value.set(1) cfg.option('a').value.set(1)
raises(ValueError, "cfg.option('b').value.set(1)") raises(ValueError, "cfg.option('b').value.set(1)")
assert cfg.option('b').value.get() == None
# #
cfg.option('b').value.set(2) cfg.option('b').value.set(2)
raises(ValueError, "cfg.option('f').value.set(2)") raises(ValueError, "cfg.option('f').value.set(2)")
assert cfg.option('f').value.get() is None
assert cfg.option('a').value.get() == 1
assert cfg.option('b').value.get() == 2
raises(ValueError, "cfg.option('f').value.set(1)") raises(ValueError, "cfg.option('f').value.set(1)")
assert cfg.option('f').value.get() is None
assert cfg.option('a').value.get() == 1
assert cfg.option('b').value.get() == 2
# #
cfg.option('d').value.set(3) cfg.option('d').value.set(3)
raises(ValueError, "cfg.option('f').value.set(3)") raises(ValueError, "cfg.option('f').value.set(3)")

View File

@ -1,4 +1,4 @@
from .autopath import do_autopath 1rom .autopath import do_autopath
do_autopath() do_autopath()
from .config import config_type, get_config from .config import config_type, get_config
@ -127,6 +127,14 @@ def test_validator(config_type):
cfg.option('opt2').value.set('val') cfg.option('opt2').value.set('val')
assert len(w) == 1 assert len(w) == 1
assert str(w[0].message) == msg assert str(w[0].message) == msg
with warnings.catch_warnings(record=True) as w:
cfg.option('opt2').value.get()
assert len(w) == 1
assert str(w[0].message) == msg
with warnings.catch_warnings(record=True) as w:
cfg.option('opt2').value.get()
assert len(w) == 1
assert str(w[0].message) == msg
def test_validator_params(config_type): def test_validator_params(config_type):

View File

@ -19,7 +19,7 @@ from time import time
from typing import List, Set, Any, Optional, Callable, Union, Dict from typing import List, Set, Any, Optional, Callable, Union, Dict
from .error import APIError, ConfigError, LeadershipError, PropertiesOptionError from .error import APIError, ConfigError, LeadershipError, PropertiesOptionError, ValueErrorWarning
from .i18n import _ from .i18n import _
from .setting import ConfigBag, OptionBag, owners, groups, Undefined, undefined, \ from .setting import ConfigBag, OptionBag, owners, groups, Undefined, undefined, \
FORBIDDEN_SET_PROPERTIES, SPECIAL_PROPERTIES, EXPIRATION_TIME FORBIDDEN_SET_PROPERTIES, SPECIAL_PROPERTIES, EXPIRATION_TIME
@ -530,6 +530,17 @@ class _TiramisuOptionValueOption:
else: else:
return values.getdefaultvalue(self._option_bag) return values.getdefaultvalue(self._option_bag)
def valid(self):
try:
with warnings.catch_warnings(record=True) as warns:
self.get()
for warn in warns:
if isinstance(warns.message, ValueErrorWarning):
return False
except ValueError:
return False
return True
class _TiramisuOptionValueLeader: class _TiramisuOptionValueLeader:
def pop(self, index): def pop(self, index):
@ -739,52 +750,54 @@ class _TiramisuOptionDescription(_TiramisuOption):
def _filter(self, def _filter(self,
opt, opt,
subconfig): subconfig,
if self._config_bag.properties: config_bag):
name = opt.impl_getname()
path = subconfig._get_subpath(name)
option_bag = OptionBag() option_bag = OptionBag()
option_bag.set_option(opt, option_bag.set_option(opt,
path, opt.impl_getpath(),
None, None,
self._config_bag) config_bag)
if opt.impl_is_optiondescription(): if opt.impl_is_optiondescription():
self._subconfig.get_subconfig(option_bag) config_bag.context.cfgimpl_get_settings().validate_properties(option_bag)
else: return subconfig.get_subconfig(option_bag)
subconfig.getattr(name, subconfig.getattr(opt.impl_getname(),
option_bag) option_bag)
def list(self, def list(self,
type='option', type='option',
group_type=None): group_type=None):
"""List options in an optiondescription (only for optiondescription)""" """List options (by default list only option)"""
assert type in ('all', 'option', 'optiondescription'), _('unknown list type {}').format(type) assert type in ('all', 'option', 'optiondescription'), _('unknown list type {}').format(type)
assert group_type is None or isinstance(group_type, groups.GroupType), \ assert group_type is None or isinstance(group_type, groups.GroupType), \
_("unknown group_type: {0}").format(group_type) _("unknown group_type: {0}").format(group_type)
config_bag = self._config_bag
if config_bag.properties and 'warnings' in config_bag.properties:
config_bag = config_bag.copy()
config_bag.remove_warnings()
option = self._get_option() option = self._get_option()
name = option.impl_getname()
path = self._subconfig._get_subpath(name)
option_bag = OptionBag() option_bag = OptionBag()
option_bag.set_option(option, option_bag.set_option(option,
path, option.impl_getpath(),
None, None,
self._config_bag) config_bag)
subconfig = self._subconfig.get_subconfig(option_bag) subconfig = self._subconfig.get_subconfig(option_bag)
for opt in option.get_children(self._config_bag): for opt in option.get_children(config_bag):
try: try:
self._filter(opt, self._filter(opt,
subconfig) subconfig,
config_bag)
except PropertiesOptionError: except PropertiesOptionError:
continue continue
if opt.impl_is_optiondescription(): if opt.impl_is_optiondescription():
if type == 'option' or (type == 'optiondescription' and group_type and \ if type == 'option' or (type == 'optiondescription' and \
opt.impl_get_group_type() != group_type): group_type and opt.impl_get_group_type() != group_type):
continue continue
elif type == 'optiondescription': elif type == 'optiondescription':
continue continue
name = opt.impl_getname() name = opt.impl_getname()
path = opt.impl_getpath()
yield TiramisuOption(name, yield TiramisuOption(name,
subconfig._get_subpath(name), path,
None, None,
subconfig, subconfig,
self._config_bag) self._config_bag)
@ -792,9 +805,10 @@ class _TiramisuOptionDescription(_TiramisuOption):
def dict(self, def dict(self,
clearable: str="all", clearable: str="all",
remotable: str="minimum", remotable: str="minimum",
form: List=[]) -> Dict: form: List=[],
force: bool=False) -> Dict:
"""convert config and option to tiramisu format""" """convert config and option to tiramisu format"""
if self._tiramisu_dict is None: if force or self._tiramisu_dict is None:
option = self._get_option() option = self._get_option()
name = option.impl_getname() name = option.impl_getname()
root = self._subconfig._get_subpath(name) root = self._subconfig._get_subpath(name)
@ -822,6 +836,10 @@ class TiramisuOption(CommonTiramisuOption):
subconfig: Union[None, KernelConfig, SubConfig]=None, subconfig: Union[None, KernelConfig, SubConfig]=None,
config_bag: Optional[ConfigBag]=None) -> None: config_bag: Optional[ConfigBag]=None) -> None:
if subconfig: if subconfig:
# not for groupconfig
if '.' in name:
subconfig, name = config_bag.context.cfgimpl_get_home_by_path(path,
config_bag)
option = subconfig.cfgimpl_get_description().get_child(name, option = subconfig.cfgimpl_get_description().get_child(name,
config_bag, config_bag,
subconfig.cfgimpl_get_path()) subconfig.cfgimpl_get_path())
@ -1219,13 +1237,12 @@ class TiramisuContextOption(TiramisuContext):
continue continue
if opt.impl_is_optiondescription(): if opt.impl_is_optiondescription():
if recursive: if recursive:
for toption in self._walk(opt, yield from self._walk(opt,
recursive, recursive,
type_, type_,
group_type, group_type,
config_bag, config_bag,
subsubconfig): subsubconfig)
yield toption
if type_ == 'option' or (type_ == 'optiondescription' and \ if type_ == 'option' or (type_ == 'optiondescription' and \
group_type and opt.impl_get_group_type() != group_type): group_type and opt.impl_get_group_type() != group_type):
continue continue
@ -1252,20 +1269,20 @@ class TiramisuContextOption(TiramisuContext):
config_bag = config_bag.copy() config_bag = config_bag.copy()
config_bag.remove_warnings() config_bag.remove_warnings()
option = config_bag.context.cfgimpl_get_description() option = config_bag.context.cfgimpl_get_description()
for toption in self._walk(option, yield from self._walk(option,
recursive, recursive,
type, type,
group_type, group_type,
config_bag, config_bag,
config_bag.context): config_bag.context)
yield toption
def dict(self, def dict(self,
clearable="all", clearable="all",
remotable="minimum", remotable="minimum",
form=[]): form=[],
force=False):
"""convert config and option to tiramisu format""" """convert config and option to tiramisu format"""
if self._tiramisu_dict is None: if force or self._tiramisu_dict is None:
self._tiramisu_dict = TiramisuDict(Config(self._config_bag.context), self._tiramisu_dict = TiramisuDict(Config(self._config_bag.context),
root=None, root=None,
clearable=clearable, clearable=clearable,
@ -1499,14 +1516,16 @@ class Config(TiramisuAPI):
descr: OptionDescription, descr: OptionDescription,
session_id: str=None, session_id: str=None,
persistent: bool=False, persistent: bool=False,
storage=None) -> None: storage=None,
display_name=None) -> None:
if isinstance(descr, KernelConfig): if isinstance(descr, KernelConfig):
config = descr config = descr
else: else:
config = KernelConfig(descr, config = KernelConfig(descr,
session_id=session_id, session_id=session_id,
persistent=persistent, persistent=persistent,
storage=storage) storage=storage,
display_name=display_name)
super().__init__(config) super().__init__(config)
@ -1516,7 +1535,8 @@ class MetaConfig(TiramisuAPI):
children, children,
session_id: Union[str, None]=None, session_id: Union[str, None]=None,
persistent: bool=False, persistent: bool=False,
optiondescription: Optional[OptionDescription]=None) -> None: optiondescription: Optional[OptionDescription]=None,
display_name=None) -> None:
if isinstance(children, KernelMetaConfig): if isinstance(children, KernelMetaConfig):
config = children config = children
else: else:
@ -1530,7 +1550,8 @@ class MetaConfig(TiramisuAPI):
config = KernelMetaConfig(_children, config = KernelMetaConfig(_children,
session_id=session_id, session_id=session_id,
persistent=persistent, persistent=persistent,
optiondescription=optiondescription) optiondescription=optiondescription,
display_name=display_name)
super().__init__(config) super().__init__(config)
@ -1540,7 +1561,8 @@ class MixConfig(TiramisuAPI):
optiondescription: OptionDescription, optiondescription: OptionDescription,
children: List[Config], children: List[Config],
session_id: Optional[str]=None, session_id: Optional[str]=None,
persistent: bool=False) -> None: persistent: bool=False,
display_name: Callable=None) -> None:
if isinstance(children, KernelMixConfig): if isinstance(children, KernelMixConfig):
config = children config = children
else: else:
@ -1554,7 +1576,8 @@ class MixConfig(TiramisuAPI):
config = KernelMixConfig(optiondescription, config = KernelMixConfig(optiondescription,
_children, _children,
session_id=session_id, session_id=session_id,
persistent=persistent) persistent=persistent,
display_name=display_name)
super().__init__(config) super().__init__(config)

View File

@ -615,7 +615,7 @@ class _CommonConfig(SubConfig):
def _impl_build_all_caches(self): def _impl_build_all_caches(self):
descr = self.cfgimpl_get_description() descr = self.cfgimpl_get_description()
if not descr.impl_already_build_caches(): if not descr.impl_already_build_caches():
descr._build_cache() descr._build_cache(display_name=self._display_name)
config_bag = ConfigBag(context=self) config_bag = ConfigBag(context=self)
descr.impl_build_force_store_values(config_bag) descr.impl_build_force_store_values(config_bag)
@ -652,7 +652,8 @@ class _CommonConfig(SubConfig):
fake_config = KernelConfig(self._impl_descr, fake_config = KernelConfig(self._impl_descr,
persistent=False, persistent=False,
force_values=get_default_values_storages(), force_values=get_default_values_storages(),
force_settings=self.cfgimpl_get_settings()) force_settings=self.cfgimpl_get_settings(),
display_name=self._display_name)
fake_config.cfgimpl_get_values()._p_.importation(self.cfgimpl_get_values()._p_.exportation()) fake_config.cfgimpl_get_values()._p_.importation(self.cfgimpl_get_values()._p_.exportation())
return fake_config return fake_config
@ -673,7 +674,8 @@ class _CommonConfig(SubConfig):
force_values=force_values, force_values=force_values,
force_settings=force_settings, force_settings=force_settings,
persistent=persistent, persistent=persistent,
storage=storage) storage=storage,
display_name=self._display_name)
else: else:
if session_id is None and metaconfig_prefix is not None: if session_id is None and metaconfig_prefix is not None:
session_id = metaconfig_prefix + self.impl_getname() session_id = metaconfig_prefix + self.impl_getname()
@ -682,7 +684,8 @@ class _CommonConfig(SubConfig):
optiondescription=self._impl_descr, optiondescription=self._impl_descr,
session_id=session_id, session_id=session_id,
persistent=persistent, persistent=persistent,
storage=storage) storage=storage,
display_name=self._display_name)
duplicated_config.cfgimpl_get_values()._p_.importation(self.cfgimpl_get_values()._p_.exportation()) duplicated_config.cfgimpl_get_values()._p_.importation(self.cfgimpl_get_values()._p_.exportation())
properties = self.cfgimpl_get_settings()._p_.exportation() properties = self.cfgimpl_get_settings()._p_.exportation()
duplicated_config.cfgimpl_get_settings()._p_.importation(properties) duplicated_config.cfgimpl_get_settings()._p_.importation(properties)
@ -714,7 +717,8 @@ class _CommonConfig(SubConfig):
class KernelConfig(_CommonConfig): class KernelConfig(_CommonConfig):
"main configuration management entry" "main configuration management entry"
__slots__ = ('__weakref__', __slots__ = ('__weakref__',
'_impl_name') '_impl_name',
'_display_name')
impl_type = 'config' impl_type = 'config'
def __init__(self, def __init__(self,
@ -723,6 +727,7 @@ class KernelConfig(_CommonConfig):
persistent=False, persistent=False,
force_values=None, force_values=None,
force_settings=None, force_settings=None,
display_name=None,
_duplicate=False, _duplicate=False,
storage=None): storage=None):
""" Configuration option management class """ Configuration option management class
@ -738,6 +743,7 @@ class KernelConfig(_CommonConfig):
:type persistent: `boolean` :type persistent: `boolean`
""" """
self._impl_meta = None self._impl_meta = None
self._display_name = display_name
if isinstance(descr, Leadership): if isinstance(descr, Leadership):
raise ConfigError(_('cannot set leadership object has root optiondescription')) raise ConfigError(_('cannot set leadership object has root optiondescription'))
if isinstance(descr, DynOptionDescription): if isinstance(descr, DynOptionDescription):
@ -976,7 +982,7 @@ class KernelGroupConfig(_CommonConfig):
class KernelMixConfig(KernelGroupConfig): class KernelMixConfig(KernelGroupConfig):
__slots__ = tuple() __slots__ = ('_display_name',)
impl_type = 'mix' impl_type = 'mix'
def __init__(self, def __init__(self,
@ -985,8 +991,10 @@ class KernelMixConfig(KernelGroupConfig):
session_id=None, session_id=None,
persistent=False, persistent=False,
storage=None, storage=None,
display_name=None,
_duplicate=False): _duplicate=False):
# FIXME _duplicate # FIXME _duplicate
self._display_name = display_name
for child in children: for child in children:
if not isinstance(child, _CommonConfig): if not isinstance(child, _CommonConfig):
try: try:
@ -1210,8 +1218,10 @@ class KernelMetaConfig(KernelMixConfig):
persistent=False, persistent=False,
optiondescription=None, optiondescription=None,
storage=None, storage=None,
display_name=None,
_duplicate=False): _duplicate=False):
descr = None descr = None
self._display_name = display_name
if optiondescription is not None: if optiondescription is not None:
if not _duplicate: if not _duplicate:
new_children = [] new_children = []
@ -1221,7 +1231,8 @@ class KernelMetaConfig(KernelMixConfig):
'not {}').format(child_session_id) 'not {}').format(child_session_id)
new_children.append(KernelConfig(optiondescription, new_children.append(KernelConfig(optiondescription,
persistent=persistent, persistent=persistent,
session_id=child_session_id)) session_id=child_session_id,
display_name=self._display_name))
children = new_children children = new_children
descr = optiondescription descr = optiondescription
for child in children: for child in children:
@ -1259,17 +1270,20 @@ class KernelMetaConfig(KernelMixConfig):
if type_ == 'config': if type_ == 'config':
config = KernelConfig(self._impl_descr, config = KernelConfig(self._impl_descr,
session_id=session_id, session_id=session_id,
persistent=persistent) persistent=persistent,
display_name=self._display_name)
elif type_ == 'metaconfig': elif type_ == 'metaconfig':
config = KernelMetaConfig([], config = KernelMetaConfig([],
optiondescription=self._impl_descr, optiondescription=self._impl_descr,
session_id=session_id, session_id=session_id,
persistent=persistent) persistent=persistent,
display_name=self._display_name)
elif type_ == 'mixconfig': elif type_ == 'mixconfig':
config = KernelMixConfig(children=[], config = KernelMixConfig(children=[],
optiondescription=self._impl_descr, optiondescription=self._impl_descr,
session_id=session_id, session_id=session_id,
persistent=persistent) persistent=persistent,
display_name=self._display_name)
# Copy context properties/permissives # Copy context properties/permissives
if new: if new:
config.cfgimpl_get_settings().set_context_properties(self.cfgimpl_get_settings().get_context_properties(), config) config.cfgimpl_get_settings().set_context_properties(self.cfgimpl_get_settings().get_context_properties(), config)

View File

@ -373,7 +373,7 @@ class BaseOption(Base):
in options that have to be set only once, it is of course done in the in options that have to be set only once, it is of course done in the
__setattr__ method __setattr__ method
""" """
__slots__ = tuple() __slots__ = ('_display_name_function',)
def __getstate__(self): def __getstate__(self):
raise NotImplementedError() raise NotImplementedError()
@ -407,7 +407,7 @@ class BaseOption(Base):
"to know if a callback has been defined or not" "to know if a callback has been defined or not"
return self.impl_get_callback()[0] is not None return self.impl_get_callback()[0] is not None
def impl_get_display_name(self, def _impl_get_display_name(self,
dyn_name: Base=None) -> str: dyn_name: Base=None) -> str:
name = self.impl_get_information('doc') name = self.impl_get_information('doc')
if name is None or name == '': if name is None or name == '':
@ -417,6 +417,12 @@ class BaseOption(Base):
name = self.impl_getname() name = self.impl_getname()
return name return name
def impl_get_display_name(self,
dyn_name: Base=None) -> str:
if hasattr(self, '_display_name_function'):
return self._display_name_function(self, dyn_name)
return self._impl_get_display_name(dyn_name)
def reset_cache(self, def reset_cache(self,
path: str, path: str,
values: Values, values: Values,

View File

@ -43,7 +43,8 @@ class CacheOptionDescription(BaseOption):
_consistencies_id=0, _consistencies_id=0,
currpath: List[str]=None, currpath: List[str]=None,
cache_option=None, cache_option=None,
force_store_values=None) -> None: force_store_values=None,
display_name=None) -> None:
"""validate options and set option has readonly option """validate options and set option has readonly option
""" """
# _consistencies is None only when we start to build cache # _consistencies is None only when we start to build cache
@ -73,7 +74,8 @@ class CacheOptionDescription(BaseOption):
_consistencies_id, _consistencies_id,
sub_currpath, sub_currpath,
cache_option, cache_option,
force_store_values) force_store_values,
display_name)
else: else:
is_multi = option.impl_is_multi() is_multi = option.impl_is_multi()
if not option.impl_is_symlinkoption(): if not option.impl_is_symlinkoption():
@ -155,6 +157,8 @@ class CacheOptionDescription(BaseOption):
require_opt.impl_getname(), option.impl_getname())) require_opt.impl_getname(), option.impl_getname()))
if option.impl_is_readonly(): if option.impl_is_readonly():
raise ConflictError(_('duplicate option: {0}').format(option)) raise ConflictError(_('duplicate option: {0}').format(option))
if not self.impl_is_readonly() and display_name:
option._display_name_function = display_name
option._path = subpath option._path = subpath
option._set_readonly() option._set_readonly()
if init: if init:

View File

@ -33,6 +33,7 @@ INPUTS = ['string',
# return always warning (even if same warning is already returned) # return always warning (even if same warning is already returned)
warnings.simplefilter("always", ValueWarning) warnings.simplefilter("always", ValueWarning)
warnings.simplefilter("always", ValueErrorWarning)
class Callbacks(object): class Callbacks(object):
@ -621,26 +622,32 @@ class TiramisuDict:
props = set(childapi.property.get()) props = set(childapi.property.get())
obj = self.gen_properties(props, obj = self.gen_properties(props,
isfollower, isfollower,
childapi.option.ismulti()) childapi.option.ismulti(),
index)
self.calc_raises_properties(obj, childapi) self.calc_raises_properties(obj, childapi)
return obj return obj
def gen_properties(self, def gen_properties(self,
properties, properties,
isfollower=False, isfollower,
ismulti=False): ismulti,
index):
obj = {} obj = {}
if not isfollower and ismulti: if not isfollower and ismulti:
if 'empty' in properties: if 'empty' in properties:
if index is None:
obj['required'] = True obj['required'] = True
properties.remove('empty') properties.remove('empty')
if 'mandatory' in properties: if 'mandatory' in properties:
if index is None:
obj['needs_len'] = True obj['needs_len'] = True
properties.remove('mandatory') properties.remove('mandatory')
elif 'mandatory' in properties: elif 'mandatory' in properties:
if index is None:
obj['required'] = True obj['required'] = True
properties.remove('mandatory') properties.remove('mandatory')
if 'frozen' in properties: if 'frozen' in properties:
if index is None:
obj['readOnly'] = True obj['readOnly'] = True
properties.remove('frozen') properties.remove('frozen')
if 'hidden' in properties: if 'hidden' in properties:
@ -744,21 +751,23 @@ class TiramisuDict:
for value in values: for value in values:
if isinstance(value, ValueError): if isinstance(value, ValueError):
obj.setdefault('error', []) obj.setdefault('error', [])
obj['error'].append(str(value)) msg = str(value)
if msg not in obj.get('error', []):
obj['error'].append(msg)
obj['invalid'] = True obj['invalid'] = True
elif isinstance(value.message, ValueErrorWarning): elif isinstance(value.message, ValueErrorWarning):
value.message.prefix = '' value.message.prefix = ''
if childapi.option.isfollower():
obj.setdefault('invalid', [])
obj['invalid'].append({'error': str(value.message),
'index': value.message.index})
else:
obj.setdefault('error', []) obj.setdefault('error', [])
obj['error'].append(str(value.message)) msg = str(value.message)
if msg not in obj.get('error', []):
obj['error'].append(msg)
obj['invalid'] = True obj['invalid'] = True
else: else:
value.message.prefix = ''
obj.setdefault('warnings', []) obj.setdefault('warnings', [])
obj['warnings'].append(str(value.message)) msg = str(value.message)
if msg not in obj.get('error', []):
obj['warnings'].append(msg)
obj['hasWarnings'] = True obj['hasWarnings'] = True
def gen_global(self): def gen_global(self):

View File

@ -76,7 +76,8 @@ class Values(object):
option_bag, option_bag,
check_error=True) check_error=True)
# store value in cache # store value in cache
validator = 'validator' in option_bag.config_bag.properties properties = option_bag.config_bag.properties
validator = 'validator' in properties and 'demoting_error_warning' not in properties
if not option_bag.fromconsistency and (not is_cached or validator): if not option_bag.fromconsistency and (not is_cached or validator):
self._p_.setcache(option_bag.path, self._p_.setcache(option_bag.path,
option_bag.index, option_bag.index,
@ -570,13 +571,12 @@ class Values(object):
except PropertiesOptionError as err: except PropertiesOptionError as err:
pass pass
else: else:
for path in self._mandatory_warnings(context, yield from self._mandatory_warnings(context,
config_bag, config_bag,
option, option,
currpath + [name], currpath + [name],
subsubconfig, subsubconfig,
od_config_bag): od_config_bag)
yield path
elif not option.impl_is_symlinkoption(): elif not option.impl_is_symlinkoption():
# don't verifying symlink # don't verifying symlink
try: try:
@ -602,11 +602,8 @@ class Values(object):
except PropertiesOptionError as err: except PropertiesOptionError as err:
if err.proptype == ['mandatory']: if err.proptype == ['mandatory']:
yield path yield path
except RequirementError: except (RequirementError, ConfigError):
pass pass
except ConfigError as err:
#assume that uncalculated value is an empty value
yield path
def mandatory_warnings(self, def mandatory_warnings(self,
config_bag): config_bag):