better support for sqlalchemy storage

This commit is contained in:
Emmanuel Garette 2014-07-06 15:35:13 +02:00
parent 71f8926fca
commit 58c22aa70f
4 changed files with 349 additions and 0 deletions

View 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

View 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

View 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()

View 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")