sqlalchemy has a storage

This commit is contained in:
Emmanuel Garette 2014-01-20 14:53:08 +01:00
parent 068f68460d
commit 661f844ce6
7 changed files with 310 additions and 299 deletions

View File

@ -481,6 +481,7 @@ def test_callback_master_and_slaves_slave_list():
assert cfg.val1.val2 == ['val', 'val'] assert cfg.val1.val2 == ['val', 'val']
cfg.val1.val1 = ['val1'] cfg.val1.val1 = ['val1']
#wrong len #wrong len
print cfg.val1.val2
raises(SlaveError, 'cfg.val1.val2') raises(SlaveError, 'cfg.val1.val2')

View File

@ -148,7 +148,7 @@ def carry_out_calculation(option, config, callback, callback_params,
for callbk in callbacks.params: for callbk in callbacks.params:
if callbk.option is not None: if callbk.option is not None:
# callbk is something link (opt, True|False) # callbk is something link (opt, True|False)
opt = callbk.get_option(config) opt = callbk.option
force_permissive = callbk.force_permissive force_permissive = callbk.force_permissive
path = config.cfgimpl_get_description().impl_get_path_by_opt( path = config.cfgimpl_get_description().impl_get_path_by_opt(
opt) opt)

View File

@ -28,17 +28,15 @@ from IPy import IP
import warnings import warnings
#from pickle import loads, dumps #from pickle import loads, dumps
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import create_engine, Column, Integer, String, Boolean, \
PickleType, ForeignKey, Table
from sqlalchemy.orm import relationship, backref
from sqlalchemy.orm import sessionmaker
from tiramisu.error import ConfigError, ConflictError, ValueWarning from tiramisu.error import ConfigError, ConflictError, ValueWarning
from tiramisu.setting import groups, multitypes from tiramisu.setting import groups, multitypes
from tiramisu.i18n import _ from tiramisu.i18n import _
from tiramisu.autolib import carry_out_calculation from tiramisu.autolib import carry_out_calculation
#FIXME : need storage...
from tiramisu.storage.sqlalchemy.option import StorageBase, StorageOptionDescription
from sqlalchemy.ext.declarative import declarative_base, declared_attr
name_regexp = re.compile(r'^\d+') name_regexp = re.compile(r'^\d+')
forbidden_names = ('iter_all', 'iter_group', 'find', 'find_first', forbidden_names = ('iter_all', 'iter_group', 'find', 'find_first',
'make_dict', 'unwrap_from_path', 'read_only', 'make_dict', 'unwrap_from_path', 'read_only',
@ -58,170 +56,7 @@ def valid_name(name):
return False return False
#____________________________________________________________ #____________________________________________________________
# #
class Base(StorageBase):
engine = create_engine('sqlite:///:memory:')
Base = declarative_base()
class _RequireExpected(Base):
__tablename__ = 'expected'
id = Column(Integer, primary_key=True)
expected = Column(PickleType)
require = Column(Integer, ForeignKey('require.id'))
def __init__(self, expected):
self.expected = expected
class _RequireOption(Base):
__tablename__ = 'require'
id = Column(Integer, primary_key=True)
option = Column(Integer, ForeignKey('baseoption.id'))
r_opt = Column(Integer)
expected = relationship("_RequireExpected")
action = Column(String, nullable=False)
inverse = Column(Boolean, default=False)
transitive = Column(Boolean, default=True)
same_action = Column(Boolean, default=True)
def __init__(self, option, expected, action, inverse, transitive,
same_action):
self.r_opt = option.id
for expect in expected:
self.expected.append(_RequireExpected(expect))
self.action = action
self.inverse = inverse
self.transitive = transitive
self.same_action = same_action
def get_expected(self):
for expected in self.expected:
yield(expected.expected)
def get_option(self, config):
return config.cfgimpl_get_description().impl_get_opt_by_id(self.r_opt)
property_table = Table('property', Base.metadata,
Column('left_id', Integer, ForeignKey('propertyoption.name')),
Column('right_id', Integer, ForeignKey('baseoption.id'))
)
class _PropertyOption(Base):
__tablename__ = 'propertyoption'
name = Column(String, primary_key=True)
def __init__(self, name):
self.name = name
class _Information(Base):
__tablename__ = 'information'
id = Column(Integer, primary_key=True)
option = Column(Integer, ForeignKey('baseoption.id'))
key = Column(String)
value = Column(PickleType)
def __init__(self, key, value):
self.key = key
self.value = value
class _CallbackParamOption(Base):
__tablename__ = 'callback_param_option'
id = Column(Integer, primary_key=True)
callback_param = Column(Integer, ForeignKey('callback_param.id'))
option = Column(Integer)
force_permissive = Column(Boolean)
value = Column(PickleType)
def __init__(self, option=None, force_permissive=None, value=None):
if value is not None:
self.value = value
else:
if isinstance(option, SymLinkOption):
option = option._opt
self.option = option.id
self.force_permissive = force_permissive
def get_option(self, config):
return config.cfgimpl_get_description().impl_get_opt_by_id(self.option)
class _CallbackParam(Base):
__tablename__ = 'callback_param'
id = Column(Integer, primary_key=True)
callback = Column(Integer, ForeignKey('baseoption.id'))
name = Column(String)
params = relationship('_CallbackParamOption')
def __init__(self, name, params):
self.name = name
for param in params:
if isinstance(param, tuple):
self.params.append(_CallbackParamOption(option=param[0],
force_permissive=param[1]))
else:
self.params.append(_CallbackParamOption(value=param))
consistency_table = Table('consistencyopt', Base.metadata,
Column('left_id', Integer, ForeignKey('consistency.id')),
Column('right_id', Integer, ForeignKey('baseoption.id'))
)
class _Consistency(Base):
__tablename__ = 'consistency'
id = Column(Integer, primary_key=True)
func = Column(PickleType)
def __init__(self, func, all_cons_opts):
self.func = func
for option in all_cons_opts:
option._consistencies.append(self)
class BaseOption(Base):
"""This abstract base class stands for attribute access
in options that have to be set only once, it is of course done in the
__setattr__ method
"""
__tablename__ = 'baseoption'
id = Column(Integer, primary_key=True)
_name = Column(String)
_informations = relationship('_Information')
_default = Column(PickleType)
_default_multi = Column(PickleType)
_requires = relationship('_RequireOption')
_multi = Column(Boolean)
_multitype = Column(String)
_callback = Column(PickleType)
_callback_params = relationship('_CallbackParam')
_validator = Column(PickleType)
_validator_params = relationship('_CallbackParam')
_parent = Column(Integer, ForeignKey('baseoption.id'))
_children = relationship('BaseOption', enable_typechecks=False)
_properties = relationship('_PropertyOption', secondary=property_table,
backref=backref('options', enable_typechecks=False))
_warnings_only = Column(Boolean)
_readonly = Column(Boolean, default=False)
_consistencies = relationship('_Consistency', secondary=consistency_table,
backref=backref('options', enable_typechecks=False))
_choice_values = Column(PickleType)
_choice_open_values = Column(Boolean)
_type = Column(String(50))
__mapper_args__ = {
'polymorphic_identity': 'person',
'polymorphic_on': _type
}
#FIXME devrait etre une table
_optiondescription_group_type = Column(String)
#__slots__ = ('_name', '_requires', '_properties', '_readonly',
# '_calc_properties', '_impl_informations',
# '_state_readonly', '_state_requires', '_stated')
def __init__(self, name, doc, default=None, default_multi=None, def __init__(self, name, doc, default=None, default_multi=None,
requires=None, multi=False, callback=None, requires=None, multi=False, callback=None,
callback_params=None, validator=None, validator_params=None, callback_params=None, validator=None, validator_params=None,
@ -235,7 +70,7 @@ class BaseOption(Base):
if requires is not None: if requires is not None:
for values in requires.values(): for values in requires.values():
for require in values.values(): for require in values.values():
self._requires.append(_RequireOption(*require)) self._add_require(require)
if not multi and default_multi is not None: if not multi and default_multi is not None:
raise ValueError(_("a default_multi is set whereas multi is False" raise ValueError(_("a default_multi is set whereas multi is False"
" in option: {0}").format(name)) " in option: {0}").format(name))
@ -271,7 +106,7 @@ class BaseOption(Base):
self._validator = validator self._validator = validator
if validator_params is not None: if validator_params is not None:
for key, values in validator_params.items(): for key, values in validator_params.items():
self._validator_params.append(_CallbackParam(key, values)) self._add_validator(key, values)
if callback is None and callback_params is not None: if callback is None and callback_params is not None:
raise ValueError(_("params defined for a callback function but " raise ValueError(_("params defined for a callback function but "
"no callback defined" "no callback defined"
@ -281,7 +116,7 @@ class BaseOption(Base):
self._callback = callback self._callback = callback
if callback_params is not None: if callback_params is not None:
for key, values in callback_params.items(): for key, values in callback_params.items():
self._callback_params.append(_CallbackParam(key, values)) self._add_callback(key, values)
if requires is not None and properties is not tuple(): if requires is not None and properties is not tuple():
set_forbidden_properties = set(properties) & set(requires.keys()) set_forbidden_properties = set(properties) & set(requires.keys())
if set_forbidden_properties != frozenset(): if set_forbidden_properties != frozenset():
@ -298,41 +133,19 @@ class BaseOption(Base):
else: else:
self._default = default self._default = default
for prop in properties: for prop in properties:
prop_obj = session.query(_PropertyOption).filter(_PropertyOption.name == prop).first() self._properties.append(self._get_property_object(prop))
if prop_obj is None:
prop_obj = _PropertyOption(prop)
self._properties.append(prop_obj)
self._warnings_only = warnings_only self._warnings_only = warnings_only
return super(Base, self).__init__()
# ____________________________________________________________
# information
def impl_set_information(self, key, value):
"""updates the information's attribute
(which is a dictionary)
:param key: information's key (ex: "help", "doc" class BaseOption(Base):
:param value: information's value (ex: "the help string") """This abstract base class stands for attribute access
in options that have to be set only once, it is of course done in the
__setattr__ method
""" """
#FIXME pas append ! remplacer ! #__slots__ = ('_name', '_requires', '_properties', '_readonly',
info = session.query(_Information).filter_by(option=self.id, key=key).first() # '_calc_properties', '_impl_informations',
if info is None: # '_state_readonly', '_state_requires', '_stated')
self._informations.append(_Information(key, value))
else:
info.value = value
def impl_get_information(self, key, default=None):
"""retrieves one information's item
:param key: the item string (ex: "help")
"""
info = session.query(_Information).filter_by(option=self.id, key=key).first()
if info is not None:
return info.value
elif default is not None:
return default
else:
raise ValueError(_("information's item not found: {0}").format(
key))
# ____________________________________________________________ # ____________________________________________________________
# serialize object # serialize object
@ -500,8 +313,6 @@ class Option(BaseOption):
validator_params, properties, validator_params, properties,
warnings_only, choice_values, warnings_only, choice_values,
choice_open_values) choice_open_values)
session.add(self)
session.commit()
#def __setattr__(self, name, value): #def __setattr__(self, name, value):
# """set once and only once some attributes in the option, # """set once and only once some attributes in the option,
@ -749,7 +560,7 @@ class Option(BaseOption):
else: else:
self._launch_consistency(func, self, value, None, self._launch_consistency(func, self, value, None,
None, all_cons_opts) None, all_cons_opts)
_Consistency(func, all_cons_opts) self._add_consistency(func, all_cons_opts)
self.impl_validate(self.impl_getdefault()) self.impl_validate(self.impl_getdefault())
def _cons_not_equal(self, opts, vals): def _cons_not_equal(self, opts, vals):
@ -856,10 +667,6 @@ class ChoiceOption(Option):
""" """
#__slots__ = ('_values', '_open_values') #__slots__ = ('_values', '_open_values')
__mapper_args__ = {
'polymorphic_identity': 'choice',
}
def __init__(self, name, doc, values, default=None, default_multi=None, def __init__(self, name, doc, values, default=None, default_multi=None,
requires=None, multi=False, callback=None, requires=None, multi=False, callback=None,
callback_params=None, open_values=False, validator=None, callback_params=None, open_values=False, validator=None,
@ -901,9 +708,6 @@ class ChoiceOption(Option):
class BoolOption(Option): class BoolOption(Option):
"represents a choice between ``True`` and ``False``" "represents a choice between ``True`` and ``False``"
# __slots__ = tuple() # __slots__ = tuple()
__mapper_args__ = {
'polymorphic_identity': 'bool',
}
def _validate(self, value): def _validate(self, value):
if not isinstance(value, bool): if not isinstance(value, bool):
@ -913,9 +717,6 @@ class BoolOption(Option):
class IntOption(Option): class IntOption(Option):
"represents a choice of an integer" "represents a choice of an integer"
# __slots__ = tuple() # __slots__ = tuple()
__mapper_args__ = {
'polymorphic_identity': 'int',
}
def _validate(self, value): def _validate(self, value):
if not isinstance(value, int): if not isinstance(value, int):
@ -925,9 +726,6 @@ class IntOption(Option):
class FloatOption(Option): class FloatOption(Option):
"represents a choice of a floating point number" "represents a choice of a floating point number"
#__slots__ = tuple() #__slots__ = tuple()
__mapper_args__ = {
'polymorphic_identity': 'float',
}
def _validate(self, value): def _validate(self, value):
if not isinstance(value, float): if not isinstance(value, float):
@ -937,9 +735,6 @@ class FloatOption(Option):
class StrOption(Option): class StrOption(Option):
"represents the choice of a string" "represents the choice of a string"
#__slots__ = tuple() #__slots__ = tuple()
__mapper_args__ = {
'polymorphic_identity': 'string',
}
def _validate(self, value): def _validate(self, value):
if not isinstance(value, str): if not isinstance(value, str):
@ -955,9 +750,6 @@ else:
class UnicodeOption(Option): class UnicodeOption(Option):
"represents the choice of a unicode string" "represents the choice of a unicode string"
#__slots__ = tuple() #__slots__ = tuple()
__mapper_args__ = {
'polymorphic_identity': 'unicode',
}
_empty = u'' _empty = u''
def _validate(self, value): def _validate(self, value):
@ -967,9 +759,6 @@ else:
class SymLinkOption(BaseOption): class SymLinkOption(BaseOption):
#__slots__ = ('_name', '_opt', '_state_opt', '_readonly', '_parent') #__slots__ = ('_name', '_opt', '_state_opt', '_readonly', '_parent')
__mapper_args__ = {
'polymorphic_identity': 'symlink',
}
#not return _opt consistencies #not return _opt consistencies
#_consistencies = None #_consistencies = None
@ -982,8 +771,7 @@ class SymLinkOption(BaseOption):
self._opt = opt self._opt = opt
self._readonly = True self._readonly = True
self._parent = None self._parent = None
session.add(self) self.commit()
session.commit()
def __getattr__(self, name): def __getattr__(self, name):
if name in ('_opt', '_opt_type', '_readonly', 'impl_getname'): if name in ('_opt', '_opt_type', '_readonly', 'impl_getname'):
@ -1001,17 +789,13 @@ class SymLinkOption(BaseOption):
super(SymLinkOption, self)._impl_setstate(descr) super(SymLinkOption, self)._impl_setstate(descr)
def impl_get_information(self, key, default=None): def impl_get_information(self, key, default=None):
#FIXME ne devrait pas etre util si ? #FIXME ne devrait pas etre utile si ?
return self._opt.impl_get_information(key, default) return self._opt.impl_get_information(key, default)
class IPOption(Option): class IPOption(Option):
"represents the choice of an ip" "represents the choice of an ip"
#__slots__ = ('_private_only', '_allow_reserved') #__slots__ = ('_private_only', '_allow_reserved')
__mapper_args__ = {
'polymorphic_identity': 'ip',
}
def __init__(self, name, doc, default=None, default_multi=None, def __init__(self, name, doc, default=None, default_multi=None,
requires=None, multi=False, callback=None, requires=None, multi=False, callback=None,
callback_params=None, validator=None, validator_params=None, callback_params=None, validator=None, validator_params=None,
@ -1061,10 +845,6 @@ class PortOption(Option):
see: http://en.wikipedia.org/wiki/Port_numbers see: http://en.wikipedia.org/wiki/Port_numbers
""" """
#__slots__ = ('_allow_range', '_allow_zero', '_min_value', '_max_value') #__slots__ = ('_allow_range', '_allow_zero', '_min_value', '_max_value')
__mapper_args__ = {
'polymorphic_identity': 'port',
}
def __init__(self, name, doc, default=None, default_multi=None, def __init__(self, name, doc, default=None, default_multi=None,
requires=None, multi=False, callback=None, requires=None, multi=False, callback=None,
callback_params=None, validator=None, validator_params=None, callback_params=None, validator=None, validator_params=None,
@ -1126,10 +906,6 @@ class PortOption(Option):
class NetworkOption(Option): class NetworkOption(Option):
"represents the choice of a network" "represents the choice of a network"
#__slots__ = tuple() #__slots__ = tuple()
__mapper_args__ = {
'polymorphic_identity': 'network',
}
def _validate(self, value): def _validate(self, value):
try: try:
IP(value) IP(value)
@ -1145,9 +921,6 @@ class NetworkOption(Option):
class NetmaskOption(Option): class NetmaskOption(Option):
"represents the choice of a netmask" "represents the choice of a netmask"
#__slots__ = tuple() #__slots__ = tuple()
__mapper_args__ = {
'polymorphic_identity': 'netmask',
}
def _validate(self, value): def _validate(self, value):
try: try:
@ -1201,9 +974,6 @@ class NetmaskOption(Option):
class BroadcastOption(Option): class BroadcastOption(Option):
#__slots__ = tuple() #__slots__ = tuple()
__mapper_args__ = {
'polymorphic_identity': 'broadcast',
}
def _validate(self, value): def _validate(self, value):
try: try:
@ -1232,9 +1002,6 @@ class DomainnameOption(Option):
fqdn: with tld, not supported yet fqdn: with tld, not supported yet
""" """
#__slots__ = ('_dom_type', '_allow_ip', '_allow_without_dot', '_domain_re') #__slots__ = ('_dom_type', '_allow_ip', '_allow_without_dot', '_domain_re')
__mapper_args__ = {
'polymorphic_identity': 'domainname',
}
def __init__(self, name, doc, default=None, default_multi=None, def __init__(self, name, doc, default=None, default_multi=None,
requires=None, multi=False, callback=None, requires=None, multi=False, callback=None,
@ -1297,9 +1064,6 @@ class DomainnameOption(Option):
class EmailOption(DomainnameOption): class EmailOption(DomainnameOption):
#__slots__ = tuple() #__slots__ = tuple()
__mapper_args__ = {
'polymorphic_identity': 'email',
}
username_re = re.compile(r"^[\w!#$%&'*+\-/=?^`{|}~.]+$") username_re = re.compile(r"^[\w!#$%&'*+\-/=?^`{|}~.]+$")
def _validate(self, value): def _validate(self, value):
@ -1316,9 +1080,6 @@ class EmailOption(DomainnameOption):
class URLOption(DomainnameOption): class URLOption(DomainnameOption):
#__slots__ = tuple() #__slots__ = tuple()
__mapper_args__ = {
'polymorphic_identity': 'url',
}
proto_re = re.compile(r'(http|https)://') proto_re = re.compile(r'(http|https)://')
path_re = re.compile(r"^[a-z0-9\-\._~:/\?#\[\]@!%\$&\'\(\)\*\+,;=]+$") path_re = re.compile(r"^[a-z0-9\-\._~:/\?#\[\]@!%\$&\'\(\)\*\+,;=]+$")
@ -1355,9 +1116,6 @@ class URLOption(DomainnameOption):
class FilenameOption(Option): class FilenameOption(Option):
#__slots__ = tuple() #__slots__ = tuple()
__mapper_args__ = {
'polymorphic_identity': 'file',
}
path_re = re.compile(r"^[a-zA-Z0-9\-\._~/+]+$") path_re = re.compile(r"^[a-zA-Z0-9\-\._~/+]+$")
def _validate(self, value): def _validate(self, value):
@ -1366,7 +1124,7 @@ class FilenameOption(Option):
raise ValueError(_('invalid filename')) raise ValueError(_('invalid filename'))
class OptionDescription(BaseOption): class OptionDescription(BaseOption, StorageOptionDescription):
"""Config's schema (organisation, group) and container of Options """Config's schema (organisation, group) and container of Options
The `OptionsDescription` objects lives in the `tiramisu.config.Config`. The `OptionsDescription` objects lives in the `tiramisu.config.Config`.
""" """
@ -1375,9 +1133,6 @@ class OptionDescription(BaseOption):
# '_cache_consistencies', '_calc_properties', '__weakref__', # '_cache_consistencies', '_calc_properties', '__weakref__',
# '_readonly', '_impl_informations', '_state_requires', # '_readonly', '_impl_informations', '_state_requires',
# '_stated', '_state_readonly') # '_stated', '_state_readonly')
__mapper_args__ = {
'polymorphic_identity': 'optiondescription',
}
def __init__(self, name, doc, children, requires=None, properties=None): def __init__(self, name, doc, children, requires=None, properties=None):
""" """
@ -1385,8 +1140,6 @@ class OptionDescription(BaseOption):
""" """
super(OptionDescription, self).__init__(name, doc=doc, requires=requires, properties=properties) super(OptionDescription, self).__init__(name, doc=doc, requires=requires, properties=properties)
session.add(self)
session.commit()
child_names = [child.impl_getname() for child in children] child_names = [child.impl_getname() for child in children]
#better performance like this #better performance like this
valid_child = copy(child_names) valid_child = copy(child_names)
@ -1528,28 +1281,6 @@ class OptionDescription(BaseOption):
self._cache_consistencies[opt] = tuple(cons) self._cache_consistencies[opt] = tuple(cons)
self._readonly = True self._readonly = True
def impl_get_opt_by_path(self, path):
try:
#FIXME
idx = self._cache_paths[1].index(path)
opt_id = self._cache_paths[0][idx]
return session.query(BaseOption).filter_by(id=opt_id).first()
except ValueError:
raise AttributeError(_('no option for path {0}').format(path))
def impl_get_opt_by_id(self, opt_id):
try:
#FIXME
#idx = self._cache_paths[0].index(opt_id)
return session.query(BaseOption).filter_by(id=opt_id).first()
except ValueError:
raise AttributeError(_('no id {0} found').format(opt_id))
def impl_get_path_by_opt(self, opt):
try:
return self._cache_paths[1][self._cache_paths[0].index(opt.id)]
except ValueError:
raise AttributeError(_('no option {0} found').format(opt))
# ____________________________________________________________ # ____________________________________________________________
def impl_set_group_type(self, group_type): def impl_set_group_type(self, group_type):
@ -1800,8 +1531,3 @@ def validate_callback(callback, callback_params, type_):
' not a {0} for second argument' ' not a {0} for second argument'
).format(type_, type( ).format(type_, type(
force_permissive))) force_permissive)))
#FIXME
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()

View File

@ -588,7 +588,7 @@ class Settings(object):
for require in opt.impl_getrequires(): for require in opt.impl_getrequires():
expected = tuple(require.get_expected()) expected = tuple(require.get_expected())
inverse = require.inverse inverse = require.inverse
option = require.get_option(self.context()) option = require.option
reqpath = self._get_path_by_opt(option) reqpath = self._get_path_by_opt(option)
if reqpath == path or reqpath.startswith(path + '.'): if reqpath == path or reqpath.startswith(path + '.'):
raise RequirementError(_("malformed requirements " raise RequirementError(_("malformed requirements "

View File

View File

@ -0,0 +1,284 @@
# -*- 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 tiramisu.setting import multitypes
from sqlalchemy.ext.declarative import declarative_base, declared_attr
from sqlalchemy import create_engine, Column, Integer, String, Boolean, \
PickleType, ForeignKey, Table
from sqlalchemy.orm import relationship, backref
from sqlalchemy.orm import sessionmaker
#FIXME
engine = create_engine('sqlite:///:memory:')
SqlAlchemyBase = declarative_base()
#____________________________________________________________
#
# require
require_table = Table('require', SqlAlchemyBase.metadata,
Column('left_id', Integer, ForeignKey('requireoption.id')),
Column('right_id', Integer, ForeignKey('baseoption.id'))
)
class _RequireExpected(SqlAlchemyBase):
__tablename__ = 'expected'
id = Column(Integer, primary_key=True)
expected = Column(PickleType)
require = Column(Integer, ForeignKey('requireoption.id'))
def __init__(self, expected):
self.expected = expected
class _RequireOption(SqlAlchemyBase):
__tablename__ = 'requireoption'
id = Column(Integer, primary_key=True)
r_opt = Column(Integer)
expected = relationship("_RequireExpected")
action = Column(String, nullable=False)
inverse = Column(Boolean, default=False)
transitive = Column(Boolean, default=True)
same_action = Column(Boolean, default=True)
def __init__(self, option, expected, action, inverse, transitive,
same_action):
self.r_opt = option.id
for expect in expected:
self.expected.append(_RequireExpected(expect))
self.action = action
self.inverse = inverse
self.transitive = transitive
self.same_action = same_action
def get_expected(self):
for expected in self.expected:
yield(expected.expected)
#def get_option(self, config):
# return config.cfgimpl_get_description().impl_get_opt_by_id(self.r_opt)
#____________________________________________________________
#
# properties
property_table = Table('property', SqlAlchemyBase.metadata,
Column('left_id', Integer, ForeignKey('propertyoption.name')),
Column('right_id', Integer, ForeignKey('baseoption.id'))
)
class _PropertyOption(SqlAlchemyBase):
__tablename__ = 'propertyoption'
name = Column(String, primary_key=True)
def __init__(self, name):
self.name = name
#____________________________________________________________
#
# information
class _Information(SqlAlchemyBase):
__tablename__ = 'information'
id = Column(Integer, primary_key=True)
option = Column(Integer, ForeignKey('baseoption.id'))
key = Column(String)
value = Column(PickleType)
def __init__(self, key, value):
self.key = key
self.value = value
#____________________________________________________________
#
# callback
class _CallbackParamOption(SqlAlchemyBase):
__tablename__ = 'callback_param_option'
id = Column(Integer, primary_key=True)
callback_param = Column(Integer, ForeignKey('callback_param.id'))
option = Column(Integer)
force_permissive = Column(Boolean)
value = Column(PickleType)
def __init__(self, option=None, force_permissive=None, value=None):
if value is not None:
self.value = value
else:
self.option = option.id
self.force_permissive = force_permissive
class _CallbackParam(SqlAlchemyBase):
__tablename__ = 'callback_param'
id = Column(Integer, primary_key=True)
callback = Column(Integer, ForeignKey('baseoption.id'))
name = Column(String)
params = relationship('_CallbackParamOption')
def __init__(self, name, params):
self.name = name
for param in params:
if isinstance(param, tuple):
self.params.append(_CallbackParamOption(option=param[0],
force_permissive=param[1]))
else:
self.params.append(_CallbackParamOption(value=param))
#____________________________________________________________
#
# consistency
consistency_table = Table('consistencyopt', SqlAlchemyBase.metadata,
Column('left_id', Integer, ForeignKey('consistency.id')),
Column('right_id', Integer, ForeignKey('baseoption.id'))
)
class _Consistency(SqlAlchemyBase):
__tablename__ = 'consistency'
id = Column(Integer, primary_key=True)
func = Column(PickleType)
def __init__(self, func, all_cons_opts):
self.func = func
for option in all_cons_opts:
option._consistencies.append(self)
#____________________________________________________________
#
# Base
class _Base(SqlAlchemyBase):
__tablename__ = 'baseoption'
id = Column(Integer, primary_key=True)
_name = Column(String)
_informations = relationship('_Information')
_default = Column(PickleType)
_default_multi = Column(PickleType)
_requires = relationship('_RequireOption', secondary=require_table,
backref=backref('option', enable_typechecks=False))
_multi = Column(Boolean)
_multitype = Column(String)
_callback = Column(PickleType)
_callback_params = relationship('_CallbackParam')
_validator = Column(PickleType)
_validator_params = relationship('_CallbackParam')
_parent = Column(Integer, ForeignKey('baseoption.id'))
_children = relationship('BaseOption', enable_typechecks=False)
_properties = relationship('_PropertyOption', secondary=property_table,
backref=backref('options', enable_typechecks=False))
_warnings_only = Column(Boolean)
_readonly = Column(Boolean, default=False)
_consistencies = relationship('_Consistency', secondary=consistency_table,
backref=backref('options', enable_typechecks=False))
_choice_values = Column(PickleType)
_choice_open_values = Column(Boolean)
_type = Column(String(50))
__mapper_args__ = {
'polymorphic_identity': 'option',
'polymorphic_on': _type
}
#FIXME devrait etre une table
_optiondescription_group_type = Column(String)
def __init__(self):
self.commit()
def commit(self):
session.add(self)
session.commit()
def _get_property_object(self, propname):
prop_obj = session.query(_PropertyOption).filter(_PropertyOption.name == propname).first()
if prop_obj is None:
prop_obj = _PropertyOption(propname)
return prop_obj
def _add_require(self, require):
self._requires.append(_RequireOption(*require))
def _add_callback(self, key, values):
self._callback_params.append(_CallbackParam(key, values))
def _add_validator(self, key, values):
self._validator_params.append(_CallbackParam(key, values))
def _add_consistency(self, func, all_cons_opts):
_Consistency(func, all_cons_opts)
# ____________________________________________________________
# information
def impl_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")
"""
info = session.query(_Information).filter_by(option=self.id, key=key).first()
#FIXME pas append ! remplacer !
if info is None:
self._informations.append(_Information(key, value))
else:
info.value = value
def impl_get_information(self, key, default=None):
"""retrieves one information's item
:param key: the item string (ex: "help")
"""
info = session.query(_Information).filter_by(option=self.id, key=key).first()
if info is not None:
return info.value
elif default is not None:
return default
else:
raise ValueError(_("information's item not found: {0}").format(
key))
class StorageOptionDescription(object):
def impl_get_opt_by_path(self, path):
try:
#FIXME
idx = self._cache_paths[1].index(path)
opt_id = self._cache_paths[0][idx]
return session.query(_Base).filter_by(id=opt_id).first()
except ValueError:
raise AttributeError(_('no option for path {0}').format(path))
def impl_get_path_by_opt(self, opt):
try:
return self._cache_paths[1][self._cache_paths[0].index(opt)]
except ValueError:
raise AttributeError(_('no option {0} found').format(opt))
class StorageBase(_Base):
@declared_attr
def __mapper_args__(self):
return {'polymorphic_identity': self.__name__.lower()}
#FIXME
SqlAlchemyBase.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()

View File

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
"default plugin for cache: set it in a simple dictionary" "utils used by storage"
# Copyright (C) 2013 Team tiramisu (see AUTHORS for all contributors) # Copyright (C) 2013 Team tiramisu (see AUTHORS for all contributors)
# #
# This program is free software; you can redistribute it and/or modify # This program is free software; you can redistribute it and/or modify