reorganisation

This commit is contained in:
Emmanuel Garette 2017-12-07 21:42:04 +01:00
parent 48e172a59a
commit a07e916153
5 changed files with 285 additions and 278 deletions

View file

@ -87,12 +87,12 @@ class SubConfig(object):
context_ = context() context_ = context()
masterp = master.impl_getpath(context_) masterp = master.impl_getpath(context_)
value = context_.cfgimpl_get_values().get_cached_value(master, value = context_.cfgimpl_get_values().get_cached_value(master,
path=masterp, masterp,
setting_properties,
validate=validate, validate=validate,
force_permissive=force_permissive, force_permissive=force_permissive,
self_properties=undefined, self_properties=undefined,
index=None, index=None)
setting_properties=setting_properties)
self._impl_length = len(value) self._impl_length = len(value)
def cfgimpl_get_length(self): def cfgimpl_get_length(self):
@ -467,9 +467,9 @@ class SubConfig(object):
if returns_option is True: if returns_option is True:
return option return option
return self.cfgimpl_get_values().get_cached_value(option, return self.cfgimpl_get_values().get_cached_value(option,
path=subpath, subpath,
setting_properties,
validate=validate, validate=validate,
setting_properties=setting_properties,
force_permissive=force_permissive, force_permissive=force_permissive,
index=index) index=index)

View file

@ -59,10 +59,21 @@ class Option(OnlyOption):
'_choice_values_params', '_choice_values_params',
) )
_empty = '' _empty = ''
def __init__(self, name, doc, default=undefined, default_multi=None, def __init__(self,
requires=None, multi=False, unique=undefined, callback=None, name,
callback_params=None, validator=None, validator_params=None, doc,
properties=None, warnings_only=False, extra=None, 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): allow_empty_list=undefined):
_setattr = object.__setattr__ _setattr = object.__setattr__
@ -91,9 +102,13 @@ class Option(OnlyOption):
default = [] default = []
if validator is not None: if validator is not None:
if multi: # and validator_params is 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: if validator_params is None:
val_call = (validator,) val_call = (validator,)
else: else:
@ -110,21 +125,24 @@ class Option(OnlyOption):
if allow_empty_list is not undefined: if allow_empty_list is not undefined:
_setattr(self, '_allow_empty_list', allow_empty_list) _setattr(self, '_allow_empty_list', allow_empty_list)
super(Option, self).__init__(name, doc, requires=requires, super(Option, self).__init__(name,
properties=properties, is_multi=is_multi) doc,
requires=requires,
properties=properties,
is_multi=is_multi)
if is_multi and default_multi is not None: if is_multi and default_multi is not None:
def test_multi_value(value): def test_multi_value(value):
err = self._validate(value) err = self._validate(value)
if err: if err:
raise ValueError(_("invalid default_multi value {0} " raise ValueError(_("invalid default_multi value {0} "
"for option {1}: {2}").format( "for option {1}: {2}").format(str(value),
str(value), self.impl_getname(),
self.impl_getname(), str(err))) str(err)))
if _multi is submulti: if _multi is submulti:
if not isinstance(default_multi, list): if not isinstance(default_multi, list):
raise ValueError(_("invalid default_multi value {0} " raise ValueError(_("invalid default_multi value {0} "
"for option {1}: must be a list for a submulti").format( "for option {1}: must be a list for a submulti"
str(default_multi), "").format(str(default_multi),
self.impl_getname())) self.impl_getname()))
for value in default_multi: for value in default_multi:
test_multi_value(value) test_multi_value(value)
@ -133,7 +151,8 @@ class Option(OnlyOption):
_setattr(self, '_default_multi', default_multi) _setattr(self, '_default_multi', default_multi)
if unique is not undefined: if unique is not undefined:
_setattr(self, '_unique', unique) _setattr(self, '_unique', unique)
err = self.impl_validate(default, is_multi=is_multi) err = self.impl_validate(default,
is_multi=is_multi)
if err: if err:
raise err raise err
if (is_multi and default != []) or \ if (is_multi and default != []) or \
@ -142,11 +161,18 @@ class Option(OnlyOption):
default = tuple(default) default = tuple(default)
_setattr(self, '_default', 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): def impl_is_multi(self):
return getattr(self, '_multi', 1) != 1 return getattr(self, '_multi', 1) != 1
def _validate(self,
*args,
**kwargs):
pass
def _launch_consistency(self, def _launch_consistency(self,
current_opt, current_opt,
func, func,
@ -270,7 +296,6 @@ class Option(OnlyOption):
def impl_validate(self, def impl_validate(self,
value, value,
context=undefined, context=undefined,
validate=True,
force_index=None, force_index=None,
current_opt=undefined, current_opt=undefined,
is_multi=None, is_multi=None,
@ -282,14 +307,11 @@ class Option(OnlyOption):
:param value: the option's value :param value: the option's value
:param context: Config's context :param context: Config's context
:type context: :class:`tiramisu.config.Config` :type context: :class:`tiramisu.config.Config`
:param validate: if true enables ``self._validator`` validation
:type validate: boolean :type validate: boolean
:param force_index: if multi, value has to be a list :param force_index: if multi, value has to be a list
not if force_index is not None not if force_index is not None
:type force_index: integer :type force_index: integer
""" """
if not validate:
return
if current_opt is undefined: if current_opt is undefined:
current_opt = self current_opt = self
@ -298,6 +320,7 @@ class Option(OnlyOption):
display_warnings = display_warnings and (setting_properties is undefined or 'warnings' in setting_properties) display_warnings = display_warnings and (setting_properties is undefined or 'warnings' in setting_properties)
def _is_not_unique(value): 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): if display_error and self.impl_is_unique() and len(set(value)) != len(value):
for idx, val in enumerate(value): for idx, val in enumerate(value):
if val in value[idx+1:]: if val in value[idx+1:]:
@ -323,115 +346,79 @@ class Option(OnlyOption):
else: else:
validator_params_ = {'': (val,)} validator_params_ = {'': (val,)}
# Raise ValueError if not valid # Raise ValueError if not valid
value = carry_out_calculation(current_opt, carry_out_calculation(current_opt,
context=context, context=context,
callback=validator, callback=validator,
callback_params=validator_params_, callback_params=validator_params_,
setting_properties=setting_properties, setting_properties=setting_properties,
index=_index, index=_index,
is_validator=True) is_validator=True)
if isinstance(value, Exception):
return value
def do_validation(_value, def do_validation(_value,
_index): _index):
if _value is None: if isinstance(_value, list): # pragma: no cover
error = None raise ValueError(_('invalid value "{}" for "{}" '
else: '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: if display_error:
# option validation # option validation
err = self._validate(_value, self._validate(_value,
context, context,
current_opt) 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 if ((display_error and not is_warnings_only) or
(display_warnings and is_warnings_only)): (display_warnings and is_warnings_only)):
error = calculation_validator(_value, calculation_validator(_value,
_index) _index)
if not error: self._second_level_validation(_value,
error = self._second_level_validation(_value,
is_warnings_only) is_warnings_only)
if error: self._valid_consistency(current_opt,
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, _value,
context, context,
_index, _index,
display_warnings, display_warnings,
display_error, display_error,
setting_properties) setting_properties)
if isinstance(ret, ValueError): except ValueError as err:
error = ret if debug: # pragma: no cover
elif ret: log.debug('do_validation: value: {0}, index: {1}:'
return ret ' {2}'.format(_value,
if error: _index,
err_msg = '{0}'.format(error) err),
if err_msg: exc_info=True)
msg = _('"{0}" is an invalid {1} for "{2}", {3}' if is_warnings_only:
'').format(_value, self._display_name, msg = _('attention, "{0}" could be an invalid {1} for "{2}"'
self.impl_get_display_name(), err_msg) '').format(_value,
self._display_name,
self.impl_get_display_name())
else: else:
msg = _('"{0}" is an invalid {1} for "{2}"' msg = _('"{0}" is an invalid {1} for "{2}"'
'').format(_value, self._display_name, '').format(_value,
self._display_name,
self.impl_get_display_name()) self.impl_get_display_name())
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) raise ValueError(msg)
if is_multi is None: if is_multi is None:
is_multi = self.impl_is_multi() is_multi = self.impl_is_multi()
if not is_multi: if not is_multi:
return do_validation(value, None) do_validation(value, None)
elif force_index is not None: elif force_index is not None:
if self.impl_is_submulti(): if self.impl_is_submulti():
err = _is_not_unique(value) _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()))
for idx, val in enumerate(value): for idx, val in enumerate(value):
if isinstance(val, list): # pragma: no cover do_validation(val,
raise ValueError(_('invalid value "{}" for "{}" ' force_index)
'which must not be a list').format(val,
self.impl_get_display_name()))
err = do_validation(val, force_index)
if err:
return err
else: else:
if multi is not None and self.impl_is_unique() and value in multi: 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: if not self.impl_is_submulti() and len(multi) - 1 >= force_index:
@ -443,42 +430,35 @@ class Option(OnlyOption):
raise ValueError(_('invalid value "{}", this value is already' raise ValueError(_('invalid value "{}", this value is already'
' in "{}"').format(value, ' in "{}"').format(value,
self.impl_get_display_name())) self.impl_get_display_name()))
return do_validation(value, force_index) do_validation(value,
force_index)
elif not isinstance(value, list): elif not isinstance(value, list):
raise ValueError(_('invalid value "{0}" for "{1}" which ' raise ValueError(_('invalid value "{0}" for "{1}" which '
'must be a list').format(value, 'must be a list').format(value,
self.impl_getname())) self.impl_getname()))
elif self.impl_is_submulti(): elif self.impl_is_submulti():
for idx, val in enumerate(value): for idx, val in enumerate(value):
err = _is_not_unique(val) _is_not_unique(val)
if err:
return err
if not isinstance(val, list): if not isinstance(val, list):
raise ValueError(_('invalid value "{0}" for "{1}" ' raise ValueError(_('invalid value "{0}" for "{1}" '
'which must be a list of list' 'which must be a list of list'
'').format(val, '').format(val,
self.impl_getname())) self.impl_getname()))
for slave_val in val: for slave_val in val:
err = do_validation(slave_val, do_validation(slave_val,
idx) idx)
if err:
return err
else: else:
err = _is_not_unique(value) _is_not_unique(value)
if err:
return err
for idx, val in enumerate(value): for idx, val in enumerate(value):
err = do_validation(val, do_validation(val,
idx) idx)
if err: #self._valid_consistency(current_opt,
return err # None,
return self._valid_consistency(current_opt, # context,
None, # None,
context, # display_warnings,
None, # display_error,
display_warnings, # setting_properties)
display_error,
setting_properties)
def impl_is_dynsymlinkoption(self): def impl_is_dynsymlinkoption(self):
return False return False
@ -634,7 +614,7 @@ class Option(OnlyOption):
suffix)) suffix))
else: else:
opts = all_cons_opts opts = all_cons_opts
err = opts[0]()._launch_consistency(self, opts[0]()._launch_consistency(self,
func, func,
option, option,
value, value,
@ -644,8 +624,6 @@ class Option(OnlyOption):
warnings_only, warnings_only,
transitive, transitive,
setting_properties) setting_properties)
if err:
return err
def _cons_not_equal(self, def _cons_not_equal(self,
current_opt, current_opt,

View file

@ -163,11 +163,12 @@ class CacheOptionDescription(BaseOption):
raise ConfigError(_('a dynoption ({0}) cannot have ' raise ConfigError(_('a dynoption ({0}) cannot have '
'force_store_value property').format(subpath)) 'force_store_value property').format(subpath))
if force_store_values and not config._impl_values._p_.hasvalue(subpath, session): if force_store_values and not config._impl_values._p_.hasvalue(subpath, session):
value = config.cfgimpl_get_values().get_cached_value(option, value = impl_build_force_store_values.getvalue(option,
path=subpath, subpath,
validate=False, index=None,
trusted_cached_properties=False, setting_properties=undefined,
validate_properties=True) self_properties=undefined,
validate=False)
value_set = True value_set = True
config._impl_values._p_.setvalue(subpath, value, config._impl_values._p_.setvalue(subpath, value,
owners.forced, None, session, False) owners.forced, None, session, False)

View file

@ -610,9 +610,9 @@ class Settings(object):
#mandatory #mandatory
if 'mandatory' in properties or 'empty' in properties: if 'mandatory' in properties or 'empty' in properties:
value = self._getcontext().cfgimpl_get_values().get_cached_value(opt, value = self._getcontext().cfgimpl_get_values().get_cached_value(opt,
path=path, path,
setting_properties,
validate=False, validate=False,
setting_properties=setting_properties,
self_properties=self_properties, self_properties=self_properties,
index=index) index=index)
if not self.validate_mandatory(opt, if not self.validate_mandatory(opt,

View file

@ -16,13 +16,11 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# ____________________________________________________________ # ____________________________________________________________
from time import time from time import time
import sys
import weakref import weakref
from .error import ConfigError, SlaveError, PropertiesOptionError from .error import ConfigError, PropertiesOptionError
from .setting import owners, expires_time, undefined, forbidden_owners from .setting import owners, expires_time, undefined, forbidden_owners
from .autolib import carry_out_calculation from .autolib import carry_out_calculation
from .i18n import _ from .i18n import _
from .option import DynSymLinkOption, Option
class Values(object): class Values(object):
@ -30,24 +28,29 @@ class Values(object):
but the values are physicaly located here, in `Values`, wich is also but the values are physicaly located here, in `Values`, wich is also
responsible of a caching utility. 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. Initializes the values's dict.
:param context: the context is the home config's values :param context: the context is the home config's values
:param storage: where values or owners are stored
""" """
self.context = weakref.ref(context) self.context = weakref.ref(context)
# the storage type is dictionary or sqlite3 # store the storage
self._p_ = storage self._p_ = storage
#______________________________________________________________________ #______________________________________________________________________
# get context # get context
def _getcontext(self): 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 context is None only if all reference to `Config` object is deleted
(for example we delete a `Config` and we manipulate a reference to (for example we delete a `Config` and we manipulate a reference to
old `SubConfig`, `Values`, `Multi` or `Settings`) old `SubConfig`, `Values`, `Multi` or `Settings`)
@ -62,16 +65,33 @@ class Values(object):
def get_cached_value(self, def get_cached_value(self,
opt, opt,
path=None, path,
setting_properties,
validate=True, validate=True,
force_permissive=False, force_permissive=False,
trusted_cached_properties=True,
setting_properties=undefined,
self_properties=undefined, self_properties=undefined,
index=None, 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 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: if 'expire' in setting_properties:
ntime = int(time()) ntime = int(time())
is_cached, value = self._p_.getcache(path, is_cached, value = self._p_.getcache(path,
@ -81,39 +101,17 @@ class Values(object):
value = value[index] value = value[index]
if is_cached: if is_cached:
return value return value
val = self.get_validated_value(opt,
# no cached value so get value
if validate and 'validator' in setting_properties:
value = self.get_validated_value(opt,
path, path,
validate,
setting_properties, setting_properties,
self_properties, self_properties,
index=index, index=index,
display_warnings=display_warnings, display_warnings=display_warnings,
force_permissive=force_permissive) force_permissive=force_permissive)
if index is None and 'cache' in setting_properties and \ else:
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:
value = self.getvalue(opt, value = self.getvalue(opt,
path, path,
index, index,
@ -121,42 +119,61 @@ class Values(object):
self_properties, self_properties,
validate, validate,
force_permissive=force_permissive) force_permissive=force_permissive)
except ConfigError as value: # store value in cache
value_error = True #FIXME pas de cache pour les slaves !!!
# For calculating properties, we need value (ie for mandatory if index is None and 'cache' in setting_properties and \
# value). validate and force_permissive is False \
# If value is calculating with a PropertiesOptionError's option and trusted_cached_properties is True:
# getvalue raise a ConfigError. if 'expire' in setting_properties:
# We can not raise ConfigError if this option should raise if ntime is None:
# PropertiesOptionError too. So we get config_error and raise ntime = int(time())
# ConfigError if properties did not raise. ntime = ntime + expires_time
config_error = value self._p_.setcache(path, value, ntime, None)
# value is not set, for 'undefined' (cannot set None because of # and return it
# mandatory property) return value
value = undefined
else: def get_validated_value(self,
value_error = False opt,
if validate: path,
err = opt.impl_validate(value, 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, context,
'validator' in setting_properties,
force_index=index, force_index=index,
display_error=True, display_error=True,
display_warnings=False, display_warnings=False,
setting_properties=setting_properties) setting_properties=setting_properties)
if err: if display_warnings:
config_error = err
value = None
if not value_error and validate and display_warnings:
opt.impl_validate(value, opt.impl_validate(value,
context, context,
'validator' in setting_properties,
force_index=index, force_index=index,
display_error=False, display_error=False,
display_warnings=display_warnings, display_warnings=display_warnings,
setting_properties=setting_properties) setting_properties=setting_properties)
if config_error is not None:
raise config_error
return value return value
def getvalue(self, def getvalue(self,
@ -169,19 +186,20 @@ class Values(object):
force_permissive=False): force_permissive=False):
"""actually retrieves the value """actually retrieves the value
:param opt: the `option.Option()` object :param opt: the `Option` that we want to get value
:returns: the option's value (or the default value if not set) :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: # get owner and value from store
settings = self._getcontext().cfgimpl_get_settings() # index allowed only for slave
self_properties = settings.getproperties(opt, is_slave = opt.impl_is_master_slaves('slave')
path, if index is None or not is_slave:
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'):
_index = None _index = None
else: else:
_index = index _index = index
@ -189,9 +207,19 @@ class Values(object):
owners.default, owners.default,
index=_index, index=_index,
with_value=True) with_value=True)
is_default = owner == owners.default
if not is_default and not force_default: if owner != owners.default:
if index is not None and not opt.impl_is_master_slaves('slave'): # 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: if len(value) > index:
return value[index] return value[index]
#value is smaller than expected #value is smaller than expected
@ -688,8 +716,8 @@ class Values(object):
validate=False) validate=False)
fake_value.get_cached_value(opt, fake_value.get_cached_value(opt,
path, path,
setting_properties,
index=index, index=index,
setting_properties=setting_properties,
force_permissive=force_permissive) force_permissive=force_permissive)
self._p_.resetvalue_index(path, index) self._p_.resetvalue_index(path, index)
@ -703,7 +731,7 @@ class Values(object):
current_value = self.get_cached_value(opt, current_value = self.get_cached_value(opt,
path, path,
setting_properties=setting_properties, setting_properties,
force_permissive=force_permissive) force_permissive=force_permissive)
current_value.pop(index) current_value.pop(index)
self.setvalue(opt, self.setvalue(opt,
@ -791,22 +819,22 @@ class Values(object):
path, path,
setting_properties=setting_properties) setting_properties=setting_properties)
if 'mandatory' in self_properties or 'empty' in self_properties: if 'mandatory' in self_properties or 'empty' in self_properties:
err = self.get_cached_value(opt, values = self.get_cached_value(opt,
path=path, path,
setting_properties,
trusted_cached_properties=False, trusted_cached_properties=False,
force_permissive=True, force_permissive=True,
setting_properties=setting_properties,
self_properties=self_properties, self_properties=self_properties,
validate=True, validate=True,
display_warnings=False) display_warnings=False)
if opt.impl_is_master_slaves('slave') and isinstance(err, list): if opt.impl_is_master_slaves('slave') and isinstance(values, list):
for val in err: for val in values:
ret = _is_properties_option(val, path) ret = _is_properties_option(val, path)
if ret is not None: if ret is not None:
yield ret yield ret
break break
else: else:
ret = _is_properties_option(err, path) ret = _is_properties_option(values, path)
if ret is not None: if ret is not None:
yield ret yield ret