From b6bb685ca571493ec0800ab959b8156139378f4f Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Wed, 21 Aug 2013 22:21:50 +0200 Subject: [PATCH] key is now always path and change opt by path dictionary storage --- test/test_cache.py | 156 ++++++++++++------------- test/test_config.py | 16 +++ test/test_metaconfig.py | 6 + test/test_option_calculation.py | 2 +- test/test_option_setting.py | 8 +- test/test_permissive.py | 6 +- tiramisu/config.py | 26 +++-- tiramisu/setting.py | 87 +++++++------- tiramisu/storage/dictionary/setting.py | 24 ++-- tiramisu/storage/dictionary/storage.py | 18 +-- tiramisu/storage/dictionary/value.py | 36 +++--- tiramisu/value.py | 154 +++++++++++++----------- 12 files changed, 297 insertions(+), 242 deletions(-) diff --git a/test/test_cache.py b/test/test_cache.py index 61eb8f4..ec51455 100644 --- a/test/test_cache.py +++ b/test/test_cache.py @@ -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) diff --git a/test/test_config.py b/test/test_config.py index 61ec52b..02e0341 100644 --- a/test/test_config.py +++ b/test/test_config.py @@ -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) diff --git a/test/test_metaconfig.py b/test/test_metaconfig.py index f20f4dd..304d227 100644 --- a/test/test_metaconfig.py +++ b/test/test_metaconfig.py @@ -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' diff --git a/test/test_option_calculation.py b/test/test_option_calculation.py index 4dc37e8..0266855 100644 --- a/test/test_option_calculation.py +++ b/test/test_option_calculation.py @@ -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 diff --git a/test/test_option_setting.py b/test/test_option_setting.py index 979a79e..70332d2 100644 --- a/test/test_option_setting.py +++ b/test/test_option_setting.py @@ -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)') diff --git a/test/test_permissive.py b/test/test_permissive.py index 783afde..cd9b434 100644 --- a/test/test_permissive.py +++ b/test/test_permissive.py @@ -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: diff --git a/tiramisu/config.py b/tiramisu/config.py index abfaa01..269493e 100644 --- a/tiramisu/config.py +++ b/tiramisu/config.py @@ -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): diff --git a/tiramisu/setting.py b/tiramisu/setting.py index f0e4d84..0b87fbe 100644 --- a/tiramisu/setting.py +++ b/tiramisu/setting.py @@ -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): diff --git a/tiramisu/storage/dictionary/setting.py b/tiramisu/storage/dictionary/setting.py index 519c844..68a144f 100644 --- a/tiramisu/storage/dictionary/setting.py +++ b/tiramisu/storage/dictionary/setting.py @@ -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()) diff --git a/tiramisu/storage/dictionary/storage.py b/tiramisu/storage/dictionary/storage.py index 09caf05..a7a135a 100644 --- a/tiramisu/storage/dictionary/storage.py +++ b/tiramisu/storage/dictionary/storage.py @@ -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 diff --git a/tiramisu/storage/dictionary/value.py b/tiramisu/storage/dictionary/value.py index 0f80f73..713473e 100644 --- a/tiramisu/storage/dictionary/value.py +++ b/tiramisu/storage/dictionary/value.py @@ -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] diff --git a/tiramisu/value.py b/tiramisu/value.py index 99d6d7f..f2cbdf3 100644 --- a/tiramisu/value.py +++ b/tiramisu/value.py @@ -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