optimise mandatory_warnings

This commit is contained in:
Emmanuel Garette 2015-10-29 09:03:13 +01:00
parent 64e9171ea6
commit a0de1109f7
7 changed files with 307 additions and 135 deletions

View File

@ -6,7 +6,7 @@ from tiramisu import setting
setting.expires_time = 1
from tiramisu.option import IntOption, OptionDescription
from tiramisu.config import Config
from tiramisu.error import ConfigError
from tiramisu.error import ConfigError, PropertiesOptionError
from time import sleep, time

View File

@ -284,7 +284,7 @@ def test_mandatory_dyndescription():
del(cfg.od.dodval1.stval1)
cfg.read_only()
raises(PropertiesOptionError, "cfg.od.dodval1.stval1")
assert cfg.cfgimpl_get_values().mandatory_warnings() == ['od.dodval1.stval1', 'od.dodval2.stval2']
assert list(cfg.cfgimpl_get_values().mandatory_warnings()) == ['od.dodval1.stval1', 'od.dodval2.stval2']
def test_build_dyndescription_context():
@ -467,7 +467,7 @@ def test_mandatory_dyndescription_context():
del(cfg.od.dodval1.stval1)
cfg.read_only()
raises(PropertiesOptionError, "cfg.od.dodval1.stval1")
assert cfg.cfgimpl_get_values().mandatory_warnings() == ['od.dodval1.stval1', 'od.dodval2.stval2']
assert list(cfg.cfgimpl_get_values().mandatory_warnings()) == ['od.dodval1.stval1', 'od.dodval2.stval2']
def test_increase_dyndescription_context():

View File

@ -1,12 +1,11 @@
# coding: utf-8
from autopath import do_autopath
do_autopath()
from time import sleep
from py.test import raises
from tiramisu.config import Config
from tiramisu.option import StrOption, UnicodeOption, OptionDescription
from tiramisu.error import PropertiesOptionError
from tiramisu.option import IntOption, StrOption, UnicodeOption, OptionDescription, SymLinkOption
from tiramisu.error import PropertiesOptionError, ConfigError
from tiramisu.setting import groups
@ -25,6 +24,61 @@ def make_description():
return descr
def return_value(value):
return value
def make_description2():
stroption = StrOption('str', 'Test string option', default="abc",
properties=('mandatory', ))
stroption1 = StrOption('str1', 'Test string option',
properties=('mandatory', ))
stroption2 = SymLinkOption('unicode2', stroption1)
stroption3 = StrOption('str3', 'Test string option', multi=True,
properties=('mandatory', ))
unicode1 = UnicodeOption('unicode1', 'Test string option', callback=return_value, callback_params={'': ((stroption, False),)}, properties=('mandatory', ))
descr = OptionDescription('tiram', '', [stroption, stroption1, stroption2, stroption3, unicode1])
return descr
def make_description_sym():
stroption = StrOption('str', 'Test string option', default="abc",
properties=('mandatory', ))
stroption1 = StrOption('str1', 'Test string option',
properties=('mandatory', ))
stroption2 = SymLinkOption('unicode2', stroption1)
stroption3 = StrOption('str3', 'Test string option', multi=True,
properties=('mandatory', ))
descr = OptionDescription('tiram', '', [stroption, stroption1, stroption2, stroption3])
return descr
def make_description3():
stroption = StrOption('str', 'Test string option', default="abc",
properties=('mandatory', ))
stroption1 = StrOption('str1', 'Test string option',
properties=('mandatory', ))
stroption2 = SymLinkOption('unicode2', stroption1)
stroption3 = StrOption('str3', 'Test string option', multi=True,
properties=('mandatory', ))
unicode1 = UnicodeOption('unicode1', 'Test string option', callback=return_value, callback_params={'': ((stroption, False),)}, properties=('mandatory', ))
int1 = IntOption('int1', '', callback=return_value, callback_params={'': ((stroption, False),)}, properties=('mandatory', ))
descr = OptionDescription('tiram', '', [stroption, stroption1, stroption2, stroption3, unicode1, int1])
return descr
def make_description4():
stroption = StrOption('str', 'Test string option', default="abc",
properties=('mandatory', ))
stroption1 = StrOption('str1', 'Test string option',
properties=('mandatory', ))
stroption2 = UnicodeOption('unicode2', 'Test string option',
properties=('mandatory', ))
stroption3 = StrOption('str3', 'Test string option', multi=True, requires=[{'option': stroption, 'expected': 'yes', 'action': 'mandatory', 'transitive': False}])
descr = OptionDescription('tiram', '', [stroption, stroption1, stroption2, stroption3])
return descr
def test_mandatory_ro():
descr = make_description()
config = Config(descr)
@ -255,13 +309,12 @@ def test_mandatory_warnings_ro():
except PropertiesOptionError as err:
proc = err.proptype
assert proc == ['mandatory']
assert config.cfgimpl_get_values().mandatory_warnings() == ['str', 'str1', 'unicode2', 'str3']
assert list(config.cfgimpl_get_values().mandatory_warnings()) == ['str', 'str1', 'unicode2', 'str3']
config.read_write()
config.str = 'a'
config.read_only()
assert config.cfgimpl_get_values().mandatory_warnings() == ['str1', 'unicode2', 'str3']
assert list(config.cfgimpl_get_values().mandatory_warnings()) == ['str1', 'unicode2', 'str3']
assert list(config.cfgimpl_get_values().mandatory_warnings(force_permissive=True)) == ['str1', 'unicode2', 'str3']
sleep(.1)
def test_mandatory_warnings_rw():
@ -270,11 +323,10 @@ def test_mandatory_warnings_rw():
config.str = ''
config.read_write()
config.str
assert config.cfgimpl_get_values().mandatory_warnings() == ['str', 'str1', 'unicode2', 'str3']
assert list(config.cfgimpl_get_values().mandatory_warnings()) == ['str', 'str1', 'unicode2', 'str3']
config.str = 'a'
assert config.cfgimpl_get_values().mandatory_warnings() == ['str1', 'unicode2', 'str3']
assert list(config.cfgimpl_get_values().mandatory_warnings()) == ['str1', 'unicode2', 'str3']
assert list(config.cfgimpl_get_values().mandatory_warnings(force_permissive=True)) == ['str1', 'unicode2', 'str3']
sleep(.1)
def test_mandatory_warnings_disabled():
@ -284,11 +336,10 @@ def test_mandatory_warnings_disabled():
setting = config.cfgimpl_get_settings()
config.read_write()
config.str
assert config.cfgimpl_get_values().mandatory_warnings() == ['str', 'str1', 'unicode2', 'str3']
assert list(config.cfgimpl_get_values().mandatory_warnings()) == ['str', 'str1', 'unicode2', 'str3']
setting[descr.str].append('disabled')
assert config.cfgimpl_get_values().mandatory_warnings() == ['str1', 'unicode2', 'str3']
assert list(config.cfgimpl_get_values().mandatory_warnings()) == ['str1', 'unicode2', 'str3']
assert list(config.cfgimpl_get_values().mandatory_warnings(force_permissive=True)) == ['str1', 'unicode2', 'str3']
sleep(.1)
def test_mandatory_warnings_hidden():
@ -312,11 +363,10 @@ def test_mandatory_warnings_frozen():
setting = config.cfgimpl_get_settings()
config.read_write()
config.str
assert config.cfgimpl_get_values().mandatory_warnings() == ['str', 'str1', 'unicode2', 'str3']
assert list(config.cfgimpl_get_values().mandatory_warnings()) == ['str', 'str1', 'unicode2', 'str3']
setting[descr.str].append('frozen')
config.read_only()
assert config.cfgimpl_get_values().mandatory_warnings() == ['str', 'str1', 'unicode2', 'str3']
sleep(.1)
assert list(config.cfgimpl_get_values().mandatory_warnings()) == ['str', 'str1', 'unicode2', 'str3']
def test_mandatory_master():
@ -401,3 +451,60 @@ def test_mandatory_slave():
config.read_only()
assert config.ip_admin_eth0.ip_admin_eth0 == ['ip']
assert config.ip_admin_eth0.netmask_admin_eth0 == ['ip']
def test_mandatory_warnings_symlink():
descr = make_description_sym()
config = Config(descr)
config.str = ''
setting = config.cfgimpl_get_settings()
config.read_write()
config.str
assert list(config.cfgimpl_get_values().mandatory_warnings()) == ['str', 'str1', 'unicode2', 'str3']
setting[descr.str].append('frozen')
config.read_only()
assert list(config.cfgimpl_get_values().mandatory_warnings()) == ['str', 'str1', 'unicode2', 'str3']
def test_mandatory_warnings_validate():
descr = make_description3()
config = Config(descr)
config.str = ''
raises(ValueError, "list(config.cfgimpl_get_values().mandatory_warnings())")
assert list(config.cfgimpl_get_values().mandatory_warnings(validate=False)) == ['str', 'str1', 'unicode2', 'str3', 'unicode1', 'int1']
config.str = 'test'
raises(ValueError, "list(config.cfgimpl_get_values().mandatory_warnings())")
assert list(config.cfgimpl_get_values().mandatory_warnings(validate=False)) == ['str1', 'unicode2', 'str3']
def test_mandatory_warnings_validate_empty():
descr = make_description2()
config = Config(descr)
config.str = ''
config.read_only()
raises(ConfigError, "list(config.cfgimpl_get_values().mandatory_warnings())")
assert list(config.cfgimpl_get_values().mandatory_warnings(validate=False)) == ['str', 'str1', 'unicode2', 'str3', 'unicode1']
def test_mandatory_warnings_requires():
descr = make_description4()
config = Config(descr)
config.str = ''
config.read_write()
config.str
assert list(config.cfgimpl_get_values().mandatory_warnings()) == ['str', 'str1', 'unicode2']
config.read_only()
assert list(config.cfgimpl_get_values().mandatory_warnings()) == ['str', 'str1', 'unicode2']
config.read_write()
config.str = 'yes'
assert list(config.cfgimpl_get_values().mandatory_warnings()) == ['str1', 'unicode2', 'str3']
def test_mandatory_od_disabled():
descr = make_description()
od = OptionDescription('od', '', [descr])
config = Config(od)
config.read_only()
assert list(config.cfgimpl_get_values().mandatory_warnings()) == ['tiram.str1', 'tiram.unicode2', 'tiram.str3']
config.cfgimpl_get_settings()[descr].append('disabled')
assert list(config.cfgimpl_get_values().mandatory_warnings()) == []

View File

@ -241,7 +241,8 @@ class SubConfig(object):
subpath = self._impl_path + '.' + name
return subpath
def getattr(self, name, force_permissive=False, validate=True):
def getattr(self, name, force_permissive=False, validate=True,
_setting_properties=undefined):
"""
attribute notation mechanism for accessing the value of an option
:param name: attribute name
@ -254,7 +255,8 @@ class SubConfig(object):
homeconfig, name = self.cfgimpl_get_home_by_path(
name, force_permissive=force_permissive)
return homeconfig.getattr(name, force_permissive=force_permissive,
validate=validate)
validate=validate,
_setting_properties=_setting_properties)
context = self._cfgimpl_get_context()
option = self.cfgimpl_get_description().__getattr__(name,
context=context)
@ -263,22 +265,26 @@ class SubConfig(object):
return self.cfgimpl_get_values()._get_cached_item(
option, path=subpath,
validate=validate,
force_permissive=force_permissive)
force_permissive=force_permissive,
setting_properties=_setting_properties)
elif isinstance(option, SymLinkOption): # pragma: no dynoptiondescription cover
path = context.cfgimpl_get_description().impl_get_path_by_opt(
option._impl_getopt())
return context.getattr(path, validate=validate,
force_permissive=force_permissive)
force_permissive=force_permissive,
_setting_properties=_setting_properties)
elif option.impl_is_optiondescription():
self.cfgimpl_get_settings().validate_properties(
option, True, False, path=subpath,
force_permissive=force_permissive)
force_permissive=force_permissive,
setting_properties=_setting_properties)
return SubConfig(option, self._impl_context, subpath)
else:
return self.cfgimpl_get_values()._get_cached_item(
option, path=subpath,
validate=validate,
force_permissive=force_permissive)
force_permissive=force_permissive,
setting_properties=_setting_properties)
def find(self, bytype=None, byname=None, byvalue=undefined, type_='option',
check_properties=True, force_permissive=False):

View File

@ -115,25 +115,25 @@ class MasterSlaves(object):
def getitem(self, values, opt, path, validate, force_permissive,
force_properties, validate_properties, slave_path=undefined,
slave_value=undefined, setting_properties=undefined, settings=undefined):
slave_value=undefined, setting_properties=undefined, self_properties=undefined):
if self.is_master(opt):
return self._getmaster(values, opt, path, validate,
force_permissive, force_properties,
validate_properties, slave_path,
slave_value, settings)
slave_value, self_properties)
else:
return self._getslave(values, opt, path, validate,
force_permissive, force_properties,
validate_properties, setting_properties, settings)
validate_properties, setting_properties, self_properties)
def _getmaster(self, values, opt, path, validate, force_permissive,
force_properties, validate_properties, c_slave_path,
c_slave_value, settings):
c_slave_value, self_properties):
value = values._get_validated_value(opt, path, validate,
force_permissive,
force_properties,
validate_properties,
settings=settings)
self_properties=self_properties)
if validate is True:
masterlen = len(value)
for slave in self.getslaves(opt):
@ -148,7 +148,7 @@ class MasterSlaves(object):
False,
None, False,
None,
settings=settings)
self_properties=self_properties)
slavelen = len(slave_value)
self.validate_slave_length(masterlen, slavelen, slave.impl_getname(), opt)
except ConfigError: # pragma: optional cover
@ -157,7 +157,7 @@ class MasterSlaves(object):
def _getslave(self, values, opt, path, validate, force_permissive,
force_properties, validate_properties, setting_properties,
settings):
self_properties):
"""
if master has length 0:
return []
@ -192,7 +192,7 @@ class MasterSlaves(object):
validate_properties,
None, # not undefined
with_meta=master_is_meta,
settings=settings)
self_properties=self_properties)
#if slave, had values until master's one
path = opt.impl_getpath(context)
valuelen = len(value)
@ -207,7 +207,7 @@ class MasterSlaves(object):
validate_properties=False,
with_meta=master_is_meta,
index=index,
settings=settings),
self_properties=self_properties),
setitem=False,
force=True,
validate=validate)
@ -218,7 +218,7 @@ class MasterSlaves(object):
path=path,
force_permissive=force_permissive,
force_properties=force_properties,
self_properties=setting_properties)
setting_properties=setting_properties)
return value
def setitem(self, values, opt, value, path):

View File

@ -330,19 +330,19 @@ class Settings(object):
# properties methods
def __contains__(self, propname):
"enables the pythonic 'in' syntaxic sugar"
return propname in self._getproperties()
return propname in self._getproperties(read_write=False)
def __repr__(self):
return str(list(self._getproperties()))
return str(list(self._getproperties(read_write=False)))
def __getitem__(self, opt):
path = opt.impl_getpath(self._getcontext())
return self._getitem(opt, path)
def _getitem(self, opt, path, self_properties=undefined):
def _getitem(self, opt, path, setting_properties=undefined):
return Property(self,
self._getproperties(opt, path,
self_properties=self_properties),
setting_properties=setting_properties),
opt, path)
def __setitem__(self, opt, value): # pragma: optional cover
@ -361,39 +361,43 @@ class Settings(object):
self._getcontext().cfgimpl_reset_cache()
def _getproperties(self, opt=None, path=None,
self_properties=undefined, read_write=True):
setting_properties=undefined, read_write=True,
apply_requires=True):
"""
"""
if opt is None:
props = self._p_.getproperties(path, default_properties)
else:
if self_properties is undefined:
self_properties = self._getproperties()
if setting_properties is undefined:
setting_properties = self._getproperties(read_write=False)
if path is None: # pragma: optional cover
raise ValueError(_('if opt is not None, path should not be'
' None in _getproperties'))
is_cached = False
if 'cache' in self_properties and 'expire' in self_properties:
if apply_requires:
if 'cache' in setting_properties and 'expire' in setting_properties:
ntime = int(time())
else:
ntime = None
if 'cache' in self_properties and self._p_.hascache(path):
if 'cache' in setting_properties and self._p_.hascache(path):
is_cached, props = self._p_.getcache(path, ntime)
if not is_cached:
props = copy(self._p_.getproperties(path, opt.impl_getproperties()))
props |= self.apply_requires(opt, path)
if 'cache' in self_properties:
if 'expire' in self_properties:
props = self._p_.getproperties(path, opt.impl_getproperties())
if apply_requires:
props = copy(props)
props |= self.apply_requires(opt, path, setting_properties)
if 'cache' in setting_properties:
if 'expire' in setting_properties:
ntime = ntime + expires_time
self._p_.setcache(path, props, ntime)
if read_write:
return copy(props)
else:
props = copy(props)
return props
def append(self, propname):
"puts property propname in the Config's properties attribute"
props = self._p_.getproperties(None, default_properties)
if propname not in props:
props.add(propname)
self._setproperties(props, None)
@ -422,7 +426,8 @@ class Settings(object):
#____________________________________________________________
def validate_properties(self, opt_or_descr, is_descr, is_write, path,
value=None, force_permissive=False,
force_properties=None, force_permissives=None,
force_properties=None,
setting_properties=undefined,
self_properties=undefined):
"""
validation upon the properties related to `opt_or_descr`
@ -432,8 +437,6 @@ class Settings(object):
was present
:param force_properties: set() with properties that is force to add
in global properties
:param force_permissives: set() with permissives that is force to add
in global permissives
:param is_descr: we have to know if we are in an option description,
just because the mandatory property
doesn't exist here
@ -443,25 +446,26 @@ class Settings(object):
(typically with the `frozen` property)
"""
# opt properties
if self_properties is undefined:
self_properties = self._getproperties(read_write=False)
if setting_properties is undefined:
setting_properties = self._getproperties(read_write=False)
if self_properties is not undefined:
properties = copy(self_properties)
else:
properties = self._getproperties(opt_or_descr, path,
self_properties=self_properties)
setting_properties=setting_properties)
# remove opt permissive
# permissive affect option's permission with or without permissive
# global property
properties -= self._p_.getpermissive(path)
# remove global permissive if need
if force_permissive is True or 'permissive' in self_properties:
if force_permissive is True or 'permissive' in setting_properties:
properties -= self._p_.getpermissive()
if force_permissives is not None:
properties -= force_permissives
if force_properties is not None:
forced_properties = copy(self_properties)
forced_properties = copy(setting_properties)
forced_properties.update(force_properties)
else:
forced_properties = self_properties
forced_properties = setting_properties
# calc properties
properties &= forced_properties
@ -531,10 +535,16 @@ class Settings(object):
#____________________________________________________________
def _read(self, remove, append):
for prop in remove:
self.remove(prop)
for prop in append:
self.append(prop)
props = self._p_.getproperties(None, default_properties)
modified = False
if remove & props != set([]):
props = props - remove
modified = True
if append & props != append:
props = props | append
modified = True
if modified:
self._setproperties(props, None)
def read_only(self):
"convenience method to freeze, hide and disable"
@ -555,7 +565,7 @@ class Settings(object):
else:
self._p_.reset_all_cache()
def apply_requires(self, opt, path):
def apply_requires(self, opt, path, setting_properties):
"""carries out the jit (just in time) requirements between options
a requirement is a tuple of this form that comes from the option's
@ -616,7 +626,8 @@ class Settings(object):
" '{0}' with requirement on: "
"'{1}'").format(path, reqpath))
try:
value = context.getattr(reqpath, force_permissive=True)
value = context.getattr(reqpath, force_permissive=True,
_setting_properties=setting_properties)
except PropertiesOptionError as err:
if not transitive:
continue

View File

@ -55,7 +55,7 @@ class Values(object):
return context
def _getvalue(self, opt, path, is_default, index=undefined,
with_meta=True, settings=undefined):
with_meta=True, self_properties=undefined):
"""actually retrieves the value
:param opt: the `option.Option()` object
@ -64,11 +64,11 @@ class Values(object):
if opt.impl_is_optiondescription(): # pragma: optional cover
raise ValueError(_('optiondescription has no value'))
if settings is undefined:
settings = self._getcontext().cfgimpl_get_settings()._getproperties(
if self_properties is undefined:
self_properties = self._getcontext().cfgimpl_get_settings()._getproperties(
opt, path, read_write=False)
force_default = 'frozen' in settings and \
'force_default_on_freeze' in settings
force_default = 'frozen' in self_properties and \
'force_default_on_freeze' in self_properties
if not is_default and not force_default:
value = self._p_.getvalue(path)
if index is not undefined:
@ -210,27 +210,37 @@ class Values(object):
def _get_cached_item(self, opt, path=None, validate=True,
force_permissive=False, force_properties=None,
validate_properties=True,
setting_properties=undefined):
setting_properties=undefined, self_properties=undefined):
untrusted_cached_properties = force_properties is None
context = self._getcontext()
if path is None:
path = opt.impl_getpath(self._getcontext())
path = opt.impl_getpath(context)
ntime = None
if setting_properties is undefined:
setting_properties = self._getcontext().cfgimpl_get_settings(
setting_properties = context.cfgimpl_get_settings(
)._getproperties(read_write=False)
settings = self._getcontext().cfgimpl_get_settings()._getproperties(
opt, path, read_write=False, self_properties=setting_properties)
if self_properties is undefined:
self_properties = context.cfgimpl_get_settings()._getproperties(
opt, path, read_write=False, setting_properties=setting_properties)
if 'cache' in setting_properties and self._p_.hascache(path):
if 'expire' in setting_properties:
ntime = int(time())
is_cached, value = self._p_.getcache(path, ntime)
if is_cached:
if opt.impl_is_multi() and not isinstance(value, Multi):
#load value so don't need to validate if is not a Multi
value = Multi(value, self.context, opt, path)
if not untrusted_cached_properties:
# revalidate properties (because not default properties)
context.cfgimpl_get_settings().validate_properties(opt, False, False, value=value,
path=path,
force_permissive=force_permissive,
force_properties=force_properties,
setting_properties=setting_properties,
self_properties=self_properties)
return value
val = self._getitem(opt, path, validate, force_permissive,
force_properties, validate_properties,
setting_properties, settings=settings)
setting_properties, self_properties=self_properties)
if 'cache' in setting_properties and validate and validate_properties \
and force_permissive is False and force_properties is None:
if 'expire' in setting_properties:
@ -242,7 +252,7 @@ class Values(object):
def _getitem(self, opt, path, validate, force_permissive, force_properties,
validate_properties, setting_properties=undefined,
settings=undefined):
self_properties=undefined):
if opt.impl_is_master_slaves():
return opt.impl_get_master_slaves().getitem(self, opt, path,
validate,
@ -250,20 +260,20 @@ class Values(object):
force_properties,
validate_properties,
setting_properties=setting_properties,
settings=settings)
self_properties=self_properties)
else:
return self._get_validated_value(opt, path, validate,
force_permissive,
force_properties,
validate_properties,
setting_properties=setting_properties,
settings=settings)
self_properties=self_properties)
def _get_validated_value(self, opt, path, validate, force_permissive,
force_properties, validate_properties,
index=undefined, submulti_index=undefined,
with_meta=True, setting_properties=undefined,
settings=undefined):
self_properties=undefined):
"""same has getitem but don't touch the cache
index is None for slave value, if value returned is not a list, just return []
"""
@ -271,12 +281,12 @@ class Values(object):
setting = context.cfgimpl_get_settings()
if setting_properties is undefined:
setting_properties = setting._getproperties(read_write=False)
if settings is undefined:
settings = setting._getproperties(opt, path, read_write=False)
if self_properties is undefined:
self_properties = setting._getproperties(opt, path, read_write=False)
is_default = self._is_default_owner(opt, path,
validate_properties=False,
validate_meta=False,
settings=settings)
self_properties=self_properties)
try:
if index is None:
gv_index = undefined
@ -284,7 +294,7 @@ class Values(object):
gv_index = index
value = self._getvalue(opt, path, is_default, index=gv_index,
with_meta=with_meta,
settings=settings)
self_properties=self_properties)
config_error = None
except ConfigError as err:
# For calculating properties, we need value (ie for mandatory
@ -329,7 +339,7 @@ class Values(object):
config_error = err
value = None
if is_default and 'force_store_value' in settings:
if is_default and 'force_store_value' in self_properties:
if isinstance(value, Multi):
item = list(value)
else:
@ -337,11 +347,18 @@ class Values(object):
self.setitem(opt, item, path, is_write=False,
force_permissive=force_permissive)
if validate_properties:
setting.validate_properties(opt, False, False, value=value,
if config_error is not None:
# should not raise PropertiesOptionError if option is
# mandatory
val_props = undefined
else:
val_props = value
setting.validate_properties(opt, False, False, value=val_props,
path=path,
force_permissive=force_permissive,
force_properties=force_properties,
self_properties=setting_properties)
setting_properties=setting_properties,
self_properties=self_properties)
if config_error is not None:
raise config_error
return value
@ -385,7 +402,7 @@ class Values(object):
setting.validate_properties(opt, False, is_write,
value=value, path=path,
force_permissive=force_permissive,
self_properties=setting_properties)
setting_properties=setting_properties)
if isinstance(value, Multi):
value = list(value)
if opt.impl_is_submulti():
@ -398,8 +415,8 @@ class Values(object):
def _is_meta(self, opt, path):
context = self._getcontext()
setting = context.cfgimpl_get_settings()
settings = setting._getproperties(opt, path, read_write=False)
if 'frozen' in settings and 'force_default_on_freeze' in settings:
self_properties = setting._getproperties(opt, path, read_write=False)
if 'frozen' in self_properties and 'force_default_on_freeze' in self_properties:
return False
if self._p_.getowner(path, owners.default) is not owners.default:
return False
@ -424,21 +441,21 @@ class Values(object):
def _getowner(self, opt, path, validate_properties=True,
force_permissive=False, validate_meta=undefined,
settings=undefined):
self_properties=undefined):
"""get owner of an option
"""
if not isinstance(opt, Option) and not isinstance(opt,
DynSymLinkOption):
raise ConfigError(_('owner only avalaible for an option'))
context = self._getcontext()
if settings is undefined:
settings = context.cfgimpl_get_settings()._getproperties(
if self_properties is undefined:
self_properties = context.cfgimpl_get_settings()._getproperties(
opt, path, read_write=False)
if 'frozen' in settings and 'force_default_on_freeze' in settings:
if 'frozen' in self_properties and 'force_default_on_freeze' in self_properties:
return owners.default
if validate_properties:
self._getitem(opt, path, True, force_permissive, None, True,
settings=settings)
self_properties=self_properties)
owner = self._p_.getowner(path, owners.default)
if validate_meta is undefined:
if opt.impl_is_master_slaves('slave'):
@ -490,10 +507,10 @@ class Values(object):
validate_meta=validate_meta)
def _is_default_owner(self, opt, path, validate_properties=True,
validate_meta=True, settings=undefined):
validate_meta=True, self_properties=undefined):
return self._getowner(opt, path, validate_properties,
validate_meta=validate_meta,
settings=settings) == \
self_properties=self_properties) == \
owners.default
def reset_cache(self, only_expired):
@ -528,41 +545,72 @@ class Values(object):
raise ValueError(_("information's item"
" not found: {0}").format(key))
def mandatory_warnings(self, force_permissive=False):
def mandatory_warnings(self, force_permissive=False, validate=True):
"""convenience function to trace Options that are mandatory and
where no value has been set
:returns: generator of mandatory Option's path
:param force_permissive: do raise with permissives properties
:type force_permissive: `bool`
:param validate: validate value when calculating properties
:type validate: `bool`
:returns: generator of mandatory Option's path
"""
def _mandatory_warnings(description):
#if value in cache, properties are not calculated
_ret = []
context = self._getcontext()
settings = context.cfgimpl_get_settings()
setting_properties = context.cfgimpl_get_settings()._getproperties(
read_write=False)
def _mandatory_warnings(description, currpath=None):
if currpath is None:
currpath = []
for opt in description._impl_getchildren(context=context):
name = opt.impl_getname()
path = '.'.join(currpath + [name])
if opt.impl_is_optiondescription():
_ret.extend(_mandatory_warnings(opt))
elif isinstance(opt, SymLinkOption) and \
not isinstance(opt, DynSymLinkOption):
pass
else:
path = opt.impl_getpath(self._getcontext())
try:
self._get_cached_item(opt, path=path,
force_properties=frozenset(('mandatory',)),
settings.validate_properties(opt, True, False, path=path,
force_permissive=force_permissive,
setting_properties=setting_properties)
except PropertiesOptionError as err:
pass
else:
for path in _mandatory_warnings(opt, currpath + [name]):
yield path
else:
if isinstance(opt, SymLinkOption) and \
not isinstance(opt, DynSymLinkOption):
true_opt = opt._impl_getopt()
true_path = descr.impl_get_path_by_opt(true_opt)
else:
true_opt = opt
true_path = path
#FIXME attention c'est réutilisé donc jamais complet ??
self_properties = settings._getproperties(true_opt, true_path,
read_write=False,
setting_properties=setting_properties)
if 'mandatory' in self_properties:
try:
self._get_cached_item(true_opt, path=true_path,
force_properties=frozenset(('mandatory',)),
force_permissive=force_permissive,
setting_properties=setting_properties,
self_properties=self_properties,
validate=validate)
except PropertiesOptionError as err:
if err.proptype == ['mandatory']:
_ret.append(path)
return _ret
self.reset_cache(False)
yield path
except ConfigError as err:
if validate:
raise err
else:
#assume that uncalculated value is an empty value
yield path
descr = self._getcontext().cfgimpl_get_description()
ret = _mandatory_warnings(descr)
self.reset_cache(False)
return ret
for path in _mandatory_warnings(descr):
yield path
def force_cache(self):
"""parse all option to force data in cache
@ -660,7 +708,7 @@ class Multi(list):
self._validate(value, fake_context, index, True)
#assume not checking mandatory property
super(Multi, self).__setitem__(index, value)
context.cfgimpl_get_values()._setvalue(self.opt, self.path, self)
context.cfgimpl_get_values()._setvalue(self.opt, self.path, self, setting_properties=setting_properties)
#def __repr__(self, *args, **kwargs):
# return super(Multi, self).__repr__(*args, **kwargs)