update sqlite storage

This commit is contained in:
Emmanuel Garette 2017-07-04 19:59:42 +02:00
parent 6f030d426b
commit 6bad3c6e64
17 changed files with 365 additions and 134 deletions

View file

@ -2,8 +2,9 @@
from autopath import do_autopath
do_autopath()
from tiramisu import setting
from tiramisu import setting, value
setting.expires_time = 1
value.expires_time = 1
from tiramisu.option import IntOption, StrOption, OptionDescription
from tiramisu.config import Config
from tiramisu.error import ConfigError

View file

@ -644,7 +644,7 @@ def test_consistency_master_and_slaves_master_mandatory_non_transitive():
maconfig = OptionDescription('rootconfig', '', [interface1, interface2])
cfg = Config(maconfig)
cfg.read_write()
assert list(cfg.cfgimpl_get_values().mandatory_warnings()) == ["val1.val1"]
assert list(cfg.cfgimpl_get_values().mandatory_warnings()) == ["val1.val1", "val1.val2"]
def test_callback_master_and_slaves_master_list():

View file

@ -692,3 +692,6 @@ def test_groups_with_master_get_modified_value():
assert cfg.cfgimpl_get_values().get_modified_values() == {'ip_admin_eth0.ip_admin_eth0': ('user', ('192.168.1.1',))}
cfg.ip_admin_eth0.netmask_admin_eth0 = ['255.255.255.255']
assert cfg.cfgimpl_get_values().get_modified_values() == {'ip_admin_eth0.ip_admin_eth0': ('user', ('192.168.1.1',)), 'ip_admin_eth0.netmask_admin_eth0': ({'0': 'user'}, {'0': '255.255.255.255'})}
cfg.ip_admin_eth0.ip_admin_eth0.append('192.168.1.1')
cfg.ip_admin_eth0.netmask_admin_eth0[-1] = '255.255.255.255'
assert cfg.cfgimpl_get_values().get_modified_values() == {'ip_admin_eth0.ip_admin_eth0': ('user', ('192.168.1.1', '192.168.1.1')), 'ip_admin_eth0.netmask_admin_eth0': ({'0': 'user', '1': 'user'}, {'0': '255.255.255.255', '1': '255.255.255.255'})}

View file

@ -6,7 +6,7 @@ do_autopath()
from tiramisu.config import Config
from tiramisu.option import BoolOption, OptionDescription
from tiramisu.setting import owners
from tiramisu.setting import groups, owners
from tiramisu.storage import list_sessions, delete_session
@ -21,6 +21,7 @@ def test_list():
o = OptionDescription('od', '', [b])
c = Config(o, session_id='test_non_persistent')
c.cfgimpl_get_settings().remove('cache')
c.b = True
assert 'test_non_persistent' in list_sessions('config')
del(c)
assert 'test_non_persistent' not in list_sessions('config')
@ -40,7 +41,8 @@ def test_list_sessions_persistent():
b = BoolOption('b', '')
o = OptionDescription('od', '', [b])
try:
Config(o, session_id='test_persistent', persistent=True)
c = Config(o, session_id='test_persistent', persistent=True)
c.b = True
except ValueError:
# storage is not persistent
pass
@ -139,6 +141,46 @@ def test_create_persistent_retrieve_owner():
del(c)
def test_create_persistent_retrieve_owner_masterslaves():
a = BoolOption('a', '', multi=True)
b = BoolOption('b', '', multi=True)
o = OptionDescription('a', '', [a, b])
o.impl_set_group_type(groups.master)
o1 = OptionDescription('a', '', [o])
try:
c = Config(o1, session_id='test_persistent', persistent=True)
except ValueError:
# storage is not persistent
pass
else:
assert c.getowner(a) == owners.default
assert c.getowner(b) == owners.default
c.a.a = [True]
c.a.a.append(False)
c.a.b[1] = True
assert c.getowner(a) == owners.user
assert c.getowner(b, 0) == owners.default
assert c.getowner(b, 1) == owners.user
owners.addowner('persistentowner2')
c.cfgimpl_get_values().setowner(b, owners.persistentowner2, 1)
c.a.b[0] = True
assert c.getowner(b, 0) == owners.user
assert c.getowner(b, 1) == owners.persistentowner2
del(c)
#
c = Config(o1, session_id='test_persistent', persistent=True)
assert c.getowner(b, 0) == owners.user
assert c.getowner(b, 1) == owners.persistentowner2
delete_session('config', c.impl_getsessionid())
del(c)
#
c = Config(o1, session_id='test_persistent', persistent=True)
assert c.a.b == []
assert c.getowner(b) == owners.default
delete_session('config', c.impl_getsessionid())
del(c)
def test_two_persistent_owner():
b = BoolOption('b', '')
o = OptionDescription('od', '', [b])
@ -204,3 +246,28 @@ def test_two_persistent_information():
c2.cfgimpl_get_settings().remove('cache')
assert c2.impl_get_information('info') == 'string'
delete_session('config', 'test_persistent')
def test_two_different_persistents():
b = BoolOption('b', '')
o = OptionDescription('od', '', [b])
try:
c = Config(o, session_id='test_persistent', persistent=True)
c.cfgimpl_get_settings().remove('cache')
d = Config(o, session_id='test_persistent2', persistent=True)
d.cfgimpl_get_settings().remove('cache')
except ValueError:
# storage is not persistent
pass
else:
c.cfgimpl_get_settings()[b].append('test')
assert str(c.cfgimpl_get_settings()[b]) in ["['test']", "[u'test']"]
assert str(d.cfgimpl_get_settings()[b]) == "[]"
assert c.b is None
assert d.b is None
c.b = True
assert c.b == True
assert d.b is None
delete_session('config', 'test_persistent')
delete_session('config', 'test_persistent2')

View file

@ -87,25 +87,6 @@ class SubConfig(object):
return self, None
return self, path[-1]
#def __hash__(self):
#FIXME
# return hash(self.cfgimpl_get_description().impl_getkey(self))
#def __eq__(self, other):
#FIXME
# "Config's comparison"
# if not isinstance(other, Config):
# return False
# return self.cfgimpl_get_description().impl_getkey(self) == \
# other.cfgimpl_get_description().impl_getkey(other)
#def __ne__(self, other):
#FIXME
# "Config's comparison"
# if not isinstance(other, Config):
# return True
# return not self == other
# ______________________________________________________________________
def __iter__(self, force_permissive=False):
"""Pythonesque way of parsing group's ordered options.
@ -287,6 +268,8 @@ class SubConfig(object):
option = self.cfgimpl_get_description().__getattr__(name,
context=context)
subpath = self._get_subpath(name)
if _setting_properties is undefined:
_setting_properties = context.cfgimpl_get_settings()._getproperties(read_write=True)
if isinstance(option, DynSymLinkOption):
cfg = self.cfgimpl_get_values()._get_cached_value(
option, path=subpath,
@ -681,10 +664,10 @@ class _CommonConfig(SubConfig):
session = self.cfgimpl_get_values()._p_.getsession()
config.cfgimpl_get_values()._p_.importation(self.cfgimpl_get_values()._p_.exportation(
session))
config.cfgimpl_get_settings()._p_._properties = self.cfgimpl_get_settings(
)._p_.get_modified_properties()
config.cfgimpl_get_settings()._p_._permissives = self.cfgimpl_get_settings(
)._p_.get_modified_permissives()
config.cfgimpl_get_settings()._p_.set_modified_properties(self.cfgimpl_get_settings(
)._p_.get_modified_properties())
config.cfgimpl_get_settings()._p_.set_modified_permissives(self.cfgimpl_get_settings(
)._p_.get_modified_permissives())
return config

View file

@ -525,7 +525,8 @@ class Option(OnlyOption):
def impl_validate(self, value, context=undefined, validate=True,
force_index=None, force_submulti_index=None,
current_opt=undefined, is_multi=None,
display_error=True, display_warnings=True, multi=None):
display_error=True, display_warnings=True, multi=None,
setting_properties=undefined):
"""
:param value: the option's value
:param context: Config's context
@ -544,8 +545,9 @@ class Option(OnlyOption):
if current_opt is undefined:
current_opt = self
display_warnings = display_warnings and (context is undefined or
'warnings' in context.cfgimpl_get_settings())
if display_warnings and setting_properties is undefined and context is not undefined:
setting_properties = context.cfgimpl_get_settings()._getproperties(read_write=False)
display_warnings = display_warnings and (setting_properties is undefined or 'warnings' in setting_properties)
def _is_not_unique(value):
if display_error and self.impl_is_unique() and len(set(value)) != len(value):
for idx, val in enumerate(value):
@ -1160,7 +1162,8 @@ class DynSymLinkOption(object):
def impl_validate(self, value, context=undefined, validate=True,
force_index=None, force_submulti_index=None, is_multi=None,
display_error=True, display_warnings=True, multi=None):
display_error=True, display_warnings=True, multi=None,
setting_properties=undefined):
return self._impl_getopt().impl_validate(value, context, validate,
force_index,
force_submulti_index,
@ -1168,7 +1171,8 @@ class DynSymLinkOption(object):
is_multi=is_multi,
display_error=display_error,
display_warnings=display_warnings,
multi=multi)
multi=multi,
setting_properties=setting_properties)
def impl_is_dynsymlinkoption(self):
return True

View file

@ -182,7 +182,7 @@ class MasterSlaves(object):
masterp = master.impl_getpath(context)
masterlen = self.get_length(values, opt, session, validate, undefined,
undefined, force_permissive,
master=master)
master=master, setting_properties=setting_properties)
if isinstance(masterlen, Exception):
if isinstance(masterlen, PropertiesOptionError):
masterlen.set_orig_opt(opt)
@ -252,7 +252,7 @@ class MasterSlaves(object):
def get_length(self, values, opt, session, validate=True, slave_path=undefined,
slave_value=undefined, force_permissive=False, master=None,
masterp=None):
masterp=None, setting_properties=undefined):
"""get master len with slave option"""
if master is None:
master = self.getmaster(opt)
@ -262,7 +262,7 @@ class MasterSlaves(object):
slave_path = undefined
value = self.getitem(values, master, masterp, validate,
force_permissive, None, True, session, slave_path=slave_path,
slave_value=slave_value)
slave_value=slave_value, setting_properties=setting_properties)
if isinstance(value, Exception):
return value
return len(value)

View file

@ -1,4 +1,4 @@
# Copyright (C) 2013-2014 Team tiramisu (see AUTHORS for all contributors)
# Copyright (C) 2013-2017 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 Lesser General Public License as published by the
@ -36,12 +36,15 @@ from ..i18n import _
MODULE_PATH = os.path.split(os.path.split(os.path.split(__file__)[0])[0])[1]
DEFAULT_STORAGE = 'dictionary'
class StorageType(object):
"""Object to store storage's type. If a Config is already set,
default storage is store as selected storage. You cannot change it
after.
"""
default_storage = os.environ.get('TIRAMISU_STORAGE', 'dictionary')
default_storage = os.environ.get('TIRAMISU_STORAGE', DEFAULT_STORAGE)
storage_type = None
mod = None
@ -55,6 +58,9 @@ class StorageType(object):
def get(self):
if self.storage_type is None:
self.storage_type = self.default_storage
set_to_default = True
else:
set_to_default = False
if self.mod is None:
modulepath = '{0}.storage.{1}'.format(MODULE_PATH, self.storage_type)
try:
@ -70,8 +76,9 @@ class StorageType(object):
storage_type = StorageType()
storage_option_type = StorageType()
storage_option_type.set(DEFAULT_STORAGE)
storage_validation = StorageType()
storage_validation.set('dictionary')
storage_validation.set(DEFAULT_STORAGE)
def set_storage(type_, name, **kwargs): # pragma: optional cover
@ -126,7 +133,7 @@ def get_storages(context, session_id, persistent):
session_id = gen_id(context)
imp = storage_type.get()
storage = imp.Storage(session_id, persistent)
settings = imp.Settings(session_id, storage)
settings = imp.Settings(storage)
values = imp.Values(storage)
return settings, values
@ -168,8 +175,9 @@ def delete_session(type_, session_id): # pragma: optional cover
session = storage_module.storage.getsession()
storage_module.value.delete_session(session_id, session)
storage_module.storage.delete_session(session_id, session)
if session:
session.commit()
del(session)
__all__ = (set_storage, list_sessions, delete_session)
__all__ = ('set_storage', 'list_sessions', 'delete_session')

View file

@ -22,7 +22,7 @@ from ..util import Cache
class Settings(Cache):
__slots__ = ('_properties', '_permissives')
def __init__(self, session_id, storage):
def __init__(self, storage):
# properties attribute: the name of a property enables this property
# key is None for global properties
self._properties = {}
@ -59,8 +59,14 @@ class Settings(Cache):
"""
return copy(self._properties)
def set_modified_properties(self, properties):
self._properties = properties
def get_modified_permissives(self):
"""return all modified permissives in a dictionary
example: {'path1': set(['perm1', 'perm2'])}
"""
return copy(self._permissives)
def set_modified_permissives(self, permissives):
self._permissives = permissives

View file

@ -33,7 +33,7 @@ def list_sessions(): # pragma: optional cover
return _list_sessions
def delete_session(session_id): # pragma: optional cover
def delete_session(session_id, session): # pragma: optional cover
raise ConfigError(_('dictionary storage cannot delete session'))

View file

@ -182,11 +182,11 @@ class Values(Cache):
indexes = self._values[1][path_idx]
if indexes is None:
if index is not None: # pragma: no cover
raise ValueError('index is forbidden')
raise ValueError('index is forbidden for {}'.format(path))
value = self._values[nb][path_idx]
else:
if index is None: # pragma: no cover
raise ValueError('index is mandatory')
raise ValueError('index is mandatory for {}'.format(path))
if index in indexes:
subidx = indexes.index(index)
value = self._values[nb][path_idx][subidx]

View file

@ -22,6 +22,6 @@ You should not configure differents Configs with same session_id.
"""
from .value import Values
from .setting import Settings
from .storage import setting, Storage, list_sessions, delete_session
from .storage import Storage, list_sessions, delete_session
__all__ = (setting, Values, Settings, Storage, list_sessions, delete_session)
__all__ = ('Values', 'Settings', 'Storage', 'list_sessions', 'delete_session')

View file

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
"default plugin for setting: set it in a simple dictionary"
# Copyright (C) 2013 Team tiramisu (see AUTHORS for all contributors)
# Copyright (C) 2013-2017 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 Lesser General Public License as published by the
@ -22,10 +22,10 @@ class Settings(Sqlite3DB):
__slots__ = tuple()
def __init__(self, storage):
settings_table = 'CREATE TABLE IF NOT EXISTS property(path text '
settings_table += 'primary key, properties text)'
permissives_table = 'CREATE TABLE IF NOT EXISTS permissive(path text '
permissives_table += 'primary key, permissives text)'
settings_table = 'CREATE TABLE IF NOT EXISTS property(path TEXT,'
settings_table += 'properties text, session_id TEXT, PRIMARY KEY(path, session_id))'
permissives_table = 'CREATE TABLE IF NOT EXISTS permissive(path TEXT,'
permissives_table += 'permissives TEXT, session_id TEXT, PRIMARY KEY(path, session_id))'
# should init cache too
super(Settings, self).__init__(storage)
self._storage.execute(settings_table, commit=False)
@ -34,16 +34,23 @@ class Settings(Sqlite3DB):
# properties
def setproperties(self, path, properties):
path = self._sqlite_encode_path(path)
self._storage.execute("DELETE FROM property WHERE path = ?", (path,),
self._storage.execute("DELETE FROM property WHERE path = ? AND session_id = ?",
(path, self._session_id),
False)
self._storage.execute("INSERT INTO property(path, properties) VALUES "
"(?, ?)", (path,
self._sqlite_encode(properties)))
self._storage.execute("INSERT INTO property(path, properties, session_id) VALUES "
"(?, ?, ?)", (path,
self._sqlite_encode(properties),
self._session_id))
def delproperties(self, path):
path = self._sqlite_encode_path(path)
self._storage.execute("DELETE FROM property WHERE path = ? AND session_id = ?",
(path, self._session_id))
def getproperties(self, path, default_properties):
path = self._sqlite_encode_path(path)
value = self._storage.select("SELECT properties FROM property WHERE "
"path = ?", (path,))
"path = ? AND session_id = ?", (path, self._session_id))
if value is None:
return set(default_properties)
else:
@ -52,29 +59,32 @@ class Settings(Sqlite3DB):
def hasproperties(self, path):
path = self._sqlite_encode_path(path)
return self._storage.select("SELECT properties FROM property WHERE "
"path = ?", (path,)) is not None
"path = ? AND session_id = ?", (path, self._session_id)
) is not None
def reset_all_properties(self):
self._storage.execute("DELETE FROM property")
self._storage.execute("DELETE FROM property WHERE session_id = ?", (self._session_id,))
def reset_properties(self, path):
path = self._sqlite_encode_path(path)
self._storage.execute("DELETE FROM property WHERE path = ?", (path,))
self._storage.execute("DELETE FROM property WHERE path = ? AND session_id = ?",
(path, self._session_id))
# permissive
def setpermissive(self, path, permissive):
path = self._sqlite_encode_path(path)
self._storage.execute("DELETE FROM permissive WHERE path = ?", (path,),
self._storage.execute("DELETE FROM permissive WHERE path = ? AND session_id = ?",
(path, self._session_id),
False)
self._storage.execute("INSERT INTO permissive(path, permissives) "
"VALUES (?, ?)", (path,
self._sqlite_encode(permissive)
))
self._storage.execute("INSERT INTO permissive(path, permissives, session_id) "
"VALUES (?, ?, ?)", (path,
self._sqlite_encode(permissive),
self._session_id))
def getpermissive(self, path='_none'):
permissives = self._storage.select("SELECT permissives FROM "
"permissive WHERE path = ?",
(path,))
"permissive WHERE path = ? AND session_id = ?",
(path, self._session_id))
if permissives is None:
return frozenset()
else:
@ -85,19 +95,43 @@ class Settings(Sqlite3DB):
example: {'path1': set(['prop1', 'prop2'])}
"""
ret = {}
for path, properties in self._storage.select("SELECT * FROM property",
for path, properties, _ in self._storage.select("SELECT * FROM property "
"WHERE session_id = ?",
(self._session_id,),
only_one=False):
path = self._sqlite_decode_path(path)
ret[path] = self._sqlite_decode(properties)
return ret
def set_modified_properties(self, properties):
self._storage.execute("DELETE FROM property", commit=False)
for path, property_ in properties.items():
self._storage.execute("INSERT INTO property(path, property, session_id) "
"VALUES (?, ?, ?)", (path,
self._sqlite_encode(property_),
self._session_id,
), False)
self._storage._conn.commit()
def get_modified_permissives(self):
"""return all modified permissives in a dictionary
example: {'path1': set(['perm1', 'perm2'])}
"""
ret = {}
for path, permissives in self._storage.select("SELECT * FROM permissive",
for path, permissives in self._storage.select("SELECT * FROM permissive "
"WHERE session_id = ?",
(self._session_id,),
only_one=False):
path = self._sqlite_decode_path(path)
ret[path] = self._sqlite_decode(permissives)
return ret
def set_modified_permissives(self, permissives):
self._storage.execute("DELETE FROM permissive", commit=False)
for path, permissive in permissives.items():
self._storage.execute("INSERT INTO permissive(path, permissive, session_id) "
"VALUES (?, ?, ?)", (path,
self._sqlite_encode(permissive),
self._session_id,
), False)
self._storage._conn.commit()

View file

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
"sqlite3 cache"
# Copyright (C) 2013 Team tiramisu (see AUTHORS for all contributors)
# Copyright (C) 2013-2017 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 Lesser General Public License as published by the
@ -23,7 +23,11 @@ from ..util import Cache
class Sqlite3DB(Cache):
__slots__ = tuple()
__slots__ = ('_session_id',)
def __init__(self, storage):
self._session_id = storage.session_id
super(Sqlite3DB, self).__init__(storage)
def _sqlite_decode_path(self, path):
if path == '_none':
return None

View file

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
"default plugin for cache: set it in a simple dictionary"
# Copyright (C) 2013 Team tiramisu (see AUTHORS for all contributors)
# Copyright (C) 2013-2017 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 Lesser General Public License as published by the
@ -17,7 +17,7 @@
# ____________________________________________________________
from os import unlink
from os.path import basename, splitext, join
from os.path import basename, splitext, join, isfile
import sqlite3
from glob import glob
from ..util import SerializeObject
@ -29,25 +29,39 @@ class Setting(SerializeObject):
"""
extension = 'db'
dir_database = '/tmp'
name = 'tiramisu'
setting = Setting()
SETTING = Setting()
def _gen_filename(name):
return join(setting.dir_database, '{0}.{1}'.format(name,
setting.extension))
def _gen_filename():
return join(SETTING.dir_database, '{0}.{1}'.format(SETTING.name, SETTING.extension))
def list_sessions():
names = []
for filename in glob(_gen_filename('*')):
names.append(basename(splitext(filename)[0]))
conn = sqlite3.connect(_gen_filename())
conn.text_factory = str
cursor = conn.cursor()
names = [row[0] for row in cursor.execute("SELECT DISTINCT session_id FROM value").fetchall()]
conn.close()
return names
def delete_session(session_id):
unlink(_gen_filename(session_id))
def delete_session(session_id, session):
conn = sqlite3.connect(_gen_filename())
conn.text_factory = str
cursor = conn.cursor()
cursor.execute("DELETE FROM property WHERE session_id = ?",
(session_id,))
cursor.execute("DELETE FROM permissive WHERE session_id = ?",
(session_id,))
cursor.execute("DELETE FROM value WHERE session_id = ?",
(session_id,))
cursor.execute("DELETE FROM information WHERE session_id = ?",
(session_id,))
conn.commit()
conn.close()
class Storage(object):
@ -56,12 +70,9 @@ class Storage(object):
def __init__(self, session_id, persistent, test=False):
self.persistent = persistent
if self.persistent:
self.serializable = True
else:
self.serializable = False
self.serializable = self.persistent
self.session_id = session_id
self._conn = sqlite3.connect(_gen_filename(self.session_id))
self._conn = sqlite3.connect(_gen_filename())
self._conn.text_factory = str
self._cursor = self._conn.cursor()
@ -83,4 +94,10 @@ class Storage(object):
self._cursor.close()
self._conn.close()
if not self.persistent:
delete_session(self.session_id)
session = None
if delete_session is not None:
delete_session(self.session_id, session)
def getsession():
pass

View file

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
"default plugin for value: set it in a simple dictionary"
# Copyright (C) 2013 Team tiramisu (see AUTHORS for all contributors)
# Copyright (C) 2013-2017 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 Lesser General Public License as published by the
@ -17,7 +17,9 @@
# ____________________________________________________________
from .sqlite3db import Sqlite3DB
from tiramisu.setting import owners
from .storage import delete_session
from ...setting import undefined, owners
from ...i18n import _
class Values(Sqlite3DB):
@ -28,87 +30,128 @@ class Values(Sqlite3DB):
"""
# should init cache too
super(Values, self).__init__(storage)
values_table = 'CREATE TABLE IF NOT EXISTS value(path text primary '
values_table += 'key, value text, owner text)'
values_table = 'CREATE TABLE IF NOT EXISTS value(path TEXT, '
values_table += 'value TEXT, owner TEXT, idx INTEGER, session_id TEXT NOT NULL, '\
'PRIMARY KEY (path, idx, session_id))'
self._storage.execute(values_table, commit=False)
informations_table = 'CREATE TABLE IF NOT EXISTS information(key text primary '
informations_table += 'key, value text)'
informations_table = 'CREATE TABLE IF NOT EXISTS information(key TEXT PRIMARY '
informations_table += 'KEY, value TEXT, session_id TEXT NOT NULL)'
self._storage.execute(informations_table)
for owner in self._storage.select("SELECT DISTINCT owner FROM value", tuple(), False):
try:
getattr(owners, owner[0])
except AttributeError:
owners.addowner(owner[0])
def getsession(self):
pass
# sqlite
def _sqlite_select(self, path):
return self._storage.select("SELECT value FROM value WHERE path = ?",
(path,))
def _sqlite_select(self, path, index):
request = "SELECT value FROM value WHERE path = ? AND session_id = ?"
params = (path, self._session_id)
if index is not None:
request += " and idx = ?"
params = (path, self._session_id, index)
return self._storage.select(request, params)
# value
def setvalue(self, path, value, owner):
def setvalue(self, path, value, owner, index, session):
"""set value for an option
a specified value must be associated to an owner
"""
self.resetvalue(path)
path = self._sqlite_encode_path(path)
self._storage.execute("INSERT INTO value(path, value, owner) VALUES "
"(?, ?, ?)", (path, self._sqlite_encode(value),
str(owner)))
if index is not None:
self._storage.execute("DELETE FROM value WHERE path = ? AND idx = ? AND "
"session_id = ?", (path, index, self._session_id),
commit=False)
self._storage.execute("INSERT INTO value(path, value, owner, idx, session_id) VALUES "
"(?, ?, ?, ?, ?)", (path, self._sqlite_encode(value),
self._sqlite_encode(str(owner)),
index,
self._session_id),
commit=True)
else:
self._storage.execute("DELETE FROM value WHERE path = ? AND session_id = ?",
(path, self._session_id),
commit=False)
self._storage.execute("INSERT INTO value(path, value, owner, session_id) VALUES "
"(?, ?, ?, ?)", (path, self._sqlite_encode(value),
self._sqlite_encode(str(owner)),
self._session_id),
commit=True)
def getvalue(self, path):
def getvalue(self, path, session, index=None):
"""get value for an option
return: only value, not the owner
"""
path = self._sqlite_encode_path(path)
return self._sqlite_decode(self._sqlite_select(path)[0])
values = self._sqlite_select(path, index)
if values is None:
return values
return self._sqlite_decode(values[0])
def hasvalue(self, path):
def hasvalue(self, path, index=None):
"""if opt has a value
return: boolean
"""
path = self._sqlite_encode_path(path)
return self._sqlite_select(path) is not None
return self._sqlite_select(path, index) is not None
def resetvalue(self, path):
def resetvalue(self, path, session):
"""remove value means delete value in storage
"""
path = self._sqlite_encode_path(path)
self._storage.execute("DELETE FROM value WHERE path = ?", (path,))
self._storage.execute("DELETE FROM value WHERE path = ? AND session_id = ?", (path, self._session_id))
def get_modified_values(self):
"""return all values in a dictionary
example: {option1: (owner, 'value1'), option2: (owner, 'value2')}
"""
ret = {}
for path, value, owner in self._storage.select("SELECT * FROM value",
for path, value, owner, index, _ in self._storage.select("SELECT * FROM value WHERE "
"session_id = ?",
(self._session_id,),
only_one=False):
path = self._sqlite_decode_path(path)
owner = getattr(owners, owner)
owner = getattr(owners, self._sqlite_decode(owner))
value = self._sqlite_decode(value)
if isinstance(value, list):
value = tuple(value)
if index is None:
ret[path] = (owner, value)
else:
if path in ret:
ret[path][0][str(index)] = owner
ret[path][1][str(index)] = value
else:
ret[path] = ({str(index): owner}, {str(index): value})
return ret
# owner
def setowner(self, path, owner):
def setowner(self, path, owner, session, index=None):
"""change owner for an option
"""
path = self._sqlite_encode_path(path)
self._storage.execute("UPDATE value SET owner = ? WHERE path = ?",
(str(owner), path))
if index is None:
self._storage.execute("UPDATE value SET owner = ? WHERE path = ? AND session_id = ?",
(self._sqlite_encode(str(owner)), path, self._session_id))
else:
self._storage.execute("UPDATE value SET owner = ? WHERE path = ? and idx = ? AND session_id = ?",
(self._sqlite_encode(str(owner)), path, index, self._session_id))
def getowner(self, path, default):
def getowner(self, path, default, session, index=None, only_default=False):
"""get owner for an option
return: owner object
"""
path = self._sqlite_encode_path(path)
owner = self._storage.select("SELECT owner FROM value WHERE path = ?",
(path,))
request = "SELECT owner FROM value WHERE path = ? AND session_id = ?"
if index is not None:
request += " AND idx = ?"
params = (path, self._session_id, index)
else:
params = (path, self._session_id)
owner = self._storage.select(request, params)
if owner is None:
return default
else:
owner = owner[0]
owner = self._sqlite_decode(owner[0])
# autocreate owners
try:
return getattr(owners, owner)
@ -123,19 +166,79 @@ class Values(Sqlite3DB):
: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,),
self._storage.execute("DELETE FROM information WHERE key = ? AND session_id = ?",
(key, self._session_id),
False)
self._storage.execute("INSERT INTO information(key, value) VALUES "
"(?, ?)", (key, self._sqlite_encode(value)))
self._storage.execute("INSERT INTO information(key, value, session_id) VALUES "
"(?, ?, ?)", (key, self._sqlite_encode(value), self._session_id))
def get_information(self, key):
def get_information(self, key, default):
"""retrieves one information's item
:param key: the item string (ex: "help")
"""
value = self._storage.select("SELECT value FROM information WHERE key = ?",
(key,))
value = self._storage.select("SELECT value FROM information WHERE key = ? AND "
"session_id = ?",
(key, self._session_id))
if value is None:
raise ValueError("not found")
if default is undefined:
raise ValueError(_("information's item"
" not found: {0}").format(key))
return default
else:
return self._sqlite_decode(value[0])
def del_information(self, key, raises):
if raises and self._storage.select("SELECT value FROM information WHERE key = ? "
"AND session_id = ?",
(key, self._session_id)) is None:
raise ValueError(_("information's item not found {0}").format(key))
self._storage.execute("DELETE FROM information WHERE key = ? AND session_id = ?",
(key, self._session_id))
def exportation(self, session, fake=False):
rows = self._storage.select("SELECT path, value, owner, idx FROM value WHERE "
"session_id = ?;", (self._session_id,), only_one=False)
ret = [[], [], [], []]
for row in rows:
path = row[0]
value = self._sqlite_decode(row[1])
owner = self._sqlite_decode(row[2])
index = row[3]
if index is None:
ret[0].append(path)
ret[1].append(index)
ret[2].append(value)
ret[3].append(owner)
else:
if path in ret[0]:
path_idx = ret[0].index(path)
ret[1][path_idx].append(index)
ret[2][path_idx].append(value)
else:
ret[0].append(path)
ret[1].append([index])
ret[2].append([value])
ret[3].append(owner)
return ret
def importation(self, export):
self._storage.execute("DELETE FROM value WHERE session_id = ?", (self._session_id,),
commit=False)
for idx, path in enumerate(export[0]):
index = export[1][idx]
value = export[2][idx]
owner = export[3][idx]
self._storage.execute("INSERT INTO value(path, value, owner, idx, session_id) VALUES "
"(?, ?, ?, ?, ?)", (path, self._sqlite_encode(value),
self._sqlite_encode(str(owner)), index,
self._session_id))
self._storage._conn.commit()
def get_max_length(self, path, session):
val_max = self._storage.select("SELECT max(idx) FROM value WHERE path = ? AND session_id = ?",
(path, self._session_id), False)
if val_max[0][0] is None:
return 0
return val_max[0][0] + 1

View file

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
"takes care of the option's values and multi values"
# Copyright (C) 2013-2014 Team tiramisu (see AUTHORS for all contributors)
# Copyright (C) 2013-2017 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 Lesser General Public License as published by the
@ -390,7 +390,8 @@ class Values(object):
force_index=index,
force_submulti_index=force_submulti_index,
display_error=False,
display_warnings=display_warnings)
display_warnings=display_warnings,
setting_properties=setting_properties,)
if config_error is not None:
return config_error
return value