better support for sqlalchemy storage
This commit is contained in:
parent
71f8926fca
commit
58c22aa70f
4 changed files with 349 additions and 0 deletions
110
tiramisu/storage/sqlalchemy/setting.py
Normal file
110
tiramisu/storage/sqlalchemy/setting.py
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"default plugin for setting: set it in a simple dictionary"
|
||||||
|
# Copyright (C) 2014 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
|
||||||
|
# Free Software Foundation, either version 3 of the License, or (at your
|
||||||
|
# option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
||||||
|
# details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
# ____________________________________________________________
|
||||||
|
from ..util import Cache
|
||||||
|
from .util import SqlAlchemyBase
|
||||||
|
import util
|
||||||
|
from sqlalchemy import Column, Integer, String, PickleType, ForeignKey
|
||||||
|
from sqlalchemy.orm import relationship
|
||||||
|
from sqlalchemy.ext.associationproxy import association_proxy
|
||||||
|
from sqlalchemy.orm.collections import attribute_mapped_collection
|
||||||
|
|
||||||
|
|
||||||
|
#____________________________________________________________
|
||||||
|
#
|
||||||
|
# properties|permissives
|
||||||
|
class _Property(SqlAlchemyBase):
|
||||||
|
__tablename__ = 'property'
|
||||||
|
id = Column(Integer, primary_key=True)
|
||||||
|
setting = Column(Integer, ForeignKey('settings.id'), nullable=False)
|
||||||
|
path = Column(String)
|
||||||
|
properties = Column(PickleType)
|
||||||
|
|
||||||
|
def __init__(self, path, properties):
|
||||||
|
self.path = path
|
||||||
|
self.properties = properties
|
||||||
|
|
||||||
|
|
||||||
|
class _Permissive (SqlAlchemyBase):
|
||||||
|
__tablename__ = 'permissive'
|
||||||
|
id = Column(Integer, primary_key=True)
|
||||||
|
setting = Column(Integer, ForeignKey('settings.id'), nullable=False)
|
||||||
|
path = Column(String)
|
||||||
|
permissives = Column(PickleType)
|
||||||
|
|
||||||
|
def __init__(self, path, permissives):
|
||||||
|
self.path = path
|
||||||
|
self.permissives = permissives
|
||||||
|
|
||||||
|
|
||||||
|
#____________________________________________________________
|
||||||
|
#FIXME marche pas le cache ... de toute facon je vais faire un storage separe !
|
||||||
|
class Settings(Cache, SqlAlchemyBase):
|
||||||
|
__tablename__ = 'settings'
|
||||||
|
id = Column(Integer, primary_key=True)
|
||||||
|
_props = relationship("_Property",
|
||||||
|
collection_class=attribute_mapped_collection('path'),
|
||||||
|
cascade="all, delete-orphan")
|
||||||
|
_properties = association_proxy("_props", "properties")
|
||||||
|
_perms = relationship("_Permissive",
|
||||||
|
collection_class=attribute_mapped_collection('path'),
|
||||||
|
cascade="all, delete-orphan")
|
||||||
|
_permissives = association_proxy("_perms", "permissives")
|
||||||
|
|
||||||
|
def __init__(self, storage):
|
||||||
|
super(Settings, self).__init__(storage)
|
||||||
|
|
||||||
|
# properties
|
||||||
|
def setproperties(self, path, properties):
|
||||||
|
self._properties[path] = properties
|
||||||
|
|
||||||
|
def getproperties(self, path, default_properties):
|
||||||
|
return self._properties.get(path, set(default_properties))
|
||||||
|
|
||||||
|
def hasproperties(self, path):
|
||||||
|
return path in self._properties
|
||||||
|
|
||||||
|
def reset_all_properties(self):
|
||||||
|
self._properties.clear()
|
||||||
|
|
||||||
|
def delproperties(self, path):
|
||||||
|
try:
|
||||||
|
del(self._properties[path])
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# permissive
|
||||||
|
def setpermissive(self, path, permissive):
|
||||||
|
self._permissives[path] = frozenset(permissive)
|
||||||
|
util.session.commit()
|
||||||
|
|
||||||
|
def getpermissive(self, path=None):
|
||||||
|
ret = self._permissives.get(path, frozenset())
|
||||||
|
#replace None by a frozenset()
|
||||||
|
return {None: frozenset()}.get(ret, ret)
|
||||||
|
|
||||||
|
def get_modified_properties(self):
|
||||||
|
"""return all modified settings in a dictionary
|
||||||
|
example: {'path1': set(['prop1', 'prop2'])}
|
||||||
|
"""
|
||||||
|
return self._properties
|
||||||
|
|
||||||
|
def get_modified_permissives(self):
|
||||||
|
"""return all modified permissives in a dictionary
|
||||||
|
example: {'path1': set(['perm1', 'perm2'])}
|
||||||
|
"""
|
||||||
|
return self._permissives
|
59
tiramisu/storage/sqlalchemy/storage.py
Normal file
59
tiramisu/storage/sqlalchemy/storage.py
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright (C) 2013 Team tiramisu (see AUTHORS for all contributors)
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify it
|
||||||
|
# under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
# Free Software Foundation, either version 3 of the License, or (at your
|
||||||
|
# option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
||||||
|
# details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
# ____________________________________________________________
|
||||||
|
from tiramisu.i18n import _
|
||||||
|
from tiramisu.error import ConfigError
|
||||||
|
from ..util import SerializeObject
|
||||||
|
|
||||||
|
|
||||||
|
class Setting(SerializeObject):
|
||||||
|
"""Dictionary storage has no particular setting.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
setting = Setting()
|
||||||
|
_list_sessions = []
|
||||||
|
|
||||||
|
|
||||||
|
def list_sessions(): # pragma: optional cover
|
||||||
|
return _list_sessions
|
||||||
|
|
||||||
|
|
||||||
|
def delete_session(session_id): # pragma: optional cover
|
||||||
|
raise ConfigError(_('dictionary storage cannot delete session'))
|
||||||
|
|
||||||
|
|
||||||
|
class Storage(object):
|
||||||
|
__slots__ = ('session_id', 'persistent')
|
||||||
|
storage = 'dictionary'
|
||||||
|
#if object could be serializable
|
||||||
|
serializable = True
|
||||||
|
|
||||||
|
def __init__(self, session_id, persistent, test=False):
|
||||||
|
if not test and session_id in _list_sessions: # pragma: optional cover
|
||||||
|
raise ValueError(_('session already used'))
|
||||||
|
if persistent: # pragma: optional cover
|
||||||
|
raise ValueError(_('a dictionary cannot be persistent'))
|
||||||
|
self.session_id = session_id
|
||||||
|
self.persistent = persistent
|
||||||
|
_list_sessions.append(self.session_id)
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
try:
|
||||||
|
_list_sessions.remove(self.session_id)
|
||||||
|
except AttributeError: # pragma: optional cover
|
||||||
|
pass
|
39
tiramisu/storage/sqlalchemy/util.py
Normal file
39
tiramisu/storage/sqlalchemy/util.py
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
""
|
||||||
|
# Copyright (C) 2014 Team tiramisu (see AUTHORS for all contributors)
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
#
|
||||||
|
# ____________________________________________________________
|
||||||
|
from sqlalchemy.orm import sessionmaker
|
||||||
|
from sqlalchemy.ext.declarative import declarative_base
|
||||||
|
from sqlalchemy import create_engine
|
||||||
|
|
||||||
|
|
||||||
|
engine = create_engine('sqlite:///:memory:')
|
||||||
|
SqlAlchemyBase = declarative_base()
|
||||||
|
|
||||||
|
global session
|
||||||
|
session = None
|
||||||
|
|
||||||
|
|
||||||
|
def load():
|
||||||
|
global session
|
||||||
|
if session is None:
|
||||||
|
#engine.echo = True
|
||||||
|
#print SqlAlchemyBase.metadata.tables.keys()
|
||||||
|
SqlAlchemyBase.metadata.create_all(engine)
|
||||||
|
Session = sessionmaker(bind=engine)
|
||||||
|
session = Session()
|
141
tiramisu/storage/sqlalchemy/value.py
Normal file
141
tiramisu/storage/sqlalchemy/value.py
Normal file
|
@ -0,0 +1,141 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"plugin for value: set it in sqlalchemy"
|
||||||
|
# Copyright (C) 2013-2014 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
|
||||||
|
# Free Software Foundation, either version 3 of the License, or (at your
|
||||||
|
# option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
||||||
|
# details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
# ____________________________________________________________
|
||||||
|
|
||||||
|
#FIXME : il me faut une classe pour le owner !
|
||||||
|
#FIXME : pas si simple que ca ... parce que on lit un owner pour une config ...
|
||||||
|
#FIXME : mais ca serait peut etre logique
|
||||||
|
#FIXME : c'est en fait dans le Setting qu'il faut faire ca ... a voir après
|
||||||
|
|
||||||
|
|
||||||
|
from ..util import Cache
|
||||||
|
from .util import SqlAlchemyBase
|
||||||
|
from sqlalchemy import Column, Integer, String, PickleType, ForeignKey
|
||||||
|
from sqlalchemy.orm import relationship
|
||||||
|
from sqlalchemy.orm.collections import attribute_mapped_collection
|
||||||
|
from sqlalchemy.ext.associationproxy import association_proxy
|
||||||
|
|
||||||
|
|
||||||
|
#____________________________________________________________
|
||||||
|
#
|
||||||
|
# information
|
||||||
|
class _Vinformation(SqlAlchemyBase):
|
||||||
|
__tablename__ = 'vinformation'
|
||||||
|
id = Column(Integer, primary_key=True)
|
||||||
|
values = Column(Integer, ForeignKey('values.id'))
|
||||||
|
key = Column(String)
|
||||||
|
value = Column(PickleType)
|
||||||
|
|
||||||
|
def __init__(self, key, value):
|
||||||
|
self.key = key
|
||||||
|
self.value = value
|
||||||
|
|
||||||
|
|
||||||
|
class _Value(SqlAlchemyBase):
|
||||||
|
__tablename__ = 'value'
|
||||||
|
id = Column(Integer, primary_key=True)
|
||||||
|
values = Column(Integer, ForeignKey('values.id'), nullable=False)
|
||||||
|
path = Column(String, nullable=True, unique=True, index=True)
|
||||||
|
#FIXME a revoir avec le owner dans le setting
|
||||||
|
owner = Column(String, nullable=False)
|
||||||
|
value = Column(PickleType, nullable=False)
|
||||||
|
|
||||||
|
def __init__(self, key, value):
|
||||||
|
self.path = key
|
||||||
|
self.value = value[0]
|
||||||
|
self.owner = value[1]
|
||||||
|
|
||||||
|
|
||||||
|
class Values(Cache, SqlAlchemyBase):
|
||||||
|
__tablename__ = 'values'
|
||||||
|
id = Column(Integer, primary_key=True)
|
||||||
|
_vals = relationship("_Value",
|
||||||
|
collection_class=attribute_mapped_collection('key'),
|
||||||
|
cascade="all, delete-orphan")
|
||||||
|
_informations = association_proxy("_vals", "value")
|
||||||
|
_infos = relationship("_Vinformation",
|
||||||
|
collection_class=attribute_mapped_collection('key'),
|
||||||
|
cascade="all, delete-orphan")
|
||||||
|
_informations = association_proxy("_infos", "value")
|
||||||
|
|
||||||
|
def __init__(self, storage):
|
||||||
|
"""init plugin means create values storage
|
||||||
|
"""
|
||||||
|
self._values = {}
|
||||||
|
self._informations = {}
|
||||||
|
super(Values, self).__init__(storage)
|
||||||
|
|
||||||
|
# value
|
||||||
|
def setvalue(self, path, value, owner):
|
||||||
|
"""set value for a path
|
||||||
|
a specified value must be associated to an owner
|
||||||
|
"""
|
||||||
|
self._values[path] = (owner, value)
|
||||||
|
|
||||||
|
def getvalue(self, path):
|
||||||
|
"""get value for a path
|
||||||
|
return: only value, not the owner
|
||||||
|
"""
|
||||||
|
return self._values[path][1]
|
||||||
|
|
||||||
|
def hasvalue(self, path):
|
||||||
|
"""if path has a value
|
||||||
|
return: boolean
|
||||||
|
"""
|
||||||
|
return path in self._values
|
||||||
|
|
||||||
|
def resetvalue(self, path):
|
||||||
|
"""remove value means delete value in storage
|
||||||
|
"""
|
||||||
|
del(self._values[path])
|
||||||
|
|
||||||
|
def get_modified_values(self):
|
||||||
|
"""return all values in a dictionary
|
||||||
|
example: {'path1': (owner, 'value1'), 'path2': (owner, 'value2')}
|
||||||
|
"""
|
||||||
|
return self._values
|
||||||
|
|
||||||
|
# owner
|
||||||
|
def setowner(self, path, owner):
|
||||||
|
"""change owner for a path
|
||||||
|
"""
|
||||||
|
self._values[path] = (owner, self._values[path][1])
|
||||||
|
|
||||||
|
def getowner(self, path, default):
|
||||||
|
"""get owner for a path
|
||||||
|
return: owner object
|
||||||
|
"""
|
||||||
|
return self._values.get(path, (default, None))[0]
|
||||||
|
|
||||||
|
def set_information(self, key, value):
|
||||||
|
"""updates the information's attribute
|
||||||
|
(which is a dictionary)
|
||||||
|
|
||||||
|
:param key: information's key (ex: "help", "doc"
|
||||||
|
:param value: information's value (ex: "the help string")
|
||||||
|
"""
|
||||||
|
self._informations[key] = value
|
||||||
|
|
||||||
|
def get_information(self, key):
|
||||||
|
"""retrieves one information's item
|
||||||
|
|
||||||
|
:param key: the item string (ex: "help")
|
||||||
|
"""
|
||||||
|
if key in self._informations:
|
||||||
|
return self._informations[key]
|
||||||
|
else: # pragma: optional cover
|
||||||
|
raise ValueError("not found")
|
Loading…
Reference in a new issue