From aeeaf6ec147704a85b0f00dc0227acbbf909093f Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Tue, 3 Sep 2013 10:38:28 +0200 Subject: [PATCH] impl_get_information and impl_set_information are, now, persistent in storage --- test/test_config.py | 1 + test/test_storage.py | 18 ++++++- tiramisu/config.py | 31 ++++++++---- tiramisu/option.py | 72 ++++++++++++---------------- tiramisu/storage/dictionary/value.py | 22 ++++++++- tiramisu/storage/sqlite3/value.py | 29 ++++++++++- tiramisu/value.py | 24 ++++++++++ 7 files changed, 143 insertions(+), 54 deletions(-) diff --git a/test/test_config.py b/test/test_config.py index 4e38f19..17e863a 100644 --- a/test/test_config.py +++ b/test/test_config.py @@ -141,6 +141,7 @@ def test_information_config(): string = 'some informations' config.impl_set_information('info', string) assert config.impl_get_information('info') == string + raises(ValueError, "config.impl_get_information('noinfo')") def test_config_impl_get_path_by_opt(): diff --git a/test/test_storage.py b/test/test_storage.py index 6dbb721..56c44e5 100644 --- a/test/test_storage.py +++ b/test/test_storage.py @@ -18,7 +18,6 @@ def test_list(): b = BoolOption('b', '') o = OptionDescription('od', '', [b]) c = Config(o, session_id='test_non_persistent') - from tiramisu.setting import list_sessions assert 'test_non_persistent' in list_sessions() del(c) assert 'test_non_persistent' not in list_sessions() @@ -43,7 +42,6 @@ def test_list_sessions_persistent(): # storage is not persistent pass else: - from tiramisu.setting import list_sessions assert 'test_persistent' in list_sessions() @@ -124,3 +122,19 @@ def test_two_persistent_owner(): assert c.getowner(b) == owners.persistent assert c2.getowner(b) == owners.persistent delete_session('test_persistent') + + +def test_two_persistent_information(): + b = BoolOption('b', '') + o = OptionDescription('od', '', [b]) + try: + c = Config(o, session_id='test_persistent', persistent=True) + except ValueError: + # storage is not persistent + pass + else: + c.impl_set_information('info', 'string') + assert c.impl_get_information('info') == 'string' + c2 = Config(o, session_id='test_persistent', persistent=True) + assert c2.impl_get_information('info') == 'string' + delete_session('test_persistent') diff --git a/tiramisu/config.py b/tiramisu/config.py index ae68e98..8537c0d 100644 --- a/tiramisu/config.py +++ b/tiramisu/config.py @@ -22,14 +22,13 @@ # ____________________________________________________________ import weakref from tiramisu.error import PropertiesOptionError, ConfigError -from tiramisu.option import OptionDescription, Option, SymLinkOption, \ - BaseInformation +from tiramisu.option import OptionDescription, Option, SymLinkOption from tiramisu.setting import groups, Settings, default_encoding, get_storage from tiramisu.value import Values from tiramisu.i18n import _ -class SubConfig(BaseInformation): +class SubConfig(object): "sub configuration management entry" __slots__ = ('_impl_context', '_impl_descr', '_impl_path') @@ -252,10 +251,10 @@ class SubConfig(BaseInformation): :returns: list of matching Option objects """ return self._cfgimpl_get_context()._find(bytype, byname, byvalue, - first=False, - type_=type_, - _subpath=self.cfgimpl_get_path() - ) + first=False, + type_=type_, + _subpath=self.cfgimpl_get_path() + ) def find_first(self, bytype=None, byname=None, byvalue=None, type_='option', display_error=True): @@ -501,6 +500,22 @@ class CommonConfig(SubConfig): def cfgimpl_get_meta(self): return self._impl_meta + # information + def impl_set_information(self, key, value): + """updates the information's attribute + + :param key: information's key (ex: "help", "doc" + :param value: information's value (ex: "the help string") + """ + self._impl_values.set_information(key, value) + + def impl_get_information(self, key, default=None): + """retrieves one information's item + + :param key: the item string (ex: "help") + """ + return self._impl_values.get_information(key, default) + # ____________________________________________________________ class Config(CommonConfig): @@ -526,7 +541,6 @@ class Config(CommonConfig): super(Config, self).__init__(descr, weakref.ref(self)) self._impl_build_all_paths() self._impl_meta = None - self._impl_informations = {} def cfgimpl_reset_cache(self, only_expired=False, @@ -565,7 +579,6 @@ class Config(CommonConfig): # self._impl_settings = Settings(self, storage) # self._impl_values = Values(self, storage) # self._impl_meta = None -# self._impl_informations = {} # def cfgimpl_get_children(self): # return self._impl_children diff --git a/tiramisu/option.py b/tiramisu/option.py index eca61e2..b8bcc0a 100644 --- a/tiramisu/option.py +++ b/tiramisu/option.py @@ -54,51 +54,15 @@ def valid_name(name): # -class BaseInformation(object): - "interface for an option's information attribute" - __slots__ = ('_impl_informations',) - - def impl_set_information(self, key, value): - """updates the information's attribute - (which is a dictionary) - - :param key: information's key (ex: "help", "doc" - :param value: information's value (ex: "the help string") - """ - try: - self._impl_informations[key] = value - except AttributeError: - raise AttributeError(_('{0} has no attribute ' - 'impl_set_information').format( - self.__class__.__name__)) - - def impl_get_information(self, key, default=None): - """retrieves one information's item - - :param key: the item string (ex: "help") - """ - try: - if key in self._impl_informations: - return self._impl_informations[key] - elif default is not None: - return default - else: - raise ValueError(_("information's item" - " not found: {0}").format(key)) - except AttributeError: - raise AttributeError(_('{0} has no attribute ' - 'impl_get_information').format( - self.__class__.__name__)) - - -class BaseOption(BaseInformation): +class BaseOption(object): """This abstract base class stands for attribute access in options that have to be set only once, it is of course done in the __setattr__ method """ __slots__ = ('_name', '_requires', '_properties', '_readonly', - '_consistencies', '_calc_properties', '_state_consistencies', - '_state_readonly', '_state_requires', '_stated') + '_consistencies', '_calc_properties', '_impl_informations', + '_state_consistencies', '_state_readonly', '_state_requires', + '_stated') def __init__(self, name, doc, requires, properties): if not valid_name(name): @@ -160,6 +124,30 @@ class BaseOption(BaseInformation): name)) object.__setattr__(self, name, value) + # information + def impl_set_information(self, key, value): + """updates the information's attribute + (which is a dictionary) + + :param key: information's key (ex: "help", "doc" + :param value: information's value (ex: "the help string") + """ + self._impl_informations[key] = value + + def impl_get_information(self, key, default=None): + """retrieves one information's item + + :param key: the item string (ex: "help") + """ + if key in self._impl_informations: + return self._impl_informations[key] + elif default is not None: + return default + else: + raise ValueError(_("information's item not found: {0}").format( + key)) + + # serialize/unserialize def _impl_convert_consistencies(self, descr, load=False): if not load and self._consistencies is None: self._state_consistencies = None @@ -215,6 +203,7 @@ class BaseOption(BaseInformation): else: self._state_requires = new_value + # serialize def _impl_getstate(self, descr): self._stated = True self._impl_convert_consistencies(descr) @@ -252,6 +241,7 @@ class BaseOption(BaseInformation): del(states['_stated']) return states + # unserialize def _impl_setstate(self, descr): self._impl_convert_consistencies(descr, load=True) self._impl_convert_requires(descr, load=True) @@ -860,7 +850,7 @@ class OptionDescription(BaseOption): '_state_group_type', '_properties', '_children', '_consistencies', '_calc_properties', '__weakref__', '_readonly', '_impl_informations', '_state_requires', - '_state_consistencies', '_stated') + '_state_consistencies', '_stated', '_state_readonly') _opt_type = 'optiondescription' def __init__(self, name, doc, children, requires=None, properties=None): diff --git a/tiramisu/storage/dictionary/value.py b/tiramisu/storage/dictionary/value.py index 9c3e1f9..c1bf2eb 100644 --- a/tiramisu/storage/dictionary/value.py +++ b/tiramisu/storage/dictionary/value.py @@ -22,12 +22,13 @@ from tiramisu.storage.dictionary.storage import Cache class Values(Cache): - __slots__ = ('_values', '__weakref__') + __slots__ = ('_values', '_informations', '__weakref__') def __init__(self, storage): """init plugin means create values storage """ self._values = {} + self._informations = {} # should init cache too super(Values, self).__init__(storage) @@ -72,3 +73,22 @@ class Values(Cache): return: owner object """ return self._values.get(path, (default, None))[0] + + def set_information(self, key, value): + """updates the information's attribute + (which is a dictionary) + + :param key: information's key (ex: "help", "doc" + :param value: information's value (ex: "the help string") + """ + self._informations[key] = value + + def get_information(self, key): + """retrieves one information's item + + :param key: the item string (ex: "help") + """ + if key in self._informations: + return self._informations[key] + else: + raise ValueError("not found") diff --git a/tiramisu/storage/sqlite3/value.py b/tiramisu/storage/sqlite3/value.py index 4207c43..2b9ddc7 100644 --- a/tiramisu/storage/sqlite3/value.py +++ b/tiramisu/storage/sqlite3/value.py @@ -32,7 +32,10 @@ class Values(Cache): super(Values, self).__init__('value', storage) values_table = 'CREATE TABLE IF NOT EXISTS value(path text primary ' values_table += 'key, value text, owner text)' - self.storage.execute(values_table) + self.storage.execute(values_table, commit=False) + informations_table = 'CREATE TABLE IF NOT EXISTS information(key text primary ' + informations_table += 'key, value text)' + self.storage.execute(informations_table) for owner in self.storage.select("SELECT DISTINCT owner FROM value", tuple(), False): try: getattr(owners, owner[0]) @@ -114,3 +117,27 @@ class Values(Cache): except AttributeError: owners.addowner(owner) return getattr(owners, owner) + + def set_information(self, key, value): + """updates the information's attribute + (which is a dictionary) + + :param key: information's key (ex: "help", "doc" + :param value: information's value (ex: "the help string") + """ + self.storage.execute("DELETE FROM information WHERE key = ?", (key,), + False) + self.storage.execute("INSERT INTO information(key, value) VALUES " + "(?, ?)", (key, self._sqlite_encode(value))) + + def get_information(self, key): + """retrieves one information's item + + :param key: the item string (ex: "help") + """ + value = self.storage.select("SELECT value FROM information WHERE key = ?", + (key,)) + if value is None: + raise ValueError("not found") + else: + return self._sqlite_decode(value[0]) diff --git a/tiramisu/value.py b/tiramisu/value.py index d846bc4..b401634 100644 --- a/tiramisu/value.py +++ b/tiramisu/value.py @@ -315,6 +315,30 @@ class Values(object): """ return self.context().cfgimpl_get_description().impl_get_path_by_opt(opt) + # information + def set_information(self, key, value): + """updates the information's attribute + + :param key: information's key (ex: "help", "doc" + :param value: information's value (ex: "the help string") + """ + self._p_.set_information(key, value) + + def get_information(self, key, default=None): + """retrieves one information's item + + :param key: the item string (ex: "help") + """ + try: + return self._p_.get_information(key) + except ValueError: + if default is not None: + return default + else: + raise ValueError(_("information's item" + " not found: {0}").format(key)) + + # ____________________________________________________________ # multi types