key is now always path and change opt by path dictionary storage

This commit is contained in:
Emmanuel Garette 2013-08-21 22:21:50 +02:00
parent 707a215a2c
commit b6bb685ca5
12 changed files with 297 additions and 242 deletions

View File

@ -20,13 +20,13 @@ def test_cache():
values = c.cfgimpl_get_values()
settings = c.cfgimpl_get_settings()
c.u1
assert od1.u1 in values._p_.get_cached('value', c)
assert od1.u1 in settings._p_.get_cached('property', c)
assert 'u1' in values._p_.get_cached('value', c)
assert 'u1' in settings._p_.get_cached('property', c)
c.u2
assert od1.u1 in values._p_.get_cached('value', c)
assert od1.u1 in settings._p_.get_cached('property', c)
assert od1.u2 in values._p_.get_cached('value', c)
assert od1.u2 in settings._p_.get_cached('property', c)
assert 'u1' in values._p_.get_cached('value', c)
assert 'u1' in settings._p_.get_cached('property', c)
assert 'u2' in values._p_.get_cached('value', c)
assert 'u2' in settings._p_.get_cached('property', c)
def test_cache_reset():
@ -36,44 +36,44 @@ def test_cache_reset():
settings = c.cfgimpl_get_settings()
#when change a value
c.u1
assert od1.u1 in values._p_.get_cached('value', c)
assert od1.u1 in settings._p_.get_cached('property', c)
assert 'u1' in values._p_.get_cached('value', c)
assert 'u1' in settings._p_.get_cached('property', c)
c.u2 = 1
assert od1.u1 not in values._p_.get_cached('value', c)
assert od1.u1 not in settings._p_.get_cached('property', c)
assert 'u1' not in values._p_.get_cached('value', c)
assert 'u1' not in settings._p_.get_cached('property', c)
#when remove a value
c.u1
assert od1.u1 in values._p_.get_cached('value', c)
assert od1.u1 in settings._p_.get_cached('property', c)
assert 'u1' in values._p_.get_cached('value', c)
assert 'u1' in settings._p_.get_cached('property', c)
del(c.u2)
assert od1.u1 not in values._p_.get_cached('value', c)
assert od1.u1 not in settings._p_.get_cached('property', c)
assert 'u1' not in values._p_.get_cached('value', c)
assert 'u1' not in settings._p_.get_cached('property', c)
#when add/del property
c.u1
assert od1.u1 in values._p_.get_cached('value', c)
assert od1.u1 in settings._p_.get_cached('property', c)
assert 'u1' in values._p_.get_cached('value', c)
assert 'u1' in settings._p_.get_cached('property', c)
c.cfgimpl_get_settings()[od1.u2].append('test')
assert od1.u1 not in values._p_.get_cached('value', c)
assert od1.u1 not in settings._p_.get_cached('property', c)
assert 'u1' not in values._p_.get_cached('value', c)
assert 'u1' not in settings._p_.get_cached('property', c)
c.u1
assert od1.u1 in values._p_.get_cached('value', c)
assert od1.u1 in settings._p_.get_cached('property', c)
assert 'u1' in values._p_.get_cached('value', c)
assert 'u1' in settings._p_.get_cached('property', c)
c.cfgimpl_get_settings()[od1.u2].remove('test')
assert od1.u1 not in values._p_.get_cached('value', c)
assert od1.u1 not in settings._p_.get_cached('property', c)
assert 'u1' not in values._p_.get_cached('value', c)
assert 'u1' not in settings._p_.get_cached('property', c)
#when enable/disabled property
c.u1
assert od1.u1 in values._p_.get_cached('value', c)
assert od1.u1 in settings._p_.get_cached('property', c)
assert 'u1' in values._p_.get_cached('value', c)
assert 'u1' in settings._p_.get_cached('property', c)
c.cfgimpl_get_settings().append('test')
assert od1.u1 not in values._p_.get_cached('value', c)
assert od1.u1 not in settings._p_.get_cached('property', c)
assert 'u1' not in values._p_.get_cached('value', c)
assert 'u1' not in settings._p_.get_cached('property', c)
c.u1
assert od1.u1 in values._p_.get_cached('value', c)
assert od1.u1 in settings._p_.get_cached('property', c)
assert 'u1' in values._p_.get_cached('value', c)
assert 'u1' in settings._p_.get_cached('property', c)
c.cfgimpl_get_settings().remove('test')
assert od1.u1 not in values._p_.get_cached('value', c)
assert od1.u1 not in settings._p_.get_cached('property', c)
assert 'u1' not in values._p_.get_cached('value', c)
assert 'u1' not in settings._p_.get_cached('property', c)
def test_cache_reset_multi():
@ -83,32 +83,32 @@ def test_cache_reset_multi():
settings = c.cfgimpl_get_settings()
#when change a value
c.u1
assert od1.u1 in values._p_.get_cached('value', c)
assert od1.u1 in settings._p_.get_cached('property', c)
assert 'u1' in values._p_.get_cached('value', c)
assert 'u1' in settings._p_.get_cached('property', c)
c.u3 = [1]
assert od1.u1 not in values._p_.get_cached('value', c)
assert od1.u1 not in settings._p_.get_cached('property', c)
assert 'u1' not in values._p_.get_cached('value', c)
assert 'u1' not in settings._p_.get_cached('property', c)
#when append value
c.u1
assert od1.u1 in values._p_.get_cached('value', c)
assert od1.u1 in settings._p_.get_cached('property', c)
assert 'u1' in values._p_.get_cached('value', c)
assert 'u1' in settings._p_.get_cached('property', c)
c.u3.append(1)
assert od1.u1 not in values._p_.get_cached('value', c)
assert od1.u1 not in settings._p_.get_cached('property', c)
assert 'u1' not in values._p_.get_cached('value', c)
assert 'u1' not in settings._p_.get_cached('property', c)
#when pop value
c.u1
assert od1.u1 in values._p_.get_cached('value', c)
assert od1.u1 in settings._p_.get_cached('property', c)
assert 'u1' in values._p_.get_cached('value', c)
assert 'u1' in settings._p_.get_cached('property', c)
c.u3.pop(1)
assert od1.u1 not in values._p_.get_cached('value', c)
assert od1.u1 not in settings._p_.get_cached('property', c)
assert 'u1' not in values._p_.get_cached('value', c)
assert 'u1' not in settings._p_.get_cached('property', c)
#when remove a value
c.u1
assert od1.u1 in values._p_.get_cached('value', c)
assert od1.u1 in settings._p_.get_cached('property', c)
assert 'u1' in values._p_.get_cached('value', c)
assert 'u1' in settings._p_.get_cached('property', c)
del(c.u3)
assert od1.u1 not in values._p_.get_cached('value', c)
assert od1.u1 not in settings._p_.get_cached('property', c)
assert 'u1' not in values._p_.get_cached('value', c)
assert 'u1' not in settings._p_.get_cached('property', c)
def test_reset_cache():
@ -117,23 +117,23 @@ def test_reset_cache():
values = c.cfgimpl_get_values()
settings = c.cfgimpl_get_settings()
c.u1
assert od1.u1 in values._p_.get_cached('value', c)
assert od1.u1 in settings._p_.get_cached('property', c)
assert 'u1' in values._p_.get_cached('value', c)
assert 'u1' in settings._p_.get_cached('property', c)
c.cfgimpl_reset_cache()
assert od1.u1 not in values._p_.get_cached('value', c)
assert od1.u1 not in settings._p_.get_cached('property', c)
assert 'u1' not in values._p_.get_cached('value', c)
assert 'u1' not in settings._p_.get_cached('property', c)
c.u1
sleep(1)
c.u2
assert od1.u1 in values._p_.get_cached('value', c)
assert od1.u1 in settings._p_.get_cached('property', c)
assert od1.u2 in values._p_.get_cached('value', c)
assert od1.u2 in settings._p_.get_cached('property', c)
assert 'u1' in values._p_.get_cached('value', c)
assert 'u1' in settings._p_.get_cached('property', c)
assert 'u2' in values._p_.get_cached('value', c)
assert 'u2' in settings._p_.get_cached('property', c)
c.cfgimpl_reset_cache()
assert od1.u1 not in values._p_.get_cached('value', c)
assert od1.u1 not in settings._p_.get_cached('property', c)
assert od1.u2 not in values._p_.get_cached('value', c)
assert od1.u2 not in settings._p_.get_cached('property', c)
assert 'u1' not in values._p_.get_cached('value', c)
assert 'u1' not in settings._p_.get_cached('property', c)
assert 'u2' not in values._p_.get_cached('value', c)
assert 'u2' not in settings._p_.get_cached('property', c)
def test_reset_cache_only_expired():
@ -142,22 +142,22 @@ def test_reset_cache_only_expired():
values = c.cfgimpl_get_values()
settings = c.cfgimpl_get_settings()
c.u1
assert od1.u1 in values._p_.get_cached('value', c)
assert od1.u1 in settings._p_.get_cached('property', c)
assert 'u1' in values._p_.get_cached('value', c)
assert 'u1' in settings._p_.get_cached('property', c)
c.cfgimpl_reset_cache(True)
assert od1.u1 in values._p_.get_cached('value', c)
assert od1.u1 in settings._p_.get_cached('property', c)
assert 'u1' in values._p_.get_cached('value', c)
assert 'u1' in settings._p_.get_cached('property', c)
sleep(1)
c.u2
assert od1.u1 in values._p_.get_cached('value', c)
assert od1.u1 in settings._p_.get_cached('property', c)
assert od1.u2 in values._p_.get_cached('value', c)
assert od1.u2 in settings._p_.get_cached('property', c)
assert 'u1' in values._p_.get_cached('value', c)
assert 'u1' in settings._p_.get_cached('property', c)
assert 'u2' in values._p_.get_cached('value', c)
assert 'u2' in settings._p_.get_cached('property', c)
c.cfgimpl_reset_cache(True)
assert od1.u1 not in values._p_.get_cached('value', c)
assert od1.u1 not in settings._p_.get_cached('property', c)
assert od1.u2 in values._p_.get_cached('value', c)
assert od1.u2 in settings._p_.get_cached('property', c)
assert 'u1' not in values._p_.get_cached('value', c)
assert 'u1' not in settings._p_.get_cached('property', c)
assert 'u2' in values._p_.get_cached('value', c)
assert 'u2' in settings._p_.get_cached('property', c)
def test_reset_cache_only():
@ -166,14 +166,14 @@ def test_reset_cache_only():
values = c.cfgimpl_get_values()
settings = c.cfgimpl_get_settings()
c.u1
assert od1.u1 in values._p_.get_cached('value', c)
assert od1.u1 in settings._p_.get_cached('property', c)
assert 'u1' in values._p_.get_cached('value', c)
assert 'u1' in settings._p_.get_cached('property', c)
c.cfgimpl_reset_cache(only=('values',))
assert od1.u1 not in values._p_.get_cached('value', c)
assert od1.u1 in settings._p_.get_cached('property', c)
assert 'u1' not in values._p_.get_cached('value', c)
assert 'u1' in settings._p_.get_cached('property', c)
c.u1
assert od1.u1 in values._p_.get_cached('value', c)
assert od1.u1 in settings._p_.get_cached('property', c)
assert 'u1' in values._p_.get_cached('value', c)
assert 'u1' in settings._p_.get_cached('property', c)
c.cfgimpl_reset_cache(only=('settings',))
assert od1.u1 in values._p_.get_cached('value', c)
assert od1.u1 not in settings._p_.get_cached('property', c)
assert 'u1' in values._p_.get_cached('value', c)
assert 'u1' not in settings._p_.get_cached('property', c)

View File

@ -39,6 +39,22 @@ def test_base_config():
assert dm._name == 'dummy'
def test_base_path():
gcdummy = BoolOption('dummy', 'dummy', default=False)
descr = OptionDescription('tiramisu', '', [gcdummy])
cfg = Config(descr)
assert cfg._impl_path is None
base = OptionDescription('config', '', [descr])
cfg = Config(base)
assert cfg._impl_path is None
assert cfg.tiramisu._impl_path == 'tiramisu'
nbase = OptionDescription('baseconfig', '', [base])
cfg = Config(nbase)
assert cfg._impl_path is None
assert cfg.config._impl_path == 'config'
assert cfg.config.tiramisu._impl_path == 'config.tiramisu'
def test_reset_value():
descr = make_description()
cfg = Config(descr)

View File

@ -164,3 +164,9 @@ def test_not_meta():
meta.set_contexts('od1.i1', 7)
assert conf1.od1.i1 == conf2.od1.i1 == 7
assert conf1.getowner('od1.i1') is conf2.getowner('od1.i1') is owners.user
def test_meta_path():
meta = make_description()
assert meta._impl_path is None
assert meta.od1._impl_path == 'od1'

View File

@ -494,7 +494,7 @@ def test_callback_hidden():
od2 = OptionDescription('od2', '', [opt2])
maconfig = OptionDescription('rootconfig', '', [od1, od2])
cfg = Config(maconfig)
cfg.cfgimpl_get_settings().set_permissive(('hidden',))
cfg.cfgimpl_get_settings().setpermissive(('hidden',))
cfg.read_write()
raises(PropertiesOptionError, 'cfg.od1.opt1')
cfg.od2.opt2

View File

@ -333,15 +333,15 @@ def test_reset_properties():
setting.reset()
assert setting._p_.get_properties(cfg) == {}
setting[option].append('test')
assert setting._p_.get_properties(cfg) == {option: set(('test',))}
assert setting._p_.get_properties(cfg) == {'gc.dummy': set(('test',))}
setting.reset()
assert setting._p_.get_properties(cfg) == {option: set(('test',))}
assert setting._p_.get_properties(cfg) == {'gc.dummy': set(('test',))}
setting.append('frozen')
assert setting._p_.get_properties(cfg) == {None: set(('frozen', 'expire', 'validator')), option: set(('test',))}
assert setting._p_.get_properties(cfg) == {None: set(('frozen', 'expire', 'validator')), 'gc.dummy': set(('test',))}
setting.reset(option)
assert setting._p_.get_properties(cfg) == {None: set(('frozen', 'expire', 'validator'))}
setting[option].append('test')
assert setting._p_.get_properties(cfg) == {None: set(('frozen', 'expire', 'validator')), option: set(('test',))}
assert setting._p_.get_properties(cfg) == {None: set(('frozen', 'expire', 'validator')), 'gc.dummy': set(('test',))}
setting.reset(all_properties=True)
assert setting._p_.get_properties(cfg) == {}
raises(ValueError, 'setting.reset(all_properties=True, opt=option)')

View File

@ -21,7 +21,7 @@ def test_permissive():
except PropertiesOptionError, err:
props = err.proptype
assert props == ['disabled']
setting.set_permissive(('disabled',))
setting.setpermissive(('disabled',))
props = []
try:
config.u1
@ -50,7 +50,7 @@ def test_permissive_mandatory():
except PropertiesOptionError, err:
props = err.proptype
assert props == ['disabled', 'mandatory']
setting.set_permissive(('mandatory', 'disabled',))
setting.setpermissive(('mandatory', 'disabled',))
setting.append('permissive')
config.u1
setting.remove('permissive')
@ -66,7 +66,7 @@ def test_permissive_frozen():
config = Config(descr)
setting = config.cfgimpl_get_settings()
config.read_write()
setting.set_permissive(('frozen', 'disabled',))
setting.setpermissive(('frozen', 'disabled',))
try:
config.u1 = 1
except PropertiesOptionError, err:

View File

@ -35,15 +35,16 @@ def gen_id(config):
class SubConfig(BaseInformation):
"sub configuration management entry"
__slots__ = ('_impl_context', '_impl_descr')
__slots__ = ('_impl_context', '_impl_descr', '_impl_path')
def __init__(self, descr, context):
def __init__(self, descr, context, subpath=None):
""" Configuration option management master class
:param descr: describes the configuration schema
:type descr: an instance of ``option.OptionDescription``
:param context: the current root config
:type context: `Config`
:type subpath: `str` with the path name
"""
# main option description
if not isinstance(descr, OptionDescription):
@ -54,6 +55,7 @@ class SubConfig(BaseInformation):
if not isinstance(context, SubConfig):
raise ValueError('context must be a SubConfig')
self._impl_context = context
self._impl_path = subpath
def cfgimpl_reset_cache(self, only_expired=False, only=('values',
'settings')):
@ -183,7 +185,11 @@ class SubConfig(BaseInformation):
return homeconfig.__setattr__(name, value)
child = getattr(self.cfgimpl_get_description(), name)
if not isinstance(child, SymLinkOption):
self.cfgimpl_get_values().setitem(child, value,
if self._impl_path is None:
path = name
else:
path = self._impl_path + '.' + name
self.cfgimpl_get_values().setitem(child, value, path,
force_permissive=force_permissive)
else:
context = self.cfgimpl_get_context()
@ -193,7 +199,7 @@ class SubConfig(BaseInformation):
def __delattr__(self, name):
child = getattr(self.cfgimpl_get_description(), name)
del(self.cfgimpl_get_values()[child])
self.cfgimpl_get_values().__delitem__(child)
def __getattr__(self, name):
return self._getattr(name)
@ -222,6 +228,10 @@ class SubConfig(BaseInformation):
return object.__getattribute__(self, name)
opt_or_descr = getattr(self.cfgimpl_get_description(), name)
# symlink options
if self._impl_path is None:
subpath = name
else:
subpath = self._impl_path + '.' + name
if isinstance(opt_or_descr, SymLinkOption):
context = self.cfgimpl_get_context()
path = context.cfgimpl_get_description().impl_get_path_by_opt(
@ -231,12 +241,13 @@ class SubConfig(BaseInformation):
force_permissive=force_permissive)
elif isinstance(opt_or_descr, OptionDescription):
self.cfgimpl_get_settings().validate_properties(
opt_or_descr, True, False, force_permissive=force_permissive,
opt_or_descr, True, False, path=subpath,
force_permissive=force_permissive,
force_properties=force_properties)
return SubConfig(opt_or_descr, self.cfgimpl_get_context())
return SubConfig(opt_or_descr, self.cfgimpl_get_context(), subpath)
else:
return self.cfgimpl_get_values().getitem(
opt_or_descr,
opt_or_descr, path=subpath,
validate=validate,
force_properties=force_properties,
force_permissive=force_permissive)
@ -555,6 +566,7 @@ class MetaConfig(CommonConfig):
if not isinstance(children, list):
raise ValueError(_("metaconfig's children must be a list"))
self._impl_descr = None
self._impl_path = None
if meta:
for child in children:
if not isinstance(child, CommonConfig):

View File

@ -152,24 +152,25 @@ populate_multitypes()
class Property(object):
"a property is responsible of the option's value access rules"
__slots__ = ('_setting', '_properties', '_opt')
__slots__ = ('_setting', '_properties', '_opt', '_path')
def __init__(self, setting, prop, opt=None):
def __init__(self, setting, prop, opt=None, path=None):
self._opt = opt
self._path = path
self._setting = setting
self._properties = prop
def append(self, propname):
self._properties.add(propname)
self._setting._setproperties(self._properties, self._opt)
self._setting._setproperties(self._properties, self._opt, self._path)
def remove(self, propname):
if propname in self._properties:
self._properties.remove(propname)
self._setting._setproperties(self._properties, self._opt)
self._setting._setproperties(self._properties, self._opt, self._path)
def reset(self):
self._setting.reset(opt=self._opt)
self._setting.reset(path=self._path)
def __contains__(self, propname):
return propname in self._properties
@ -200,15 +201,6 @@ class Settings(object):
self._p_ = __import__(import_lib, globals(), locals(), ['Settings'],
-1).Settings(storage)
def _getkey(self, opt):
if self._p_.key_is_path:
if opt is None:
return '_none'
else:
return self._get_opt_path(opt)
else:
return opt
#____________________________________________________________
# properties methods
def __contains__(self, propname):
@ -219,7 +211,14 @@ class Settings(object):
return str(list(self._getproperties()))
def __getitem__(self, opt):
return Property(self, self._getproperties(opt), opt)
if opt is None:
path = None
else:
path = self._get_opt_path(opt)
return self._getitem(opt, path)
def _getitem(self, opt, path):
return Property(self, self._getproperties(opt, path), opt, path)
def __setitem__(self, opt, value):
raise ValueError('you must only append/remove properties')
@ -231,26 +230,32 @@ class Settings(object):
if all_properties:
self._p_.reset_all_propertives()
else:
self._p_.reset_properties(self._getkey(opt))
if opt is None:
path = None
else:
path = self._get_opt_path(opt)
self._p_.reset_properties(path)
self.context.cfgimpl_reset_cache()
def _getproperties(self, opt=None, is_apply_req=True):
def _getproperties(self, opt=None, path=None, is_apply_req=True):
if opt is None:
props = self._p_.getproperties(self._getkey(opt), default_properties)
props = self._p_.getproperties(path, default_properties)
else:
if path is None:
raise ValueError(_('if opt is not None, path should not be None in _getproperties'))
ntime = None
if self._p_.hascache('property', self._getkey(opt)):
if self._p_.hascache('property', path):
ntime = time()
is_cached, props = self._p_.getcache('property', self._getkey(opt), ntime)
is_cached, props = self._p_.getcache('property', path, ntime)
if is_cached:
return props
if is_apply_req:
self.apply_requires(opt)
props = self._p_.getproperties(self._getkey(opt), opt._properties)
self.apply_requires(opt, path)
props = self._p_.getproperties(path, opt._properties)
if 'expire' in self:
if ntime is None:
ntime = time()
self._p_.setcache('property', self._getkey(opt), props, ntime + expires_time)
self._p_.setcache('property', path, props, ntime + expires_time)
return props
def append(self, propname):
@ -261,21 +266,21 @@ class Settings(object):
"deletes property propname in the Config's properties attribute"
Property(self, self._getproperties()).remove(propname)
def _setproperties(self, properties, opt=None):
def _setproperties(self, properties, opt, path):
"""save properties for specified opt
(never save properties if same has option properties)
"""
if opt is None:
self._p_.setproperties(self._getkey(opt), properties)
self._p_.setproperties(path, properties)
else:
if set(opt._properties) == properties:
self._p_.reset_properties(self._getkey(opt))
self._p_.reset_properties(path)
else:
self._p_.setproperties(self._getkey(opt), properties)
self._p_.setproperties(path, properties)
self.context.cfgimpl_reset_cache()
#____________________________________________________________
def validate_properties(self, opt_or_descr, is_descr, is_write,
def validate_properties(self, opt_or_descr, is_descr, is_write, path,
value=None, force_permissive=False,
force_properties=None):
"""
@ -291,9 +296,9 @@ class Settings(object):
property)
"""
# opt properties
properties = copy(self._getproperties(opt_or_descr))
properties = copy(self._getproperties(opt_or_descr, path))
# remove opt permissive
properties -= self._p_.getpermissive(self._getkey(opt_or_descr))
properties -= self._p_.getpermissive(path)
# remove global permissive if need
self_properties = copy(self._getproperties())
if force_permissive is True or 'permissive' in self_properties:
@ -332,11 +337,10 @@ class Settings(object):
"").format(opt_or_descr._name,
str(props)), props)
# XXX should rename it to setpermissive, but kept for retro compatibility
def set_permissive(self, permissive, opt=None):
def setpermissive(self, permissive, path=None):
if not isinstance(permissive, tuple):
raise TypeError(_('permissive must be a tuple'))
self._p_.setpermissive(self._getkey(opt), permissive)
self._p_.setpermissive(path, permissive)
#____________________________________________________________
def setowner(self, owner):
@ -369,28 +373,27 @@ class Settings(object):
else:
self._p_.reset_all_cache('property')
def apply_requires(self, opt):
def apply_requires(self, opt, path):
"carries out the jit (just in time requirements between options"
if opt._requires is None:
return
# filters the callbacks
setting = Property(self, self._getproperties(opt, False), opt)
setting = Property(self, self._getproperties(opt, path, False), opt, path=path)
descr = self.context.cfgimpl_get_description()
optpath = descr.impl_get_path_by_opt(opt)
for requires in opt._requires:
matches = False
for require in requires:
option, expected, action, inverse, \
transitive, same_action = require
path = descr.impl_get_path_by_opt(option)
if path == optpath or path.startswith(optpath + '.'):
reqpath = self._get_opt_path(option)
if reqpath == path or reqpath.startswith(path + '.'):
raise RequirementError(_("malformed requirements "
"imbrication detected for option:"
" '{0}' with requirement on: "
"'{1}'").format(optpath, path))
"'{1}'").format(path, reqpath))
try:
value = self.context._getattr(path, force_permissive=True)
value = self.context._getattr(reqpath, force_permissive=True)
except PropertiesOptionError, err:
if not transitive:
continue
@ -400,14 +403,14 @@ class Settings(object):
"requirement's property "
"error: "
"{1} {2}").format(opt._name,
path,
reqpath,
properties))
# transitive action, force expected
value = expected[0]
inverse = False
except AttributeError:
raise AttributeError(_("required option not found: "
"{0}").format(path))
"{0}").format(reqpath))
if (not inverse and
value in expected or
inverse and value not in expected):

View File

@ -32,21 +32,21 @@ class Settings(Cache):
super(Settings, self).__init__()
# propertives
def setproperties(self, opt, properties):
self._properties[opt] = properties
def setproperties(self, path, properties):
self._properties[path] = properties
def getproperties(self, opt, default_properties):
return self._properties.get(opt, set(default_properties))
def getproperties(self, path, default_properties):
return self._properties.get(path, set(default_properties))
def hasproperties(self, opt):
return opt in self._properties
def hasproperties(self, path):
return path in self._properties
def reset_all_propertives(self):
self._properties.clear()
def reset_properties(self, opt):
def reset_properties(self, path):
try:
del(self._properties[opt])
del(self._properties[path])
except KeyError:
pass
@ -54,8 +54,8 @@ class Settings(Cache):
return self._properties
# permissive
def setpermissive(self, opt, permissive):
self._permissives[opt] = frozenset(permissive)
def setpermissive(self, path, permissive):
self._permissives[path] = frozenset(permissive)
def getpermissive(self, opt=None):
return self._permissives.get(opt, frozenset())
def getpermissive(self, path=None):
return self._permissives.get(path, frozenset())

View File

@ -36,22 +36,22 @@ class Cache(object):
def __init__(self):
self._cache = {}
def setcache(self, cache_type, opt, val, time):
self._cache[opt] = (val, time)
def setcache(self, cache_type, path, val, time):
self._cache[path] = (val, time)
def getcache(self, cache_type, opt, exp):
value, created = self._cache[opt]
def getcache(self, cache_type, path, exp):
value, created = self._cache[path]
if exp < created:
return True, value
return False, None
def hascache(self, cache_type, opt):
""" option is in the cache
def hascache(self, cache_type, path):
""" path is in the cache
:param cache_type: value | property
:param opt: the key (typically, the option object)
:param path: the path's option
"""
return opt in self._cache
return path in self._cache
def reset_expired_cache(self, cache_type, exp):
keys = self._cache.keys()
@ -66,6 +66,6 @@ class Cache(object):
def get_cached(self, cache_type, context):
"""return all values in a dictionary
example: {option1: ('value1', 'time1'), option2: ('value2', 'time2')}
example: {'path1': ('value1', 'time1'), 'path2': ('value2', 'time2')}
"""
return self._cache

View File

@ -32,43 +32,43 @@ class Values(Cache):
super(Values, self).__init__()
# value
def setvalue(self, opt, value, owner):
"""set value for an option
def setvalue(self, path, value, owner):
"""set value for a path
a specified value must be associated to an owner
"""
self._values[opt] = (owner, value)
self._values[path] = (owner, value)
def getvalue(self, opt):
"""get value for an option
def getvalue(self, path):
"""get value for a path
return: only value, not the owner
"""
return self._values[opt][1]
return self._values[path][1]
def hasvalue(self, opt):
"""if opt has a value
def hasvalue(self, path):
"""if path has a value
return: boolean
"""
return opt in self._values
return path in self._values
def resetvalue(self, opt):
def resetvalue(self, path):
"""remove value means delete value in storage
"""
del(self._values[opt])
del(self._values[path])
def get_modified_values(self):
"""return all values in a dictionary
example: {option1: (owner, 'value1'), option2: (owner, 'value2')}
example: {'path1': (owner, 'value1'), 'path2': (owner, 'value2')}
"""
return self._values
# owner
def setowner(self, opt, owner):
"""change owner for an option
def setowner(self, path, owner):
"""change owner for a path
"""
self._values[opt] = (owner, self._values[opt][1])
self._values[path] = (owner, self._values[path][1])
def getowner(self, opt, default):
"""get owner for an option
def getowner(self, path, default):
"""get owner for a path
return: owner object
"""
return self._values.get(opt, (default, None))[0]
return self._values.get(path, (default, None))[0]

View File

@ -46,15 +46,6 @@ class Values(object):
self._p_ = __import__(import_lib, globals(), locals(), ['Values'],
-1).Values(storage)
def _getkey(self, opt):
"""depends on the storage utility.
typically, the option's path in the parent `Config` or `SubConfig`
"""
if self._p_.key_is_path:
return self._get_opt_path(opt)
else:
return opt
def _getdefault(self, opt):
"""
actually retrieves the default value
@ -71,24 +62,23 @@ class Values(object):
else:
return value
def _getvalue(self, opt, validate=True):
def _getvalue(self, opt, path, validate=True):
"""actually retrieves the value
:param opt: the `option.Option()` object
:returns: the option's value (or the default value if not set)
"""
key = self._getkey(opt)
if not self._p_.hasvalue(key):
if not self._p_.hasvalue(path):
# if there is no value
value = self._getdefault(opt)
if opt.impl_is_multi():
value = Multi(value, self.context, opt, validate)
value = Multi(value, self.context, opt, path, validate)
else:
# if there is a value
value = self._p_.getvalue(key)
value = self._p_.getvalue(path)
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, validate=False)
value = Multi(value, self.context, opt, path, validate=False)
return value
def get_modified_values(self):
@ -101,15 +91,20 @@ class Values(object):
:param opt: the `option.Option()` object
"""
return self._p_.hasvalue('value', self._getkey(opt))
path = self._get_opt_path(opt)
self._contains(path)
def _contains(self, path):
return self._p_.hasvalue('value', path)
def __delitem__(self, opt):
"""overrides the builtins `del()` instructions"""
self.reset(opt)
def reset(self, opt):
key = self._getkey(opt)
if self._p_.hasvalue(key):
def reset(self, opt, path=None):
if path is None:
path = self._get_opt_path(opt)
if self._p_.hasvalue(path):
setting = self.context.cfgimpl_get_settings()
opt.impl_validate(opt.impl_getdefault(), self.context,
'validator' in setting)
@ -118,7 +113,7 @@ class Values(object):
opt.impl_get_multitype() == multitypes.master):
for slave in opt.impl_get_master_slaves():
self.reset(slave)
self._p_.resetvalue(key)
self._p_.resetvalue(path)
def _isempty(self, opt, value):
"convenience method to know if an option is empty"
@ -150,30 +145,31 @@ class Values(object):
"enables us to use the pythonic dictionnary-like access to values"
return self.getitem(opt)
def getitem(self, opt, validate=True, force_permissive=False,
def getitem(self, opt, path=None, validate=True, force_permissive=False,
force_properties=None, validate_properties=True):
ntime = None
key = self._getkey(opt)
if self._p_.hascache('value', self._getkey(opt)):
if path is None:
path = self._get_opt_path(opt)
if self._p_.hascache('value', path):
ntime = time()
is_cached, value = self._p_.getcache('value', key, ntime)
is_cached, value = self._p_.getcache('value', 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, validate=False)
value = Multi(value, self.context, opt, path, validate=False)
return value
val = self._getitem(opt, validate, force_permissive, force_properties,
val = self._getitem(opt, path, validate, force_permissive, force_properties,
validate_properties)
if 'expire' in self.context.cfgimpl_get_settings() and validate and \
validate_properties and force_permissive is False and \
force_properties is None:
if ntime is None:
ntime = time()
self._p_.setcache('value', key, val, ntime + expires_time)
self._p_.setcache('value', path, val, ntime + expires_time)
return val
def _getitem(self, opt, validate, force_permissive, force_properties,
def _getitem(self, opt, path, validate, force_permissive, force_properties,
validate_properties):
# options with callbacks
setting = self.context.cfgimpl_get_settings()
@ -181,7 +177,7 @@ class Values(object):
# if value is callback and is not set
# or frozen with force_default_on_freeze
if opt.impl_has_callback() and (
self.is_default_owner(opt) or
self._is_default_owner(path) or
(is_frozen and 'force_default_on_freeze' in setting[opt])):
no_value_slave = False
if (opt.impl_is_multi() and
@ -200,53 +196,55 @@ class Values(object):
if not isinstance(value, list):
value = [value for i in range(lenmaster)]
if opt.impl_is_multi():
value = Multi(value, self.context, opt, validate)
value = Multi(value, self.context, opt, path, validate)
# suppress value if already set
self.reset(opt)
self.reset(opt, path)
# frozen and force default
elif is_frozen and 'force_default_on_freeze' in setting[opt]:
value = self._getdefault(opt)
if opt.impl_is_multi():
value = Multi(value, self.context, opt, validate)
value = Multi(value, self.context, opt, path, validate)
else:
value = self._getvalue(opt, validate)
value = self._getvalue(opt, path, validate)
if validate:
opt.impl_validate(value, self.context, 'validator' in setting)
if self.is_default_owner(opt) and \
if self._is_default_owner(path) and \
'force_store_value' in setting[opt]:
self.setitem(opt, value, is_write=False)
self.setitem(opt, value, path, is_write=False)
if validate_properties:
setting.validate_properties(opt, False, False, value=value,
setting.validate_properties(opt, False, False, value=value, path=path,
force_permissive=force_permissive,
force_properties=force_properties)
return value
def __setitem__(self, opt, value):
self.setitem(opt, value)
path = self._get_opt_path(opt)
self.setitem(opt, value, path)
def setitem(self, opt, value, force_permissive=False, is_write=True):
def setitem(self, opt, value, path, force_permissive=False,
is_write=True):
# is_write is, for example, used with "force_store_value"
# user didn't change value, so not write
# valid opt
opt.impl_validate(value, self.context,
'validator' in self.context.cfgimpl_get_settings())
if opt.impl_is_multi() and not isinstance(value, Multi):
value = Multi(value, self.context, opt)
self._setvalue(opt, value, force_permissive=force_permissive,
value = Multi(value, self.context, opt, path)
self._setvalue(opt, path, value, force_permissive=force_permissive,
is_write=is_write)
def _setvalue(self, opt, value, force_permissive=False,
def _setvalue(self, opt, path, value, force_permissive=False,
force_properties=None,
is_write=True, validate_properties=True):
self.context.cfgimpl_reset_cache()
if validate_properties:
setting = self.context.cfgimpl_get_settings()
setting.validate_properties(opt, False, is_write,
value=value,
value=value, path=path,
force_permissive=force_permissive,
force_properties=force_properties)
owner = self.context.cfgimpl_get_settings().getowner()
self._p_.setvalue(self._getkey(opt), value, owner)
self._p_.setvalue(path, value, owner)
def getowner(self, opt):
"""
@ -257,10 +255,14 @@ class Values(object):
"""
if isinstance(opt, SymLinkOption):
opt = opt._opt
owner = self._p_.getowner(self._getkey(opt), owners.default)
path = self._get_opt_path(opt)
return self._getowner(path)
def _getowner(self, path):
owner = self._p_.getowner(path, owners.default)
meta = self.context.cfgimpl_get_meta()
if owner is owners.default and meta is not None:
owner = meta.cfgimpl_get_values().getowner(opt)
owner = meta.cfgimpl_get_values()._getowner(path)
return owner
def setowner(self, opt, owner):
@ -272,10 +274,15 @@ class Values(object):
"""
if not isinstance(owner, owners.Owner):
raise TypeError(_("invalid generic owner {0}").format(str(owner)))
if self.getowner(opt) == owners.default:
path = self._get_opt_path(opt)
self._setowner(path, owner)
def _setowner(self, path, owner):
if self._getowner(path) == owners.default:
raise ConfigError(_('no value for {0} cannot change owner to {1}'
'').format(opt._name, owner))
self._p_.setowner(self._getkey(opt), owner)
'').format(path, owner))
self._p_.setowner(path, owner)
def is_default_owner(self, opt):
"""
@ -283,7 +290,11 @@ class Values(object):
(not the toplevel config)
:return: boolean
"""
return self.getowner(opt) == owners.default
path = self._get_opt_path(opt)
return self._is_default_owner(path)
def _is_default_owner(self, path):
return self._getowner(path) == owners.default
def reset_cache(self, only_expired):
"""
@ -310,15 +321,16 @@ class Values(object):
class Multi(list):
"""multi options values container
that support item notation for the values of multi options"""
__slots__ = ('opt', 'context')
__slots__ = ('opt', 'path', 'context')
def __init__(self, value, context, opt, validate=True):
def __init__(self, value, context, opt, path, validate=True):
"""
:param value: the Multi wraps a list value
:param context: the home config that has the values
:param opt: the option object that have this Multi value
"""
self.opt = opt
self.path = path
self.context = context
if not isinstance(value, list):
value = [value]
@ -337,7 +349,7 @@ class Multi(list):
valuelen = len(value)
if valuelen > masterlen or (valuelen < masterlen and
not self.context.cfgimpl_get_values(
).is_default_owner(self.opt)):
)._is_default_owner(self.path)):
raise SlaveError(_("invalid len for the slave: {0}"
" which has {1} as master").format(
self.opt._name, masterp))
@ -351,8 +363,9 @@ class Multi(list):
masterlen = len(value)
values = self.context.cfgimpl_get_values()
for slave in self.opt._master_slaves:
if not values.is_default_owner(slave):
value_slave = values._getvalue(slave)
path = values._get_opt_path(slave)
if not values._is_default_owner(path):
value_slave = values._getvalue(slave, path)
if len(value_slave) > masterlen:
raise SlaveError(_("invalid len for the master: {0}"
" which has {1} as slave with"
@ -363,11 +376,11 @@ class Multi(list):
value_slave.append(slave.impl_getdefault_multi(),
force=True)
def __setitem__(self, key, value):
def __setitem__(self, path, value):
self._validate(value)
#assume not checking mandatory property
super(Multi, self).__setitem__(key, value)
self.context.cfgimpl_get_values()._setvalue(self.opt, self)
super(Multi, self).__setitem__(path, value)
self.context.cfgimpl_get_values()._setvalue(self.opt, path, self)
def append(self, value, force=False):
"""the list value can be updated (appened)
@ -386,21 +399,26 @@ class Multi(list):
value = None
self._validate(value)
super(Multi, self).append(value)
self.context.cfgimpl_get_values()._setvalue(self.opt, self, validate_properties=not force)
self.context.cfgimpl_get_values()._setvalue(self.opt, self.path, self, validate_properties=not force)
if not force and self.opt.impl_get_multitype() == multitypes.master:
for slave in self.opt.impl_get_master_slaves():
if not values.is_default_owner(slave):
path = values._get_opt_path(slave)
if not values._is_default_owner(path):
if slave.impl_has_callback():
index = self.__len__() - 1
dvalue = values._getcallback_value(slave, index=index)
else:
dvalue = slave.impl_getdefault_multi()
old_value = values.getitem(slave, validate_properties=False)
old_value = values.getitem(slave, path,
validate_properties=False)
if len(old_value) < self.__len__():
values.getitem(slave, validate_properties=False).append(
dvalue, force=True)
values.getitem(slave, path,
validate_properties=False).append(
dvalue, force=True)
else:
values.getitem(slave, validate_properties=False)[index] = dvalue
values.getitem(slave, path,
validate_properties=False)[
index] = dvalue
def sort(self, cmp=None, key=None, reverse=False):
if self.opt.impl_get_multitype() in [multitypes.slave,
@ -408,7 +426,7 @@ class Multi(list):
raise SlaveError(_("cannot sort multi option {0} if master or slave"
"").format(self.opt._name))
super(Multi, self).sort(cmp=cmp, key=key, reverse=reverse)
self.context.cfgimpl_get_values()._setvalue(self.opt, self)
self.context.cfgimpl_get_values()._setvalue(self.opt, self.path, self)
def reverse(self):
if self.opt.impl_get_multitype() in [multitypes.slave,
@ -416,7 +434,7 @@ class Multi(list):
raise SlaveError(_("cannot reverse multi option {0} if master or "
"slave").format(self.opt._name))
super(Multi, self).reverse()
self.context.cfgimpl_get_values()._setvalue(self.opt, self)
self.context.cfgimpl_get_values()._setvalue(self.opt, self.path, self)
def insert(self, index, obj):
if self.opt.impl_get_multitype() in [multitypes.slave,
@ -424,7 +442,7 @@ class Multi(list):
raise SlaveError(_("cannot insert multi option {0} if master or "
"slave").format(self.opt._name))
super(Multi, self).insert(index, obj)
self.context.cfgimpl_get_values()._setvalue(self.opt, self)
self.context.cfgimpl_get_values()._setvalue(self.opt, self.path, self)
def extend(self, iterable):
if self.opt.impl_get_multitype() in [multitypes.slave,
@ -432,7 +450,7 @@ class Multi(list):
raise SlaveError(_("cannot extend multi option {0} if master or "
"slave").format(self.opt._name))
super(Multi, self).extend(iterable)
self.context.cfgimpl_get_values()._setvalue(self.opt, self)
self.context.cfgimpl_get_values()._setvalue(self.opt, self.path, self)
def _validate(self, value):
if value is not None:
@ -465,5 +483,5 @@ class Multi(list):
).pop(key, force=True)
#set value without valid properties
ret = super(Multi, self).pop(key)
self.context.cfgimpl_get_values()._setvalue(self.opt, self, validate_properties=not force)
self.context.cfgimpl_get_values()._setvalue(self.opt, self.path, self, validate_properties=not force)
return ret