diff --git a/tiramisu/api.py b/tiramisu/api.py
index 0c56245..943ab49 100644
--- a/tiramisu/api.py
+++ b/tiramisu/api.py
@@ -17,6 +17,7 @@
from inspect import ismethod, getdoc, signature
from time import time
from typing import List, Set, Any, Optional, Callable, Union, Dict
+from warnings import catch_warnings, simplefilter
from .error import APIError, ConfigError, LeadershipError, PropertiesOptionError, ValueErrorWarning
@@ -134,7 +135,7 @@ class CommonTiramisuOption(CommonTiramisu):
if not option.impl_is_optiondescription() and \
self._option_bag.index is None and \
option.impl_is_follower():
- raise APIError(_('index must be set with the follower option "{}"').format(self._option_bag.path))
+ raise APIError(_('index must be set with the follower option "{}"').format(self._option_bag.option.impl_get_display_name()))
def __getattr__(self, name):
raise APIError(_('unknown method {} in {}').format(name, self.__class__.__name__))
@@ -389,6 +390,7 @@ class TiramisuOptionProperty(CommonTiramisuOption):
raise ConfigError(_('cannot add this property: "{0}"').format(
' '.join(prop)))
props = self._settings._p_.getproperties(self._option_bag.path,
+ self._option_bag.index,
option.impl_getproperties())
self._settings.setproperties(self._option_bag.path,
props | {prop},
@@ -399,6 +401,7 @@ class TiramisuOptionProperty(CommonTiramisuOption):
"""Remove new property for an option"""
option = self._option_bag.option
props = self._settings._p_.getproperties(self._option_bag.path,
+ self._option_bag.index,
option.impl_getproperties())
self._settings.setproperties(self._option_bag.path,
props - {prop},
@@ -430,8 +433,7 @@ class TiramisuOptionPermissive(CommonTiramisuOption):
def get(self):
"""Get permissives value"""
- return self._settings.getpermissives(self._option_bag.option,
- self._option_bag.path)
+ return self._settings.getpermissives(self._option_bag)
def set(self, permissives):
"""Set permissives value"""
@@ -528,7 +530,8 @@ class _TiramisuOptionValueOption:
def valid(self):
try:
- with warnings.catch_warnings(record=True) as warns:
+ with catch_warnings(record=True) as warns:
+ simplefilter("always", ValueErrorWarning)
self.get()
for warn in warns:
if isinstance(warns.message, ValueErrorWarning):
@@ -538,6 +541,13 @@ class _TiramisuOptionValueOption:
return True
+class _TiramisuOptionValueChoiceOption:
+ def list(self):
+ """All values available for a ChoiceOption"""
+ option = self._option_bag.option
+ return option.impl_get_values(self._option_bag)
+
+
class _TiramisuOptionValueLeader:
def pop(self, index):
"""Pop a value"""
@@ -556,12 +566,6 @@ class _TiramisuOptionValueLeader:
return self._length
-class _TiramisuOptionValueGroup:
- def reset(self):
- """Reset value"""
- self._option_bag.config_bag.context.reset(self._option_bag.path)
-
-
class _TiramisuOptionValueFollower:
def len(self):
"""Length of follower option"""
@@ -572,16 +576,10 @@ class _TiramisuOptionValueFollower:
return self._length
-class _TiramisuOptionValueChoiceOption:
- def list(self):
- """All values available for a ChoiceOption"""
- option = self._option_bag.option
- return option.impl_get_values(self._option_bag)
-
- def callbacks(self):
- """Get callbacks for a values"""
- option = self._option_bag.option
- return option.get_callback()
+class _TiramisuOptionValueGroup:
+ def reset(self):
+ """Reset value"""
+ self._option_bag.config_bag.context.reset(self._option_bag.path)
class _TiramisuOptionValueOptionDescription:
@@ -901,6 +899,7 @@ class TiramisuContextValue(TiramisuConfig):
"""Return path of options with mandatory property without any value"""
return self._config_bag.context.cfgimpl_get_values().mandatory_warnings(self._config_bag)
+ # FIXME should be only for group/meta
def set(self,
path: str,
value,
@@ -925,6 +924,7 @@ class TiramisuContextValue(TiramisuConfig):
self._config_bag,
**kwargs)
+ # FIXME should be only for group/meta
def reset(self,
path: str,
only_children: bool=False):
@@ -1026,20 +1026,20 @@ class TiramisuContextProperty(TiramisuConfig):
"""Add a config property"""
props = set(self.get())
props.add(prop)
- self.set(frozenset(props))
+ self._set(frozenset(props))
def pop(self, prop):
"""Remove a config property"""
props = set(self.get())
if prop in props:
props.remove(prop)
- self.set(frozenset(props))
+ self._set(frozenset(props))
def get(self):
"""Get all config properties"""
return self._config_bag.properties
- def set(self, props):
+ def _set(self, props):
"""Personalise config properties"""
if 'force_store_value' in props:
force_store_value = 'force_store_value' not in self._config_bag.properties
@@ -1065,7 +1065,7 @@ class TiramisuContextProperty(TiramisuConfig):
def importation(self, properties):
"""Import config properties"""
- if 'force_store_value' in properties.get(None, []):
+ if 'force_store_value' in properties.get(None, {}).get(None, []):
force_store_value = 'force_store_value' not in self._config_bag.properties
else:
force_store_value = False
@@ -1134,7 +1134,7 @@ class TiramisuContextPermissive(TiramisuConfig):
"""Get config permissives"""
return self._config_bag.context.cfgimpl_get_settings().get_context_permissives()
- def set(self, permissives):
+ def _set(self, permissives):
"""Set config permissives"""
self._config_bag.context.cfgimpl_get_settings().set_context_permissives(permissives)
del self._config_bag.permissives
@@ -1161,14 +1161,14 @@ class TiramisuContextPermissive(TiramisuConfig):
"""Add a config permissive"""
props = set(self.get())
props.add(prop)
- self.set(frozenset(props))
+ self._set(frozenset(props))
def pop(self, prop):
"""Remove a config permissive"""
props = set(self.get())
if prop in props:
props.remove(prop)
- self.set(frozenset(props))
+ self._set(frozenset(props))
class TiramisuContextOption(TiramisuConfig):
diff --git a/tiramisu/setting.py b/tiramisu/setting.py
index 252455a..4cf5161 100644
--- a/tiramisu/setting.py
+++ b/tiramisu/setting.py
@@ -15,6 +15,7 @@
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see .
# ____________________________________________________________
+from itertools import chain
from .error import PropertiesOptionError, ConstError, ConfigError, LeadershipError, display_list
from .i18n import _
@@ -42,11 +43,6 @@ frozen
cannot set value for option with this properties if 'frozen' is set in
config
-mandatory
- should set value for option with this properties if 'mandatory' is set in
- config
-
-
* Special property:
permissive
@@ -55,6 +51,16 @@ permissive
config with 'permissive', whole option in this config cannot raise
PropertiesOptionError for properties set in permissive
+mandatory
+ should set value for option with this properties if 'mandatory' is set in
+ config
+
+empty
+ raise mandatory PropertiesOptionError if multi or leader have empty value
+
+unique
+ raise ValueError if a value is set twice or more in a multi Option
+
* Special Config properties:
cache
@@ -67,9 +73,6 @@ everything_frozen
whole option in config are frozen (even if option have not frozen
property)
-empty
- raise mandatory PropertiesOptionError if multi or leader have empty value
-
validator
launch validator set by user in option (this property has no effect
for internal validator)
@@ -109,11 +112,12 @@ FORBIDDEN_SET_PERMISSIVES = frozenset(['force_default_on_freeze',
'force_metaconfig_on_freeze',
'force_store_value'])
ALLOWED_LEADER_PROPERTIES = frozenset(['empty',
- 'force_store_value',
- 'mandatory',
- 'force_default_on_freeze',
- 'force_metaconfig_on_freeze',
- 'frozen'])
+ 'unique',
+ 'force_store_value',
+ 'mandatory',
+ 'force_default_on_freeze',
+ 'force_metaconfig_on_freeze',
+ 'frozen'])
static_set = frozenset()
@@ -405,6 +409,7 @@ class Settings(object):
'context_props')
if not is_cached:
props = self._p_.getproperties(None,
+ None,
self.default_properties)
cache.setcache(None,
None,
@@ -416,11 +421,9 @@ class Settings(object):
def getproperties(self,
option_bag,
- apply_requires=True,
- search_properties=None):
+ apply_requires=True):
"""
"""
- # FIXME search_properties
option = option_bag.option
config_bag = option_bag.config_bag
if option.impl_is_symlinkoption():
@@ -430,25 +433,32 @@ class Settings(object):
if apply_requires:
cache = config_bag.context._impl_properties_cache
- props = config_bag.properties
+ config_bag_props = config_bag.properties
is_cached, props, validated = cache.getcache(path,
config_bag.expiration_time,
index,
- props,
+ config_bag_props,
{},
'self_props')
else:
is_cached = False
if not is_cached:
props = set()
- for prop in self._p_.getproperties(path,
- option.impl_getproperties()):
+ p_props = self._p_.getproperties(path,
+ None,
+ option.impl_getproperties())
+ if index is not None:
+ p_props = chain(p_props,
+ self._p_.getproperties(path,
+ index,
+ option.impl_getproperties()))
+ for prop in p_props:
if isinstance(prop, str):
props.add(prop)
elif apply_requires:
new_prop = prop.execute(option_bag,
leadership_must_have_index=True)
- if not new_prop:
+ if new_prop is None:
continue
elif not isinstance(new_prop, str):
raise ValueError(_('invalid property type {} for {} with {} function').format(type(new_prop),
@@ -457,8 +467,7 @@ class Settings(object):
if not option.impl_is_optiondescription() and option.impl_is_leader() and new_prop not in ALLOWED_LEADER_PROPERTIES:
raise LeadershipError(_('leader cannot have "{}" property').format(new_prop))
props.add(new_prop)
- props -= self.getpermissives(option,
- path)
+ props -= self.getpermissives(option_bag)
if apply_requires and not config_bag.is_unrestraint:
cache.setcache(path,
index,
@@ -470,37 +479,61 @@ class Settings(object):
def get_calculated_properties(self,
option_bag):
- opt = option_bag.option
- if opt.impl_is_symlinkoption():
- opt = opt.impl_getopt()
- path = opt.impl_getpath()
- for prop in self._p_.getproperties(path,
- opt.impl_getproperties()):
+ option = option_bag.option
+ if option.impl_is_symlinkoption():
+ option = option.impl_getopt()
+ path = option.impl_getpath()
+ p_props = self._p_.getproperties(path,
+ None,
+ option.impl_getproperties())
+ if option_bag.index is not None:
+ p_props = chain(p_props,
+ self._p_.getproperties(path,
+ option_bag.index,
+ option.impl_getproperties()))
+ for prop in p_props:
if not isinstance(prop, str):
yield prop
def has_properties_index(self,
option_bag):
- opt = option_bag.option
- if opt.impl_is_symlinkoption():
- opt = opt.impl_getopt()
- path = opt.impl_getpath()
- for prop in self._p_.getproperties(path,
- opt.impl_getproperties()):
- if not isinstance(prop, str) and prop.has_index:
+ option = option_bag.option
+ if option.impl_is_symlinkoption():
+ option = option.impl_getopt()
+ path = option.impl_getpath()
+ p_props = self._p_.getproperties(path,
+ None,
+ option.impl_getproperties())
+ if option_bag.index is not None:
+ p_props = chain(p_props,
+ self._p_.getproperties(path,
+ option_bag.index,
+ option.impl_getproperties()))
+ for prop in p_props:
+ if not isinstance(prop, str) and prop.has_index(option_bag.option):
return True
return False
def get_context_permissives(self):
- return self.getpermissives(None, None)
+ return self.getpermissives(None)
def getpermissives(self,
- opt,
- path):
- if opt and opt.impl_is_symlinkoption():
- opt = opt.impl_getopt()
- path = opt.impl_getpath()
- return self._pp_.getpermissives(path)
+ option_bag):
+ if option_bag is None:
+ path = None
+ index = None
+ else:
+ opt = option_bag.option
+ if opt.impl_is_symlinkoption():
+ opt = opt.impl_getopt()
+ path = opt.impl_getpath()
+ else:
+ path = option_bag.path
+ index = option_bag.index
+ permissives = self._pp_.getpermissives(path, None)
+ if index is not None:
+ permissives = frozenset(self._pp_.getpermissives(path, index) | permissives)
+ return permissives
#____________________________________________________________
# set methods
@@ -508,6 +541,7 @@ class Settings(object):
properties,
context):
self._p_.setproperties(None,
+ None,
properties)
context.cfgimpl_reset_cache(None)
@@ -536,6 +570,7 @@ class Settings(object):
'"force_default_on_freeze" or "force_metaconfig_on_freeze" property without "frozen"'
'').format(opt.impl_get_display_name()))
self._p_.setproperties(path,
+ option_bag.index,
properties)
# values too because of follower values could have a PropertiesOptionError has value
context.cfgimpl_reset_cache(option_bag)
@@ -566,13 +601,15 @@ class Settings(object):
raise TypeError(_("can't assign permissive to the symlinkoption \"{}\""
"").format(opt.impl_get_display_name()))
path = option_bag.path
+ index = option_bag.index
else:
path = None
+ index = None
forbidden_permissives = FORBIDDEN_SET_PERMISSIVES & permissives
if forbidden_permissives:
raise ConfigError(_('cannot add those permissives: {0}').format(
' '.join(forbidden_permissives)))
- self._pp_.setpermissives(path, permissives)
+ self._pp_.setpermissives(path, index, permissives)
if option_bag is not None:
option_bag.config_bag.context.cfgimpl_reset_cache(option_bag)
@@ -585,13 +622,15 @@ class Settings(object):
if option_bag is None:
opt = None
path = None
+ index = None
else:
opt = option_bag.option
assert not opt.impl_is_symlinkoption(), _("can't reset properties to "
"the symlinkoption \"{}\""
"").format(opt.impl_get_display_name())
path = option_bag.path
- self._p_.delproperties(path)
+ index = option_bag.index
+ self._p_.delproperties(path, index)
context.cfgimpl_reset_cache(option_bag)
def reset_permissives(self,
@@ -600,13 +639,15 @@ class Settings(object):
if option_bag is None:
opt = None
path = None
+ index = None
else:
opt = option_bag.option
assert not opt.impl_is_symlinkoption(), _("can't reset permissives to "
"the symlinkoption \"{}\""
"").format(opt.impl_get_display_name())
+ index = option_bag.index
path = option_bag.path
- self._pp_.delpermissive(path)
+ self._pp_.delpermissive(path, index)
context.cfgimpl_reset_cache(option_bag)
#____________________________________________________________
@@ -658,28 +699,27 @@ class Settings(object):
option_bag):
if 'mandatory' in option_bag.config_bag.properties:
values = option_bag.config_bag.context.cfgimpl_get_values()
- is_mandatory = False
if not ('permissive' in option_bag.config_bag.properties and
'mandatory' in option_bag.config_bag.permissives) and \
'mandatory' in option_bag.properties and values.isempty(option_bag.option,
value,
index=option_bag.index):
- is_mandatory = True
+ raise PropertiesOptionError(option_bag,
+ ['mandatory'],
+ self)
if 'empty' in option_bag.properties and values.isempty(option_bag.option,
value,
force_allow_empty_list=True,
index=option_bag.index):
- is_mandatory = True
- if is_mandatory:
raise PropertiesOptionError(option_bag,
- ['mandatory'],
+ ['empty'],
self)
def validate_frozen(self,
option_bag):
if option_bag.config_bag.properties and \
('everything_frozen' in option_bag.config_bag.properties or
- 'frozen' in option_bag.properties) and \
+ ('frozen' in option_bag.config_bag.properties and 'frozen' in option_bag.properties)) and \
not (('permissive' in option_bag.config_bag.properties) and
'frozen' in option_bag.config_bag.permissives):
raise PropertiesOptionError(option_bag,
@@ -694,6 +734,7 @@ class Settings(object):
append,
context):
props = self._p_.getproperties(None,
+ None,
self.default_properties)
modified = False
if remove & props:
diff --git a/tiramisu/storage/dictionary/setting.py b/tiramisu/storage/dictionary/setting.py
index 79a9cd6..15b98eb 100644
--- a/tiramisu/storage/dictionary/setting.py
+++ b/tiramisu/storage/dictionary/setting.py
@@ -15,7 +15,7 @@
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see .
# ____________________________________________________________
-from copy import copy
+from copy import deepcopy
from ...log import log
@@ -30,25 +30,29 @@ class Properties:
self._storage = storage
# properties
- def setproperties(self, path, properties):
- log.debug('setproperties %s %s', path, properties)
- self._properties[path] = properties
+ def setproperties(self, path, index, properties):
+ log.debug('setproperties %s %s %s', path, index, properties)
+ self._properties.setdefault(path, {})[index] = properties
- def getproperties(self, path, default_properties):
- ret = self._properties.get(path, frozenset(default_properties))
- log.debug('getproperties %s %s', path, ret)
+ def getproperties(self, path, index, default_properties):
+ if path not in self._properties:
+ ret = frozenset(default_properties)
+ else:
+ ret = self._properties[path].get(index, frozenset(default_properties))
+ log.debug('getproperties %s %s %s', path, index, ret)
return ret
- def delproperties(self, path):
+ def delproperties(self, path, index):
log.debug('delproperties %s', path)
- if path in self._properties:
- del(self._properties[path])
+ if path in self._properties and index in self._properties[path]:
+ del(self._properties[path][index])
+
def exportation(self):
"""return all modified settings in a dictionary
example: {'path1': set(['prop1', 'prop2'])}
"""
- return copy(self._properties)
+ return deepcopy(self._properties)
def importation(self, properties):
self._properties = properties
@@ -63,29 +67,28 @@ class Permissives:
self._permissives = {}
self._storage = storage
- def setpermissives(self, path, permissives):
+ def setpermissives(self, path, index, permissives):
log.debug('setpermissives %s %s', path, permissives)
- if not permissives:
- if path in self._permissives:
- del self._permissives[path]
- else:
- self._permissives[path] = permissives
+ self._permissives.setdefault(path, {})[index] = permissives
- def getpermissives(self, path=None):
- ret = self._permissives.get(path, frozenset())
+ def getpermissives(self, path, index):
+ if not path in self._permissives:
+ ret = frozenset()
+ else:
+ ret = self._permissives[path].get(index, frozenset())
log.debug('getpermissives %s %s', path, ret)
return ret
+ def delpermissive(self, path, index):
+ log.debug('delpermissive %s', path)
+ if path in self._permissives and index in self._permissives[path]:
+ del(self._permissives[path][index])
+
def exportation(self):
"""return all modified permissives in a dictionary
example: {'path1': set(['perm1', 'perm2'])}
"""
- return copy(self._permissives)
+ return deepcopy(self._permissives)
def importation(self, permissives):
self._permissives = permissives
-
- def delpermissive(self, path):
- log.debug('delpermissive %s', path)
- if path in self._permissives:
- del(self._permissives[path])
diff --git a/tiramisu/storage/sqlite3/setting.py b/tiramisu/storage/sqlite3/setting.py
index cce1445..0dca195 100644
--- a/tiramisu/storage/sqlite3/setting.py
+++ b/tiramisu/storage/sqlite3/setting.py
@@ -26,29 +26,30 @@ class Properties(Sqlite3DB):
super(Properties, self).__init__(storage)
# properties
- def setproperties(self, path, properties):
+ def setproperties(self, path, index, properties):
path = self._sqlite_encode_path(path)
- self._storage.execute("DELETE FROM property WHERE path = ? AND session_id = ?",
- (path, self._session_id),
+ self._storage.execute("DELETE FROM property WHERE path = ? AND tiram_index = ? AND session_id = ?",
+ (path, index, self._session_id),
False)
- self._storage.execute("INSERT INTO property(path, properties, session_id) VALUES "
- "(?, ?, ?)", (path,
- self._sqlite_encode(properties),
- self._session_id))
+ self._storage.execute("INSERT INTO property(path, tiram_index, properties, session_id) VALUES "
+ "(?, ?, ?, ?)", (path,
+ index,
+ self._sqlite_encode(properties),
+ self._session_id))
- def getproperties(self, path, default_properties):
+ def getproperties(self, path, index, default_properties):
path = self._sqlite_encode_path(path)
value = self._storage.select("SELECT properties FROM property WHERE "
- "path = ? AND session_id = ? LIMIT 1", (path, self._session_id))
+ "path = ? AND tiram_index = ? AND session_id = ? LIMIT 1", (path, index, self._session_id))
if value is None:
return set(default_properties)
else:
return set(self._sqlite_decode(value[0]))
- def delproperties(self, path):
+ def delproperties(self, path, index):
path = self._sqlite_encode_path(path)
- self._storage.execute("DELETE FROM property WHERE path = ? AND session_id = ?",
- (path, self._session_id))
+ self._storage.execute("DELETE FROM property WHERE path = ? AND tiram_index = ? AND session_id = ?",
+ (path, index, self._session_id))
def exportation(self):
"""return all modified settings in a dictionary
@@ -79,22 +80,25 @@ class Permissives(Sqlite3DB):
__slots__ = tuple()
# permissive
- def setpermissives(self, path, permissive):
+ def setpermissives(self, path, index, permissive):
path = self._sqlite_encode_path(path)
- log.debug('setpermissive %s %s %s', path, permissive, id(self))
- self._storage.execute("DELETE FROM permissive WHERE path = ? AND session_id = ?",
- (path, self._session_id),
- False)
- self._storage.execute("INSERT INTO permissive(path, permissives, session_id) "
- "VALUES (?, ?, ?)", (path,
+ log.debug('setpermissive %s %s %s %s', path, index, permissive, id(self))
+ self._storage.execute("DELETE FROM permissive WHERE path = ? AND tiram_index = ? AND session_id = ?",
+ (path,
+ index,
+ self._session_id),
+ False)
+ self._storage.execute("INSERT INTO permissive(path, tiram_index, permissives, session_id) "
+ "VALUES (?, ?, ?, ?)", (path,
+ index,
self._sqlite_encode(permissive),
self._session_id))
- def getpermissives(self, path='_none'):
+ def getpermissives(self, path, index):
path = self._sqlite_encode_path(path)
permissives = self._storage.select("SELECT permissives FROM "
- "permissive WHERE path = ? AND session_id = ? LIMIT 1",
- (path, self._session_id))
+ "permissive WHERE path = ? AND tiram_index = ? AND session_id = ? LIMIT 1",
+ (path, index, self._session_id))
if permissives is None:
ret = frozenset()
else:
@@ -102,17 +106,17 @@ class Permissives(Sqlite3DB):
log.debug('getpermissive %s %s %s', path, ret, id(self))
return ret
- def delpermissive(self, path):
+ def delpermissive(self, path, index):
path = self._sqlite_encode_path(path)
- self._storage.execute("DELETE FROM permissive WHERE path = ? AND session_id = ?",
- (path, self._session_id))
+ self._storage.execute("DELETE FROM permissive WHERE path = ? AND tiram_index = ? AND session_id = ?",
+ (path, index, self._session_id))
def exportation(self):
"""return all modified permissives in a dictionary
example: {'path1': set(['perm1', 'perm2'])}
"""
ret = {}
- for path, permissives in self._storage.select("SELECT path, permissives FROM permissive "
+ for path, index, permissives in self._storage.select("SELECT path, tiram_index, permissives FROM permissive "
"WHERE session_id = ?",
(self._session_id,),
only_one=False):
@@ -125,8 +129,9 @@ class Permissives(Sqlite3DB):
commit=False)
for path, permissive in permissives.items():
path = self._sqlite_encode_path(path)
- self._storage.execute("INSERT INTO permissive(path, permissives, session_id) "
+ self._storage.execute("INSERT INTO permissive(path, tiram_index, permissives, session_id) "
"VALUES (?, ?, ?)", (path,
+ index,
self._sqlite_encode(permissive),
self._session_id,
), False)
diff --git a/tiramisu/storage/sqlite3/storage.py b/tiramisu/storage/sqlite3/storage.py
index 771516d..dcbd81f 100644
--- a/tiramisu/storage/sqlite3/storage.py
+++ b/tiramisu/storage/sqlite3/storage.py
@@ -105,11 +105,11 @@ class Storage(object):
if init:
session_table = 'CREATE TABLE IF NOT EXISTS session(session_id INTEGER, '
session_table += 'session TEXT UNIQUE, persistent BOOL, PRIMARY KEY(session_id))'
- settings_table = 'CREATE TABLE IF NOT EXISTS property(path TEXT,'
- settings_table += 'properties text, session_id INTEGER, PRIMARY KEY(path, session_id), '
+ settings_table = 'CREATE TABLE IF NOT EXISTS property(path TEXT, '
+ settings_table += 'tiram_index INTEGER, properties TEXT, session_id INTEGER, PRIMARY KEY(path, tiram_index, session_id), '
settings_table += 'FOREIGN KEY(session_id) REFERENCES session(session_id))'
permissives_table = 'CREATE TABLE IF NOT EXISTS permissive(path TEXT,'
- permissives_table += 'permissives TEXT, session_id INTEGER, PRIMARY KEY(path, session_id), '
+ permissives_table += 'tiram_index INTEGER, permissives TEXT, session_id INTEGER, PRIMARY KEY(path, tiram_index, session_id), '
permissives_table += 'FOREIGN KEY(session_id) REFERENCES session(session_id))'
values_table = 'CREATE TABLE IF NOT EXISTS value(path TEXT, '
values_table += 'value TEXT, owner TEXT, idx INTEGER, session_id INTEGER, '\