add sqlite plugin
authorEmmanuel Garette <egarette@cadoles.com>
Mon, 19 Aug 2013 09:01:21 +0000 (11:01 +0200)
committerEmmanuel Garette <egarette@cadoles.com>
Mon, 19 Aug 2013 09:01:21 +0000 (11:01 +0200)
13 files changed:
test/test_cache.py
test/test_option_setting.py
tiramisu/config.py
tiramisu/option.py
tiramisu/plugins/dictionary/cache.py
tiramisu/plugins/dictionary/setting.py
tiramisu/plugins/dictionary/value.py
tiramisu/plugins/sqlite3/__init__.py [new file with mode: 0644]
tiramisu/plugins/sqlite3/cache.py [new file with mode: 0644]
tiramisu/plugins/sqlite3/setting.py [new file with mode: 0644]
tiramisu/plugins/sqlite3/value.py [new file with mode: 0644]
tiramisu/setting.py
tiramisu/value.py

index 2bc35fe..c7bf3b4 100644 (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._cache
-    assert od1.u1 in settings._cache
+    assert od1.u1 in values._p_get_cached('value')
+    assert od1.u1 in settings._p_get_cached('property')
     c.u2
-    assert od1.u1 in values._cache
-    assert od1.u1 in settings._cache
-    assert od1.u2 in values._cache
-    assert od1.u2 in settings._cache
+    assert od1.u1 in values._p_get_cached('value')
+    assert od1.u1 in settings._p_get_cached('property')
+    assert od1.u2 in values._p_get_cached('value')
+    assert od1.u2 in settings._p_get_cached('property')
 
 
 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._cache
-    assert od1.u1 in settings._cache
+    assert od1.u1 in values._p_get_cached('value')
+    assert od1.u1 in settings._p_get_cached('property')
     c.u2 = 1
-    assert od1.u1 not in values._cache
-    assert od1.u1 not in settings._cache
+    assert od1.u1 not in values._p_get_cached('value')
+    assert od1.u1 not in settings._p_get_cached('property')
     #when remove a value
     c.u1
-    assert od1.u1 in values._cache
-    assert od1.u1 in settings._cache
+    assert od1.u1 in values._p_get_cached('value')
+    assert od1.u1 in settings._p_get_cached('property')
     del(c.u2)
-    assert od1.u1 not in values._cache
-    assert od1.u1 not in settings._cache
+    assert od1.u1 not in values._p_get_cached('value')
+    assert od1.u1 not in settings._p_get_cached('property')
     #when add/del property
     c.u1
-    assert od1.u1 in values._cache
-    assert od1.u1 in settings._cache
+    assert od1.u1 in values._p_get_cached('value')
+    assert od1.u1 in settings._p_get_cached('property')
     c.cfgimpl_get_settings()[od1.u2].append('test')
-    assert od1.u1 not in values._cache
-    assert od1.u1 not in settings._cache
+    assert od1.u1 not in values._p_get_cached('value')
+    assert od1.u1 not in settings._p_get_cached('property')
     c.u1
-    assert od1.u1 in values._cache
-    assert od1.u1 in settings._cache
+    assert od1.u1 in values._p_get_cached('value')
+    assert od1.u1 in settings._p_get_cached('property')
     c.cfgimpl_get_settings()[od1.u2].remove('test')
-    assert od1.u1 not in values._cache
-    assert od1.u1 not in settings._cache
+    assert od1.u1 not in values._p_get_cached('value')
+    assert od1.u1 not in settings._p_get_cached('property')
     #when enable/disabled property
     c.u1
-    assert od1.u1 in values._cache
-    assert od1.u1 in settings._cache
+    assert od1.u1 in values._p_get_cached('value')
+    assert od1.u1 in settings._p_get_cached('property')
     c.cfgimpl_get_settings().append('test')
-    assert od1.u1 not in values._cache
-    assert od1.u1 not in settings._cache
+    assert od1.u1 not in values._p_get_cached('value')
+    assert od1.u1 not in settings._p_get_cached('property')
     c.u1
-    assert od1.u1 in values._cache
-    assert od1.u1 in settings._cache
+    assert od1.u1 in values._p_get_cached('value')
+    assert od1.u1 in settings._p_get_cached('property')
     c.cfgimpl_get_settings().remove('test')
-    assert od1.u1 not in values._cache
-    assert od1.u1 not in settings._cache
+    assert od1.u1 not in values._p_get_cached('value')
+    assert od1.u1 not in settings._p_get_cached('property')
 
 
 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._cache
-    assert od1.u1 in settings._cache
+    assert od1.u1 in values._p_get_cached('value')
+    assert od1.u1 in settings._p_get_cached('property')
     c.u3 = [1]
-    assert od1.u1 not in values._cache
-    assert od1.u1 not in settings._cache
+    assert od1.u1 not in values._p_get_cached('value')
+    assert od1.u1 not in settings._p_get_cached('property')
     #when append value
     c.u1
-    assert od1.u1 in values._cache
-    assert od1.u1 in settings._cache
+    assert od1.u1 in values._p_get_cached('value')
+    assert od1.u1 in settings._p_get_cached('property')
     c.u3.append(1)
-    assert od1.u1 not in values._cache
-    assert od1.u1 not in settings._cache
+    assert od1.u1 not in values._p_get_cached('value')
+    assert od1.u1 not in settings._p_get_cached('property')
     #when pop value
     c.u1
-    assert od1.u1 in values._cache
-    assert od1.u1 in settings._cache
+    assert od1.u1 in values._p_get_cached('value')
+    assert od1.u1 in settings._p_get_cached('property')
     c.u3.pop(1)
-    assert od1.u1 not in values._cache
-    assert od1.u1 not in settings._cache
+    assert od1.u1 not in values._p_get_cached('value')
+    assert od1.u1 not in settings._p_get_cached('property')
     #when remove a value
     c.u1
-    assert od1.u1 in values._cache
-    assert od1.u1 in settings._cache
+    assert od1.u1 in values._p_get_cached('value')
+    assert od1.u1 in settings._p_get_cached('property')
     del(c.u3)
-    assert od1.u1 not in values._cache
-    assert od1.u1 not in settings._cache
+    assert od1.u1 not in values._p_get_cached('value')
+    assert od1.u1 not in settings._p_get_cached('property')
 
 
 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._cache
-    assert od1.u1 in settings._cache
+    assert od1.u1 in values._p_get_cached('value')
+    assert od1.u1 in settings._p_get_cached('property')
     c.cfgimpl_reset_cache()
-    assert od1.u1 not in values._cache
-    assert od1.u1 not in settings._cache
+    assert od1.u1 not in values._p_get_cached('value')
+    assert od1.u1 not in settings._p_get_cached('property')
     c.u1
     sleep(1)
     c.u2
-    assert od1.u1 in values._cache
-    assert od1.u1 in settings._cache
-    assert od1.u2 in values._cache
-    assert od1.u2 in settings._cache
+    assert od1.u1 in values._p_get_cached('value')
+    assert od1.u1 in settings._p_get_cached('property')
+    assert od1.u2 in values._p_get_cached('value')
+    assert od1.u2 in settings._p_get_cached('property')
     c.cfgimpl_reset_cache()
-    assert od1.u1 not in values._cache
-    assert od1.u1 not in settings._cache
-    assert od1.u2 not in values._cache
-    assert od1.u2 not in settings._cache
+    assert od1.u1 not in values._p_get_cached('value')
+    assert od1.u1 not in settings._p_get_cached('property')
+    assert od1.u2 not in values._p_get_cached('value')
+    assert od1.u2 not in settings._p_get_cached('property')
 
 
 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._cache
-    assert od1.u1 in settings._cache
+    assert od1.u1 in values._p_get_cached('value')
+    assert od1.u1 in settings._p_get_cached('property')
     c.cfgimpl_reset_cache(True)
-    assert od1.u1 in values._cache
-    assert od1.u1 in settings._cache
+    assert od1.u1 in values._p_get_cached('value')
+    assert od1.u1 in settings._p_get_cached('property')
     sleep(1)
     c.u2
-    assert od1.u1 in values._cache
-    assert od1.u1 in settings._cache
-    assert od1.u2 in values._cache
-    assert od1.u2 in settings._cache
+    assert od1.u1 in values._p_get_cached('value')
+    assert od1.u1 in settings._p_get_cached('property')
+    assert od1.u2 in values._p_get_cached('value')
+    assert od1.u2 in settings._p_get_cached('property')
     c.cfgimpl_reset_cache(True)
-    assert od1.u1 not in values._cache
-    assert od1.u1 not in settings._cache
-    assert od1.u2 in values._cache
-    assert od1.u2 in settings._cache
+    assert od1.u1 not in values._p_get_cached('value')
+    assert od1.u1 not in settings._p_get_cached('property')
+    assert od1.u2 in values._p_get_cached('value')
+    assert od1.u2 in settings._p_get_cached('property')
 
 
 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._cache
-    assert od1.u1 in settings._cache
+    assert od1.u1 in values._p_get_cached('value')
+    assert od1.u1 in settings._p_get_cached('property')
     c.cfgimpl_reset_cache(only=('values',))
-    assert od1.u1 not in values._cache
-    assert od1.u1 in settings._cache
+    assert od1.u1 not in values._p_get_cached('value')
+    assert od1.u1 in settings._p_get_cached('property')
     c.u1
-    assert od1.u1 in values._cache
-    assert od1.u1 in settings._cache
+    assert od1.u1 in values._p_get_cached('value')
+    assert od1.u1 in settings._p_get_cached('property')
     c.cfgimpl_reset_cache(only=('settings',))
-    assert od1.u1 in values._cache
-    assert od1.u1 not in settings._cache
+    assert od1.u1 in values._p_get_cached('value')
+    assert od1.u1 not in settings._p_get_cached('property')
index 74993c2..66121ec 100644 (file)
@@ -327,23 +327,23 @@ def test_reset_properties():
     cfg = Config(descr)
     setting = cfg.cfgimpl_get_settings()
     option = cfg.cfgimpl_get_description().gc.dummy
-    assert setting._properties == {}
+    assert setting._p_get_properties() == {}
     setting.append('frozen')
-    assert setting._properties == {None: set(('frozen', 'expire', 'validator'))}
+    assert setting._p_get_properties() == {None: set(('frozen', 'expire', 'validator'))}
     setting.reset()
-    assert setting._properties == {}
+    assert setting._p_get_properties() == {}
     setting[option].append('test')
-    assert setting._properties == {option: set(('test',))}
+    assert setting._p_get_properties() == {option: set(('test',))}
     setting.reset()
-    assert setting._properties == {option: set(('test',))}
+    assert setting._p_get_properties() == {option: set(('test',))}
     setting.append('frozen')
-    assert setting._properties == {None: set(('frozen', 'expire', 'validator')), option: set(('test',))}
+    assert setting._p_get_properties() == {None: set(('frozen', 'expire', 'validator')), option: set(('test',))}
     setting.reset(option)
-    assert setting._properties == {None: set(('frozen', 'expire', 'validator'))}
+    assert setting._p_get_properties() == {None: set(('frozen', 'expire', 'validator'))}
     setting[option].append('test')
-    assert setting._properties == {None: set(('frozen', 'expire', 'validator')), option: set(('test',))}
+    assert setting._p_get_properties() == {None: set(('frozen', 'expire', 'validator')), option: set(('test',))}
     setting.reset(all_properties=True)
-    assert setting._properties == {}
+    assert setting._p_get_properties() == {}
     raises(ValueError, 'setting.reset(all_properties=True, opt=option)')
 
 
index bd71d9b..3703937 100644 (file)
@@ -505,8 +505,9 @@ class Config(CommonConfig):
         :param context: the current root config
         :type context: `Config`
         """
-        self._impl_settings = Settings(self)
-        self._impl_values = Values(self)
+        config_id = str(id(self))
+        self._impl_settings = Settings(self, config_id)
+        self._impl_values = Values(self, config_id)
         super(Config, self).__init__(descr, self)
         self._impl_build_all_paths()
         self._impl_meta = None
@@ -540,9 +541,10 @@ class MetaConfig(CommonConfig):
                     raise ValueError(_("child has already a metaconfig's"))
                 child._impl_meta = self
 
+        config_id = str(id(self))
         self._impl_children = children
-        self._impl_settings = Settings(self)
-        self._impl_values = Values(self)
+        self._impl_settings = Settings(self, config_id)
+        self._impl_values = Values(self, config_id)
         self._impl_meta = None
         self._impl_informations = {}
 
index 23cbd27..3175995 100644 (file)
@@ -438,7 +438,8 @@ class StrOption(Option):
 
     def _validate(self, value):
         if not isinstance(value, str):
-            raise ValueError(_('value must be a string'))
+            raise ValueError(_('value must be a string, not '
+                               '{0}').format(type(value)))
 
 
 class UnicodeOption(Option):
index fd67847..2f189e6 100644 (file)
@@ -46,3 +46,9 @@ class PluginCache(object):
 
     def _p_reset_all_cache(self, cache_type):
         self._cache.clear()
+
+    def _p_get_cached(self, cache_type):
+        """return all values in a dictionary
+        example: {option1: ('value1', 'time1'), option2: ('value2', 'time2')}
+        """
+        return self._cache
index 3ccbeb1..24ff86c 100644 (file)
@@ -23,7 +23,7 @@ from tiramisu.plugins.dictionary.cache import PluginCache
 class PluginSettings(PluginCache):
     __slots__ = ('_properties', '_permissives')
 
-    def __init__(self):
+    def __init__(self, config_id):
         # properties attribute: the name of a property enables this property
         # key is None for global properties
         self._properties = {}
@@ -42,7 +42,7 @@ class PluginSettings(PluginCache):
         return opt in self._properties
 
     def _p_reset_all_propertives(self):
-        self._properties = {}
+        self._properties.clear()
 
     def _p_reset_properties(self, opt):
         try:
@@ -50,6 +50,9 @@ class PluginSettings(PluginCache):
         except KeyError:
             pass
 
+    def _p_get_properties(self, cache_type):
+        return self._properties
+
     # permissive
     def _p_setpermissive(self, opt, permissive):
         self._permissives[opt] = frozenset(permissive)
index 84f60c2..0095f28 100644 (file)
@@ -25,7 +25,7 @@ from tiramisu.plugins.dictionary.cache import PluginCache
 class PluginValues(PluginCache):
     __slots__ = ('_values',)
 
-    def __init__(self):
+    def __init__(self, config_id):
         """init plugin means create values storage
         """
         self._values = {}
diff --git a/tiramisu/plugins/sqlite3/__init__.py b/tiramisu/plugins/sqlite3/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tiramisu/plugins/sqlite3/cache.py b/tiramisu/plugins/sqlite3/cache.py
new file mode 100644 (file)
index 0000000..8bd8ce6
--- /dev/null
@@ -0,0 +1,85 @@
+# -*- coding: utf-8 -*-
+"default plugin for cache: set it in a simple dictionary"
+# Copyright (C) 2013 Team tiramisu (see AUTHORS for all contributors)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+# ____________________________________________________________
+
+from pickle import dumps, loads
+from os import unlink
+import sqlite3
+
+
+class PluginCache(object):
+    __slots__ = ('_conn', '_cursor')
+
+    def __init__(self, config_id, cache_type):
+        cache_table = 'CREATE TABLE IF NOT EXISTS cache_{0}(path text primary key, value text, time real)'.format(cache_type)
+        self._conn = sqlite3.connect(config_id + '.db')
+        self._conn.text_factory = str
+        self._cursor = self._conn.cursor()
+        self._cursor.execute(cache_table)
+
+    # value
+    def _p_sqlite_decode(self, value):
+        return loads(value)
+
+    def _p_sqlite_encode(self, value):
+        if isinstance(value, list):
+            value = list(value)
+        return dumps(value)
+
+    def _p_setcache(self, cache_type, opt, val, time):
+        path = self._get_opt_path(opt)
+        convert_value = self._p_sqlite_encode(val)
+        self._cursor.execute("DELETE FROM cache_{0} WHERE path = ?".format(cache_type), (path,))
+        self._cursor.execute("INSERT INTO cache_{0}(path, value, time) VALUES (?, ?, ?)".format(cache_type),
+                             (path, convert_value, time))
+        self._conn.commit()
+
+    def _p_getcache(self, cache_type, opt, exp):
+        path = self._get_opt_path(opt)
+        self._cursor.execute("SELECT value FROM cache_{0} WHERE path = ? AND time >= ?".format(cache_type), (path, exp))
+        cached = self._cursor.fetchone()
+        if cached is None:
+            return False, None
+        else:
+            return True, self._p_sqlite_decode(cached[0])
+
+    def _p_hascache(self, cache_type, opt):
+        path = self._get_opt_path(opt)
+        self._cursor.execute("SELECT value FROM cache_{0} WHERE path = ?".format(cache_type), (path,))
+        return self._cursor.fetchone() is not None
+
+    def _p_reset_expired_cache(self, cache_type, exp):
+        self._cursor.execute("DELETE FROM cache_{0} WHERE time < ?".format(cache_type), (exp,))
+        self._conn.commit()
+
+    def _p_reset_all_cache(self, cache_type):
+        self._cursor.execute("DELETE FROM cache_{0}".format(cache_type))
+        self._conn.commit()
+
+    def _p_get_cached(self, cache_type):
+        """return all values in a dictionary
+        example: {option1: ('value1', 'time1'), option2: ('value2', 'time2')}
+        """
+        self._cursor.execute("SELECT * FROM cache_{0}".format(cache_type))
+        ret = {}
+        for path, value, time in self._cursor.fetchall():
+            opt = self.context.cfgimpl_get_description().impl_get_opt_by_path(path)
+            value = self._p_sqlite_decode(value)
+            ret[opt] = (value, time)
+        return ret
diff --git a/tiramisu/plugins/sqlite3/setting.py b/tiramisu/plugins/sqlite3/setting.py
new file mode 100644 (file)
index 0000000..816c510
--- /dev/null
@@ -0,0 +1,101 @@
+# -*- coding: utf-8 -*-
+"default plugin for setting: set it in a simple dictionary"
+# Copyright (C) 2013 Team tiramisu (see AUTHORS for all contributors)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+# ____________________________________________________________
+from tiramisu.plugins.sqlite3.cache import PluginCache
+
+
+class PluginSettings(PluginCache):
+    __slots__ = tuple()
+
+    def __init__(self, config_id):
+        settings_table = 'CREATE TABLE IF NOT EXISTS property(path text primary key, properties text)'
+        permissives_table = 'CREATE TABLE IF NOT EXISTS permissive(path text primary key, permissives text)'
+        # should init cache too
+        super(PluginSettings, self).__init__(config_id, 'property')
+        self._cursor.execute(settings_table)
+        self._cursor.execute(permissives_table)
+        self._conn.commit()
+    # sqlite
+
+    def _p_sqlite_getpath(self, opt):
+        if opt is None:
+            return '_none'
+        else:
+            return self._get_opt_path(opt)
+
+    # propertives
+    def _p_setproperties(self, opt, properties):
+        path = self._p_sqlite_getpath(opt)
+        self._cursor.execute("DELETE FROM property WHERE path = ?", (path,))
+        self._cursor.execute("INSERT INTO property(path, properties) VALUES (?, ?)",
+                             (path, self._p_sqlite_encode(properties)))
+        self._conn.commit()
+
+    def _p_getproperties(self, opt, default_properties):
+        path = self._p_sqlite_getpath(opt)
+        self._cursor.execute("SELECT properties FROM property WHERE path = ?", (path,))
+        value = self._cursor.fetchone()
+        if value is None:
+            return set(default_properties)
+        else:
+            return set(self._p_sqlite_decode(value[0]))
+
+    def _p_hasproperties(self, opt):
+        path = self._p_sqlite_getpath(opt)
+        return self._cursor.execute("SELECT properties FROM property WHERE path = ?", (path,)) is not None
+
+    def _p_reset_all_propertives(self):
+        self._cursor.execute("DELETE FROM property")
+        self._conn.commit()
+
+    def _p_reset_properties(self, opt):
+        path = self._p_sqlite_getpath(opt)
+        self._cursor.execute("DELETE FROM property WHERE path = ?", (path,))
+        self._conn.commit()
+
+    def _p_get_properties(self):
+        """return all properties in a dictionary
+        """
+        self._cursor.execute("SELECT * FROM property")
+        ret = {}
+        for path, properties in self._cursor.fetchall():
+            if path == '_none':
+                opt = None
+            else:
+                opt = self.context.cfgimpl_get_description().impl_get_opt_by_path(path)
+            properties = self._p_sqlite_decode(properties)
+            ret[opt] = properties
+        return ret
+
+    # permissive
+    def _p_setpermissive(self, opt, permissive):
+        path = self._p_sqlite_getpath(opt)
+        self._cursor.execute("DELETE FROM permissive WHERE path = ?", (path,))
+        self._cursor.execute("INSERT INTO permissive(path, permissives) VALUES (?, ?)",
+                             (path, self._p_sqlite_encode(permissive)))
+        self._conn.commit()
+
+    def _p_getpermissive(self, opt=None):
+        path = self._p_sqlite_getpath(opt)
+        self._cursor.execute("SELECT permissives FROM permissive WHERE path = ?", (path,))
+        permissives = self._cursor.fetchone()
+        if permissives is None:
+            return frozenset()
+        else:
+            return frozenset(self._p_sqlite_decode(permissives[0]))
diff --git a/tiramisu/plugins/sqlite3/value.py b/tiramisu/plugins/sqlite3/value.py
new file mode 100644 (file)
index 0000000..b499f8b
--- /dev/null
@@ -0,0 +1,109 @@
+# -*- coding: utf-8 -*-
+"default plugin for value: set it in a simple dictionary"
+# Copyright (C) 2013 Team tiramisu (see AUTHORS for all contributors)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+# ____________________________________________________________
+
+from tiramisu.plugins.sqlite3.cache import PluginCache
+
+
+class PluginValues(PluginCache):
+    __slots__ = tuple()
+
+    def __init__(self, config_id):
+        """init plugin means create values storage
+        """
+        values_table = 'CREATE TABLE IF NOT EXISTS value(path text primary key, value text, owner text)'
+        # should init cache too
+        super(PluginValues, self).__init__(config_id, 'value')
+        self._cursor.execute(values_table)
+        self._conn.commit()
+
+    # sqlite
+    def _p_sqlite_select(self, opt):
+        path = self._get_opt_path(opt)
+        self._cursor.execute("SELECT value FROM value WHERE path = ?", (path,))
+        return self._cursor.fetchone()
+
+    # value
+    def _p_setvalue(self, opt, value):
+        """set value for an option
+        a specified value must be associated to an owner
+        """
+        path = self._get_opt_path(opt)
+        owner = self.context.cfgimpl_get_settings().getowner()
+        self._p_resetvalue(opt, path)
+        self._cursor.execute("INSERT INTO value(path, value, owner) VALUES (?, ?, ?)",
+                             (path, self._p_sqlite_encode(value), str(owner)))
+        self._conn.commit()
+
+    def _p_getvalue(self, opt):
+        """get value for an option
+        return: only value, not the owner
+        """
+        return self._p_sqlite_decode(self._p_sqlite_select(opt)[0])
+
+    def _p_hasvalue(self, opt):
+        """if opt has a value
+        return: boolean
+        """
+        return self._p_sqlite_select(opt) is not None
+
+    def _p_resetvalue(self, opt, path=None):
+        """remove value means delete value in storage
+        """
+        if not path:
+            path = self._get_opt_path(opt)
+        self._cursor.execute("DELETE FROM value WHERE path = ?", (path,))
+        self._conn.commit()
+
+    def _p_get_modified_values(self):
+        """return all values in a dictionary
+        example: {option1: (owner, 'value1'), option2: (owner, 'value2')}
+        """
+        self._cursor.execute("SELECT value")
+        ret = {}
+        for path, value, owner in self._cursor.fetchall():
+            opt = self.context.cfgimpl_get_description().impl_get_opt_by_path(path)
+            owner = self._get_owner_from_str(owner)
+            value = self._p_sqlite_decode(value)
+            ret[opt] = (owner, value)
+        return ret
+
+    # owner
+    def _p_setowner(self, opt, owner):
+        """change owner for an option
+        """
+        path = self._get_opt_path(opt)
+        self._cursor.execute("UPDATE value SET owner = ? WHERE path = ?", (str(owner), path))
+        self._conn.commit()
+
+    def _p_getowner(self, opt, default):
+        """get owner for an option
+        return: owner object
+        """
+        path = self._get_opt_path(opt)
+        self._cursor.execute("SELECT owner FROM value WHERE path = ?", (path,))
+        owner = self._cursor.fetchone()
+        if owner is None:
+            return default
+        else:
+            return self._get_owner_from_str(owner[0])
+
+    def __del__(self):
+        self._cursor.close()
+        self._conn.close()
index 43e2d70..508b40f 100644 (file)
@@ -24,7 +24,8 @@ from time import time
 from copy import copy
 from tiramisu.error import RequirementError, PropertiesOptionError
 from tiramisu.i18n import _
-from tiramisu.plugins.dictionary.setting import PluginSettings
+#from tiramisu.plugins.dictionary.setting import PluginSettings
+from tiramisu.plugins.sqlite3.setting import PluginSettings
 
 
 default_encoding = 'utf-8'
@@ -182,11 +183,11 @@ class Settings(PluginSettings):
     "``Config()``'s configuration options"
     __slots__ = ('context', '_owner')
 
-    def __init__(self, context):
+    def __init__(self, context, config_id):
         # generic owner
         self._owner = owners.user
         self.context = context
-        super(Settings, self).__init__()
+        super(Settings, self).__init__(config_id)
 
     #____________________________________________________________
     # properties methods
@@ -217,9 +218,9 @@ class Settings(PluginSettings):
             props = self._p_getproperties(opt, default_properties)
         else:
             ntime = None
-            if self._p_hascache('properties', opt):
+            if self._p_hascache('property', opt):
                 ntime = time()
-                is_cached, props = self._p_getcache('properties', opt, ntime)
+                is_cached, props = self._p_getcache('property', opt, ntime)
                 if is_cached:
                     return props
             if is_apply_req:
@@ -228,7 +229,7 @@ class Settings(PluginSettings):
             if 'expire' in self:
                 if ntime is None:
                     ntime = time()
-                self._p_setcache('properties', opt, props, ntime + expires_time)
+                self._p_setcache('property', opt, props, ntime + expires_time)
         return props
 
     def append(self, propname):
@@ -328,9 +329,9 @@ class Settings(PluginSettings):
 
     def reset_cache(self, only_expired):
         if only_expired:
-            self._p_reset_expired_cache('properties', time())
+            self._p_reset_expired_cache('property', time())
         else:
-            self._p_reset_all_cache('properties')
+            self._p_reset_all_cache('property')
 
     def apply_requires(self, opt):
         "carries out the jit (just in time requirements between options"
@@ -373,3 +374,6 @@ class Settings(PluginSettings):
             # no requirement has been triggered, then just reverse the action
             if not matches:
                 setting.remove(action)
+
+    def _get_opt_path(self, opt):
+        return self.context.cfgimpl_get_description().impl_get_path_by_opt(opt)
index d22bec3..4348ff7 100644 (file)
@@ -26,7 +26,8 @@ from tiramisu.i18n import _
 from tiramisu.option import SymLinkOption
 
 #FIXME
-from tiramisu.plugins.dictionary.value import PluginValues
+#from tiramisu.plugins.dictionary.value import PluginValues
+from tiramisu.plugins.sqlite3.value import PluginValues
 
 
 class Values(PluginValues):
@@ -36,7 +37,7 @@ class Values(PluginValues):
     """
     __slots__ = ('context',)
 
-    def __init__(self, context):
+    def __init__(self, context, config_id):
         """
         Initializes the values's dict.
 
@@ -45,7 +46,7 @@ class Values(PluginValues):
         """
 
         self.context = context
-        super(Values, self).__init__()
+        super(Values, self).__init__(config_id)
 
     def _getdefault(self, opt):
         meta = self.context.cfgimpl_get_meta()
@@ -77,7 +78,7 @@ class Values(PluginValues):
         return self._p_get_modified_values()
 
     def __contains__(self, opt):
-        return self._p_hascache('value', opt)
+        return self._p_hasvalue('value', opt)
 
     def __delitem__(self, opt):
         self.reset(opt)
@@ -121,6 +122,9 @@ class Values(PluginValues):
             ntime = time()
             is_cached, value = self._p_getcache('value', opt, 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)
                 return value
         val = self._getitem(opt, validate, force_permissive, force_properties,
                             validate_properties)
@@ -321,6 +325,7 @@ 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)
         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):
@@ -329,10 +334,12 @@ class Multi(list):
                         dvalue = values._getcallback_value(slave, index=index)
                     else:
                         dvalue = slave.impl_getdefault_multi()
-                    #get multi without valid properties
-                    values.getitem(slave, validate_properties=False).append(
-                        dvalue, force=True)
-        self.context.cfgimpl_get_values()._setvalue(self.opt, self, validate_properties=not force)
+                    old_value = values.getitem(slave, validate_properties=False)
+                    if len(old_value) < self.__len__():
+                        values.getitem(slave, validate_properties=False).append(
+                            dvalue, force=True)
+                    else:
+                        values.getitem(slave, validate_properties=False)[index] = dvalue
 
     def sort(self, cmp=None, key=None, reverse=False):
         if self.opt.impl_get_multitype() in [multitypes.slave,