update sqlite storage
This commit is contained in:
parent
6f030d426b
commit
6bad3c6e64
17 changed files with 365 additions and 134 deletions
|
@ -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
|
||||
|
|
|
@ -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():
|
||||
|
|
|
@ -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'})}
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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'))
|
||||
|
||||
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue