sqlalchemy has a storage
This commit is contained in:
parent
068f68460d
commit
661f844ce6
|
@ -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')
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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()
|
|
||||||
|
|
|
@ -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 "
|
||||||
|
|
|
@ -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()
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue