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 setting.expires_time = 1
from tiramisu.option import IntOption, OptionDescription from tiramisu.option import IntOption, OptionDescription
from tiramisu.config import Config from tiramisu.config import Config
from tiramisu.error import ConfigError from tiramisu.error import ConfigError, PropertiesOptionError
from time import sleep, time from time import sleep, time

View File

@ -284,7 +284,7 @@ def test_mandatory_dyndescription():
del(cfg.od.dodval1.stval1) del(cfg.od.dodval1.stval1)
cfg.read_only() cfg.read_only()
raises(PropertiesOptionError, "cfg.od.dodval1.stval1") 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(): def test_build_dyndescription_context():
@ -467,7 +467,7 @@ def test_mandatory_dyndescription_context():
del(cfg.od.dodval1.stval1) del(cfg.od.dodval1.stval1)
cfg.read_only() cfg.read_only()
raises(PropertiesOptionError, "cfg.od.dodval1.stval1") 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(): def test_increase_dyndescription_context():

View File

@ -1,12 +1,11 @@
# coding: utf-8 # coding: utf-8
from autopath import do_autopath from autopath import do_autopath
do_autopath() do_autopath()
from time import sleep
from py.test import raises from py.test import raises
from tiramisu.config import Config from tiramisu.config import Config
from tiramisu.option import StrOption, UnicodeOption, OptionDescription from tiramisu.option import IntOption, StrOption, UnicodeOption, OptionDescription, SymLinkOption
from tiramisu.error import PropertiesOptionError from tiramisu.error import PropertiesOptionError, ConfigError
from tiramisu.setting import groups from tiramisu.setting import groups
@ -25,6 +24,61 @@ def make_description():
return descr 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(): def test_mandatory_ro():
descr = make_description() descr = make_description()
config = Config(descr) config = Config(descr)
@ -255,13 +309,12 @@ def test_mandatory_warnings_ro():
except PropertiesOptionError as err: except PropertiesOptionError as err:
proc = err.proptype proc = err.proptype
assert proc == ['mandatory'] 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.read_write()
config.str = 'a' config.str = 'a'
config.read_only() 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'] assert list(config.cfgimpl_get_values().mandatory_warnings(force_permissive=True)) == ['str1', 'unicode2', 'str3']
sleep(.1)
def test_mandatory_warnings_rw(): def test_mandatory_warnings_rw():
@ -270,11 +323,10 @@ def test_mandatory_warnings_rw():
config.str = '' config.str = ''
config.read_write() config.read_write()
config.str 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' 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'] assert list(config.cfgimpl_get_values().mandatory_warnings(force_permissive=True)) == ['str1', 'unicode2', 'str3']
sleep(.1)
def test_mandatory_warnings_disabled(): def test_mandatory_warnings_disabled():
@ -284,11 +336,10 @@ def test_mandatory_warnings_disabled():
setting = config.cfgimpl_get_settings() setting = config.cfgimpl_get_settings()
config.read_write() config.read_write()
config.str 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') 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'] assert list(config.cfgimpl_get_values().mandatory_warnings(force_permissive=True)) == ['str1', 'unicode2', 'str3']
sleep(.1)
def test_mandatory_warnings_hidden(): def test_mandatory_warnings_hidden():
@ -312,11 +363,10 @@ def test_mandatory_warnings_frozen():
setting = config.cfgimpl_get_settings() setting = config.cfgimpl_get_settings()
config.read_write() config.read_write()
config.str 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') setting[descr.str].append('frozen')
config.read_only() config.read_only()
assert config.cfgimpl_get_values().mandatory_warnings() == ['str', 'str1', 'unicode2', 'str3'] assert list(config.cfgimpl_get_values().mandatory_warnings()) == ['str', 'str1', 'unicode2', 'str3']
sleep(.1)
def test_mandatory_master(): def test_mandatory_master():
@ -401,3 +451,60 @@ def test_mandatory_slave():
config.read_only() config.read_only()
assert config.ip_admin_eth0.ip_admin_eth0 == ['ip'] assert config.ip_admin_eth0.ip_admin_eth0 == ['ip']
assert config.ip_admin_eth0.netmask_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 subpath = self._impl_path + '.' + name
return subpath 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 attribute notation mechanism for accessing the value of an option
:param name: attribute name :param name: attribute name
@ -254,7 +255,8 @@ class SubConfig(object):
homeconfig, name = self.cfgimpl_get_home_by_path( homeconfig, name = self.cfgimpl_get_home_by_path(
name, force_permissive=force_permissive) name, force_permissive=force_permissive)
return homeconfig.getattr(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() context = self._cfgimpl_get_context()
option = self.cfgimpl_get_description().__getattr__(name, option = self.cfgimpl_get_description().__getattr__(name,
context=context) context=context)
@ -263,22 +265,26 @@ class SubConfig(object):
return self.cfgimpl_get_values()._get_cached_item( return self.cfgimpl_get_values()._get_cached_item(
option, path=subpath, option, path=subpath,
validate=validate, validate=validate,
force_permissive=force_permissive) force_permissive=force_permissive,
setting_properties=_setting_properties)
elif isinstance(option, SymLinkOption): # pragma: no dynoptiondescription cover elif isinstance(option, SymLinkOption): # pragma: no dynoptiondescription cover
path = context.cfgimpl_get_description().impl_get_path_by_opt( path = context.cfgimpl_get_description().impl_get_path_by_opt(
option._impl_getopt()) option._impl_getopt())
return context.getattr(path, validate=validate, return context.getattr(path, validate=validate,
force_permissive=force_permissive) force_permissive=force_permissive,
_setting_properties=_setting_properties)
elif option.impl_is_optiondescription(): elif option.impl_is_optiondescription():
self.cfgimpl_get_settings().validate_properties( self.cfgimpl_get_settings().validate_properties(
option, True, False, path=subpath, option, True, False, path=subpath,
force_permissive=force_permissive) force_permissive=force_permissive,
setting_properties=_setting_properties)
return SubConfig(option, self._impl_context, subpath) return SubConfig(option, self._impl_context, subpath)
else: else:
return self.cfgimpl_get_values()._get_cached_item( return self.cfgimpl_get_values()._get_cached_item(
option, path=subpath, option, path=subpath,
validate=validate, 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', def find(self, bytype=None, byname=None, byvalue=undefined, type_='option',
check_properties=True, force_permissive=False): check_properties=True, force_permissive=False):

View File

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

View File

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

View File

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