remove option's storage

This commit is contained in:
Emmanuel Garette 2017-07-22 16:26:06 +02:00
parent 5ca2e32ac5
commit 57a47763d6
10 changed files with 620 additions and 1720 deletions

View File

@ -44,7 +44,7 @@ def test_create_delete_not_persistent():
try: try:
Config(o, session_id='test_persistent', persistent=True) Config(o, session_id='test_persistent', persistent=True)
except ValueError: except ValueError:
raises(ConfigError, "delete_session('option', 'test_persistent')") raises(ValueError, "delete_session('option', 'test_persistent')")
def test_list_sessions_persistent(): def test_list_sessions_persistent():

View File

@ -23,30 +23,29 @@ from types import FunctionType
import warnings import warnings
import sys import sys
from ..i18n import _
from ..setting import log, undefined, debug
from ..autolib import carry_out_calculation
from ..error import (ConfigError, ValueWarning, PropertiesOptionError,
display_list)
if sys.version_info[0] >= 3: # pragma: no cover if sys.version_info[0] >= 3: # pragma: no cover
from inspect import signature from inspect import signature
else: else:
from inspect import getargspec from inspect import getargspec
from ..i18n import _ static_tuple = tuple()
from ..setting import log, undefined, debug, groups
from ..autolib import carry_out_calculation
from ..error import (ConfigError, ValueWarning, PropertiesOptionError,
display_list)
from ..storage import get_storages_option
from . import MasterSlaves
if sys.version_info[0] >= 3: # pragma: no cover if sys.version_info[0] >= 3: # pragma: no cover
xrange = range xrange = range
StorageBase = get_storages_option('base')
submulti = 2 submulti = 2
name_regexp = re.compile(r'^[a-z][a-zA-Z\d_]*$') name_regexp = re.compile(r'^[a-z][a-zA-Z\d_]*$')
forbidden_names = frozenset(['iter_all', 'iter_group', 'find', 'find_first', FORBIDDEN_NAMES = frozenset(['iter_all', 'iter_group', 'find', 'find_first',
'make_dict', 'unwrap_from_path', 'read_only', 'make_dict', 'unwrap_from_path', 'read_only',
'read_write', 'getowner', 'set_contexts']) 'read_write', 'getowner', 'set_contexts'])
allowed_const_list = ['_cons_not_equal'] ALLOWED_CONST_LIST = ['_cons_not_equal']
def valid_name(name): def valid_name(name):
@ -54,7 +53,7 @@ def valid_name(name):
if not isinstance(name, str): if not isinstance(name, str):
return False return False
if re.match(name_regexp, name) is not None and \ if re.match(name_regexp, name) is not None and \
name not in forbidden_names and \ name not in FORBIDDEN_NAMES and \
not name.startswith('impl_') and \ not name.startswith('impl_') and \
not name.startswith('cfgimpl_'): not name.startswith('cfgimpl_'):
return True return True
@ -113,14 +112,40 @@ def validate_callback(callback, callback_params, type_, callbackoption):
# #
class Base(StorageBase): class Base(object):
__slots__ = tuple() __slots__ = ('_name',
'_informations',
'_extra',
'_warnings_only',
'_allow_empty_list',
#multi
'_multi',
'_unique',
#value
'_default',
'_default_multi',
#calcul
'_subdyn',
'_requires',
'_properties',
'_calc_properties',
'_val_call',
#
'_consistencies',
'_master_slaves',
'_choice_values',
'_choice_values_params',
#other
'_has_dependency',
'_dependencies',
'__weakref__'
)
def __init__(self, name, doc, default=None, default_multi=None, def __init__(self, name, doc, default=None, default_multi=None,
requires=None, multi=False, unique=undefined, callback=None, requires=None, multi=False, unique=undefined, callback=None,
callback_params=None, validator=None, validator_params=None, callback_params=None, validator=None, validator_params=None,
properties=None, warnings_only=False, extra=None, properties=None, warnings_only=False, extra=None,
allow_empty_list=undefined, session=None): allow_empty_list=undefined):
if not valid_name(name): if not valid_name(name):
raise ValueError(_("invalid name: {0} for option").format(name)) raise ValueError(_("invalid name: {0} for option").format(name))
if not multi and default_multi is not None: if not multi and default_multi is not None:
@ -159,7 +184,11 @@ class Base(StorageBase):
validator_params = self._build_validator_params(validator, validator_params) validator_params = self._build_validator_params(validator, validator_params)
validate_callback(validator, validator_params, 'validator', self) validate_callback(validator, validator_params, 'validator', self)
self._set_validator(validator, validator_params) if validator_params is None:
val_call = (validator,)
else:
val_call = (validator, validator_params)
self._val_call = (val_call, None)
self._set_has_dependency() self._set_has_dependency()
if calc_properties != frozenset([]) and properties is not tuple(): if calc_properties != frozenset([]) and properties is not tuple():
set_forbidden_properties = calc_properties & set(properties) set_forbidden_properties = calc_properties & set(properties)
@ -167,21 +196,50 @@ class Base(StorageBase):
raise ValueError('conflict: properties already set in ' raise ValueError('conflict: properties already set in '
'requirement {0}'.format( 'requirement {0}'.format(
list(set_forbidden_properties))) list(set_forbidden_properties)))
if session is None: _setattr = object.__setattr__
session = self.getsession() _setattr(self, '_name', name)
StorageBase.__init__(self, name, _multi, warnings_only, doc, extra, if sys.version_info[0] < 3 and isinstance(doc, str):
calc_properties, requires, properties, doc = doc.decode('utf8')
allow_empty_list, unique, session=session) if extra is not None:
_setattr(self, '_extra', extra)
_setattr(self, '_informations', {'doc': doc})
if _multi != 1:
_setattr(self, '_multi', _multi)
if warnings_only is True:
_setattr(self, '_warnings_only', warnings_only)
if calc_properties is not undefined:
_setattr(self, '_calc_properties', calc_properties)
if requires is not undefined:
_setattr(self, '_requires', requires)
if properties is not undefined:
_setattr(self, '_properties', properties)
if multi is not False and default is None: if multi is not False and default is None:
default = [] default = []
if allow_empty_list is not undefined:
_setattr(self, '_allow_empty_list', allow_empty_list)
if unique is not undefined:
_setattr(self, '_unique', unique)
err = self.impl_validate(default, is_multi=is_multi) err = self.impl_validate(default, is_multi=is_multi)
if err: if err:
raise err raise err
self._set_default_values(default, default_multi, is_multi) if (is_multi and default != []) or \
(not is_multi and default is not None):
if is_multi:
default = tuple(default)
_setattr(self, '_default', default)
if is_multi and default_multi is not None:
err = self._validate(default_multi)
if err:
raise ValueError(_("invalid default_multi value {0} "
"for option {1}: {2}").format(
str(default_multi),
self.impl_getname(), str(err)))
_setattr(self, '_default_multi', default_multi)
##callback is False in optiondescription ##callback is False in optiondescription
if callback is not False: if callback is not False:
self.impl_set_callback(callback, callback_params, _init=True) self.impl_set_callback(callback, callback_params, _init=True)
self.commit(session)
def _build_validator_params(self, validator, validator_params): def _build_validator_params(self, validator, validator_params):
if sys.version_info[0] < 3: if sys.version_info[0] < 3:
@ -237,7 +295,12 @@ class Base(StorageBase):
self._validate_callback(callback, callback_params) self._validate_callback(callback, callback_params)
if callback is not None: if callback is not None:
validate_callback(callback, callback_params, 'callback', self) validate_callback(callback, callback_params, 'callback', self)
self._set_callback(callback, callback_params) val = getattr(self, '_val_call', (None,))[0]
if callback_params is None or callback_params == {}:
val_call = (callback,)
else:
val_call = tuple([callback, callback_params])
self._val_call = (val, val_call)
def impl_is_optiondescription(self): def impl_is_optiondescription(self):
return self.__class__.__name__ in ['OptionDescription', return self.__class__.__name__ in ['OptionDescription',
@ -248,6 +311,93 @@ class Base(StorageBase):
return self.__class__.__name__ in ['DynOptionDescription', return self.__class__.__name__ in ['DynOptionDescription',
'SynDynOptionDescription'] 'SynDynOptionDescription']
def impl_getname(self):
return self._name
def impl_is_multi(self):
return getattr(self, '_multi', 1) != 1
def impl_is_readonly(self):
return not isinstance(getattr(self, '_informations', dict()), dict)
def impl_getproperties(self):
return self._properties
def _set_readonly(self, has_extra):
if not self.impl_is_readonly():
_setattr = object.__setattr__
dico = self._informations
keys = tuple(dico.keys())
if len(keys) == 1:
dico = dico['doc']
else:
dico = tuple([keys, tuple(dico.values())])
_setattr(self, '_informations', dico)
if has_extra:
extra = getattr(self, '_extra', None)
if extra is not None:
_setattr(self, '_extra', tuple([tuple(extra.keys()), tuple(extra.values())]))
def _impl_setsubdyn(self, subdyn):
self._subdyn = subdyn
def impl_getrequires(self):
return getattr(self, '_requires', static_tuple)
def impl_get_callback(self):
call = getattr(self, '_val_call', (None, None))[1]
if call is None:
ret_call = (None, {})
elif len(call) == 1:
ret_call = (call[0], {})
else:
ret_call = call
return ret_call
# ____________________________________________________________
# information
def impl_get_information(self, key, default=undefined):
"""retrieves one information's item
:param key: the item string (ex: "help")
"""
def _is_string(infos):
if sys.version_info[0] >= 3: # pragma: no cover
return isinstance(infos, str)
else:
return isinstance(infos, str) or isinstance(infos, unicode)
dico = self._informations
if isinstance(dico, tuple):
if key in dico[0]:
return dico[1][dico[0].index(key)]
elif _is_string(dico):
if key == 'doc':
return dico
elif isinstance(dico, dict):
if key in dico:
return dico[key]
if default is not undefined:
return default
raise ValueError(_("information's item not found: {0}").format(
key))
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")
"""
if self.impl_is_readonly():
raise AttributeError(_("'{0}' ({1}) object attribute '{2}' is"
" read-only").format(
self.__class__.__name__,
self,
#self.impl_getname(),
key))
self._informations[key] = value
class BaseOption(Base): class BaseOption(Base):
"""This abstract base class stands for attribute access """This abstract base class stands for attribute access
@ -429,6 +579,19 @@ class Option(OnlyOption):
else: else:
return err return err
def impl_is_unique(self):
return getattr(self, '_unique', False)
def impl_get_validator(self):
val = getattr(self, '_val_call', (None,))[0]
if val is None:
ret_val = (None, {})
elif len(val) == 1:
ret_val = (val[0], {})
else:
ret_val = val
return ret_val
def impl_validate(self, value, context=undefined, validate=True, def impl_validate(self, value, context=undefined, validate=True,
force_index=None, force_submulti_index=None, force_index=None, force_submulti_index=None,
current_opt=undefined, is_multi=None, current_opt=undefined, is_multi=None,
@ -455,6 +618,7 @@ class Option(OnlyOption):
if display_warnings and setting_properties is undefined and context is not undefined: if display_warnings and setting_properties is undefined and context is not undefined:
setting_properties = context.cfgimpl_get_settings()._getproperties(read_write=False) setting_properties = context.cfgimpl_get_settings()._getproperties(read_write=False)
display_warnings = display_warnings and (setting_properties is undefined or 'warnings' in setting_properties) display_warnings = display_warnings and (setting_properties is undefined or 'warnings' in setting_properties)
def _is_not_unique(value): def _is_not_unique(value):
if display_error and self.impl_is_unique() and len(set(value)) != len(value): if display_error and self.impl_is_unique() and len(set(value)) != len(value):
for idx, val in enumerate(value): for idx, val in enumerate(value):
@ -511,16 +675,17 @@ class Option(OnlyOption):
self.impl_get_display_name()) self.impl_get_display_name())
return ValueError(msg) return ValueError(msg)
error = None error = None
if ((display_error and not self._is_warnings_only()) or is_warnings_only = getattr(self, '_warnings_only', False)
(display_warnings and self._is_warnings_only())): if ((display_error and not is_warnings_only) or
(display_warnings and is_warnings_only)):
error = calculation_validator(_value, _index) error = calculation_validator(_value, _index)
if not error: if not error:
error = self._second_level_validation(_value, self._is_warnings_only()) error = self._second_level_validation(_value, is_warnings_only)
if error: if error:
if debug: # pragma: no cover if debug: # pragma: no cover
log.debug(_('do_validation for {0}: error in value').format( log.debug(_('do_validation for {0}: error in value').format(
self.impl_getname()), exc_info=True) self.impl_getname()), exc_info=True)
if self._is_warnings_only(): if is_warnings_only:
msg = _('attention, "{0}" could be an invalid {1} for "{2}", {3}').format( msg = _('attention, "{0}" could be an invalid {1} for "{2}", {3}').format(
_value, self._display_name, self.impl_get_display_name(), error) _value, self._display_name, self.impl_get_display_name(), error)
warnings.warn_explicit(ValueWarning(msg, self), warnings.warn_explicit(ValueWarning(msg, self),
@ -629,8 +794,7 @@ class Option(OnlyOption):
return False return False
def impl_get_master_slaves(self): def impl_get_master_slaves(self):
masterslaves = self._get_master_slave() return getattr(self, '_master_slaves', None)
return masterslaves
def impl_getdoc(self): def impl_getdoc(self):
"accesses the Option's doc" "accesses the Option's doc"
@ -638,7 +802,7 @@ class Option(OnlyOption):
def _valid_consistencies(self, other_opts, init=True, func=None): def _valid_consistencies(self, other_opts, init=True, func=None):
if self._is_subdyn(): if self._is_subdyn():
dynod = self._impl_getsubdyn() dynod = self._subdyn
else: else:
dynod = None dynod = None
if self.impl_is_submulti(): if self.impl_is_submulti():
@ -653,10 +817,10 @@ class Option(OnlyOption):
if dynod is None: if dynod is None:
raise ConfigError(_('almost one option in consistency is ' raise ConfigError(_('almost one option in consistency is '
'in a dynoptiondescription but not all')) 'in a dynoptiondescription but not all'))
if dynod != opt._impl_getsubdyn(): if dynod != opt._subdyn:
raise ConfigError(_('option in consistency must be in same' raise ConfigError(_('option in consistency must be in same'
' dynoptiondescription')) ' dynoptiondescription'))
dynod = opt._impl_getsubdyn() dynod = opt._subdyn
elif dynod is not None: elif dynod is not None:
raise ConfigError(_('almost one option in consistency is in a ' raise ConfigError(_('almost one option in consistency is in a '
'dynoptiondescription but not all')) 'dynoptiondescription but not all'))
@ -699,7 +863,7 @@ class Option(OnlyOption):
if err: if err:
self._del_consistency() self._del_consistency()
raise err raise err
if func in allowed_const_list: if func in ALLOWED_CONST_LIST:
for opt in all_cons_opts: for opt in all_cons_opts:
if getattr(opt, '_unique', undefined) == undefined: if getattr(opt, '_unique', undefined) == undefined:
opt._unique = True opt._unique = True
@ -779,6 +943,10 @@ class Option(OnlyOption):
def _impl_to_dyn(self, name, path): def _impl_to_dyn(self, name, path):
return DynSymLinkOption(name, self, dyn=path) return DynSymLinkOption(name, self, dyn=path)
def impl_getdefault_multi(self):
"accessing the default value for a multi"
return getattr(self, '_default_multi', None)
def _validate_callback(self, callback, callback_params): def _validate_callback(self, callback, callback_params):
"""callback_params: """callback_params:
* None * None
@ -794,6 +962,52 @@ class Option(OnlyOption):
raise ValueError(_("default value not allowed if option: {0} " raise ValueError(_("default value not allowed if option: {0} "
"is calculated").format(self.impl_getname())) "is calculated").format(self.impl_getname()))
def impl_getdefault(self):
"accessing the default value"
is_multi = self.impl_is_multi()
default = getattr(self, '_default', undefined)
if default is undefined:
if is_multi:
default = []
else:
default = None
else:
if is_multi:
default = list(default)
return default
def _get_extra(self, key):
extra = self._extra
if isinstance(extra, tuple):
return extra[1][extra[0].index(key)]
else:
return extra[key]
def impl_is_submulti(self):
return getattr(self, '_multi', 1) == 2
def impl_allow_empty_list(self):
return getattr(self, '_allow_empty_list', undefined)
#____________________________________________________________
# consistency
def _add_consistency(self, func, all_cons_opts, params):
cons = (func, all_cons_opts, params)
consistencies = getattr(self, '_consistencies', None)
if consistencies is None:
self._consistencies = [cons]
else:
consistencies.append(cons)
def _del_consistency(self):
self._consistencies.pop(-1)
def _get_consistencies(self):
return getattr(self, '_consistencies', static_tuple)
def _has_consistencies(self):
return hasattr(self, '_consistencies')
def validate_requires_arg(new_option, multi, requires, name): def validate_requires_arg(new_option, multi, requires, name):
"""check malformed requirements """check malformed requirements
@ -951,16 +1165,17 @@ class SymLinkOption(OnlyOption):
raise ValueError(_('malformed symlinkoption ' raise ValueError(_('malformed symlinkoption '
'must be an option ' 'must be an option '
'for symlink {0}').format(name)) 'for symlink {0}').format(name))
session = self.getsession() _setattr = object.__setattr__
super(Base, self).__init__(name, undefined, undefined, undefined, _setattr(self, '_name', name)
undefined, undefined, undefined, undefined, _setattr(self, '_opt', opt)
undefined, undefined, opt=opt, session=session)
opt._set_has_dependency() opt._set_has_dependency()
self.commit(session)
def __getattr__(self, name, context=undefined): def __getattr__(self, name, context=undefined):
return getattr(self._impl_getopt(), name) return getattr(self._impl_getopt(), name)
def _impl_getopt(self):
return self._opt
def impl_get_information(self, key, default=undefined): def impl_get_information(self, key, default=undefined):
return self._impl_getopt().impl_get_information(key, default) return self._impl_getopt().impl_get_information(key, default)

View File

@ -22,20 +22,12 @@
from ..i18n import _ from ..i18n import _
from ..setting import log, undefined, debug from ..setting import log, undefined, debug
from ..error import SlaveError, PropertiesOptionError from ..error import SlaveError, PropertiesOptionError
from ..storage import get_storages_option
StorageMasterSlaves = get_storages_option('masterslaves')
class MasterSlaves(object): class MasterSlaves(object):
__slots__ = ('_p_') __slots__ = ('master', 'slaves')
def __init__(self, name, childs=None, validate=True, add=True): def __init__(self, name, childs=None, validate=True, add=True):
if isinstance(name, StorageMasterSlaves): # pragma: no cover
# only for sqlalchemy
self._p_ = name
else:
#if master (same name has group) is set #if master (same name has group) is set
#for collect all slaves #for collect all slaves
slaves = [] slaves = []
@ -61,18 +53,19 @@ class MasterSlaves(object):
raise ValueError(_("callback of master's option shall " raise ValueError(_("callback of master's option shall "
"not refered a slave's ones")) "not refered a slave's ones"))
#everything is ok, store references #everything is ok, store references
self._p_ = StorageMasterSlaves(master, slaves) self.master = master
self.slaves = tuple(slaves)
if add: if add:
for child in childs: for child in childs:
child._set_master_slaves(self) child._master_slaves = self
def is_master(self, opt): def is_master(self, opt):
master = self._p_._sm_getmaster().impl_getname() master = self.master.impl_getname()
return opt.impl_getname() == master or (opt.impl_is_dynsymlinkoption() and return opt.impl_getname() == master or (opt.impl_is_dynsymlinkoption() and
opt._opt.impl_getname() == master) opt._opt.impl_getname() == master)
def getmaster(self, opt): def getmaster(self, opt):
master = self._p_._sm_getmaster() master = self.master
if opt.impl_is_dynsymlinkoption(): if opt.impl_is_dynsymlinkoption():
suffix = opt.impl_getsuffix() suffix = opt.impl_getsuffix()
name = master.impl_getname() + suffix name = master.impl_getname() + suffix
@ -83,21 +76,21 @@ class MasterSlaves(object):
def getslaves(self, opt): def getslaves(self, opt):
if opt.impl_is_dynsymlinkoption(): if opt.impl_is_dynsymlinkoption():
for slave in self._p_._sm_getslaves(): for slave in self.slaves:
suffix = opt.impl_getsuffix() suffix = opt.impl_getsuffix()
name = slave.impl_getname() + suffix name = slave.impl_getname() + suffix
base_path = opt._dyn.split('.')[0] + '.' base_path = opt._dyn.split('.')[0] + '.'
path = base_path + name path = base_path + name
yield slave._impl_to_dyn(name, path) yield slave._impl_to_dyn(name, path)
else: else:
for slave in self._p_._sm_getslaves(): for slave in self.slaves:
yield slave yield slave
def in_same_group(self, opt): def in_same_group(self, opt):
if opt.impl_is_dynsymlinkoption(): if opt.impl_is_dynsymlinkoption():
return opt._opt == self._p_._sm_getmaster() or opt._opt in self._p_._sm_getslaves() return opt._opt == self.master or opt._opt in self.slaves
else: else:
return opt == self._p_._sm_getmaster() or opt in self._p_._sm_getslaves() return opt == self.master or opt in self.slaves
def reset(self, opt, values, setting_properties, _commit=True): def reset(self, opt, values, setting_properties, _commit=True):
for slave in self.getslaves(opt): for slave in self.getslaves(opt):

View File

@ -56,8 +56,9 @@ class ChoiceOption(Option):
if not isinstance(values, tuple): if not isinstance(values, tuple):
raise TypeError(_('values must be a tuple or a function for {0}' raise TypeError(_('values must be a tuple or a function for {0}'
).format(name)) ).format(name))
session = self.getsession() self._choice_values = values
self.impl_set_choice_values_params(values, values_params, session) if values_params is not None:
self._choice_values_params = values_params
super(ChoiceOption, self).__init__(name, doc, default=default, super(ChoiceOption, self).__init__(name, doc, default=default,
default_multi=default_multi, default_multi=default_multi,
callback=callback, callback=callback,
@ -67,9 +68,7 @@ class ChoiceOption(Option):
validator=validator, validator=validator,
validator_params=validator_params, validator_params=validator_params,
properties=properties, properties=properties,
warnings_only=warnings_only, warnings_only=warnings_only)
session=session)
self.commit(session)
def impl_get_values(self, context, current_opt=undefined): def impl_get_values(self, context, current_opt=undefined):
if current_opt is undefined: if current_opt is undefined:
@ -82,7 +81,7 @@ class ChoiceOption(Option):
else: else:
values = carry_out_calculation(current_opt, context=context, values = carry_out_calculation(current_opt, context=context,
callback=values, callback=values,
callback_params=self.impl_get_choice_values_params()) callback_params=getattr(self, '_choice_values_params', {}))
if isinstance(values, Exception): if isinstance(values, Exception):
return values return values
if values is not undefined and not isinstance(values, list): if values is not undefined and not isinstance(values, list):

View File

@ -24,15 +24,12 @@ import re
from ..i18n import _ from ..i18n import _
from ..setting import groups, undefined, owners # , log from ..setting import groups, undefined, owners # , log
from .baseoption import BaseOption, SymLinkOption, Option, allowed_const_list from .baseoption import BaseOption, SymLinkOption, Option, ALLOWED_CONST_LIST
from . import MasterSlaves from . import MasterSlaves
from ..error import ConfigError, ConflictError from ..error import ConfigError, ConflictError
from ..storage import get_storages_option
from ..autolib import carry_out_calculation from ..autolib import carry_out_calculation
StorageOptionDescription = get_storages_option('optiondescription')
name_regexp = re.compile(r'^[a-zA-Z\d\-_]*$') name_regexp = re.compile(r'^[a-zA-Z\d\-_]*$')
import sys import sys
@ -41,61 +38,8 @@ if sys.version_info[0] >= 3: # pragma: no cover
del(sys) del(sys)
class OptionDescription(BaseOption, StorageOptionDescription): class CacheOptionDescription(BaseOption):
"""Config's schema (organisation, group) and container of Options __slots__ = ('_cache_paths', '_cache_consistencies', '_cache_force_store_values')
The `OptionsDescription` objects lives in the `tiramisu.config.Config`.
"""
__slots__ = tuple()
def __init__(self, name, doc, children, requires=None, properties=None):
"""
:param children: a list of options (including optiondescriptions)
"""
super(OptionDescription, self).__init__(name, doc=doc,
requires=requires,
properties=properties,
callback=False)
child_names = []
dynopt_names = []
for child in children:
name = child.impl_getname()
child_names.append(name)
if isinstance(child, DynOptionDescription):
dynopt_names.append(name)
#better performance like this
valid_child = copy(child_names)
valid_child.sort()
old = None
for child in valid_child:
if child == old: # pragma: optional cover
raise ConflictError(_('duplicate option name: '
'{0}').format(child))
if dynopt_names:
for dynopt in dynopt_names:
if child != dynopt and child.startswith(dynopt):
raise ConflictError(_('option must not start as '
'dynoptiondescription'))
old = child
self._add_children(child_names, children)
_setattr = object.__setattr__
_setattr(self, '_cache_consistencies', None)
# the group_type is useful for filtering OptionDescriptions in a config
_setattr(self, '_group_type', groups.default)
def impl_getdoc(self):
return self.impl_get_information('doc')
def impl_validate(self, *args, **kwargs):
"""usefull for OptionDescription"""
pass
def impl_getpaths(self, include_groups=False, _currpath=None):
"""returns a list of all paths in self, recursively
_currpath should not be provided (helps with recursion)
"""
return _impl_getpaths(self, include_groups, _currpath)
def impl_build_cache(self, config, path='', _consistencies=None, def impl_build_cache(self, config, path='', _consistencies=None,
cache_option=None, force_store_values=None): cache_option=None, force_store_values=None):
@ -112,9 +56,7 @@ class OptionDescription(BaseOption, StorageOptionDescription):
else: else:
init = False init = False
for option in self._impl_getchildren(dyn=False): for option in self._impl_getchildren(dyn=False):
#FIXME specifique id for sqlalchemy? cache_option.append(option)
#FIXME avec sqlalchemy ca marche le multi parent ? (dans des configs différentes)
cache_option.append(option._get_id())
if path == '': if path == '':
subpath = option.impl_getname() subpath = option.impl_getname()
else: else:
@ -138,7 +80,7 @@ class OptionDescription(BaseOption, StorageOptionDescription):
force_store_values.append((subpath, option)) force_store_values.append((subpath, option))
for func, all_cons_opts, params in option._get_consistencies(): for func, all_cons_opts, params in option._get_consistencies():
option._valid_consistencies(all_cons_opts[1:], init=False) option._valid_consistencies(all_cons_opts[1:], init=False)
if func not in allowed_const_list and is_multi: if func not in ALLOWED_CONST_LIST and is_multi:
is_masterslaves = option.impl_is_master_slaves() is_masterslaves = option.impl_is_master_slaves()
if not is_masterslaves: if not is_masterslaves:
raise ConfigError(_('malformed consistency option "{0}" ' raise ConfigError(_('malformed consistency option "{0}" '
@ -146,7 +88,7 @@ class OptionDescription(BaseOption, StorageOptionDescription):
option.impl_getname())) option.impl_getname()))
masterslaves = option.impl_get_master_slaves() masterslaves = option.impl_get_master_slaves()
for opt in all_cons_opts: for opt in all_cons_opts:
if func not in allowed_const_list and is_multi: if func not in ALLOWED_CONST_LIST and is_multi:
if not opt.impl_is_master_slaves(): if not opt.impl_is_master_slaves():
raise ConfigError(_('malformed consistency option "{0}" ' raise ConfigError(_('malformed consistency option "{0}" '
'must not be a multi for "{1}"').format( 'must not be a multi for "{1}"').format(
@ -193,7 +135,7 @@ class OptionDescription(BaseOption, StorageOptionDescription):
if _consistencies != {}: if _consistencies != {}:
self._cache_consistencies = {} self._cache_consistencies = {}
for opt, cons in _consistencies.items(): for opt, cons in _consistencies.items():
if opt._get_id() not in cache_option: # pragma: optional cover if opt not in cache_option: # pragma: optional cover
raise ConfigError(_('consistency with option {0} ' raise ConfigError(_('consistency with option {0} '
'which is not in Config').format( 'which is not in Config').format(
opt.impl_getname())) opt.impl_getname()))
@ -201,6 +143,8 @@ class OptionDescription(BaseOption, StorageOptionDescription):
self._cache_force_store_values = force_store_values self._cache_force_store_values = force_store_values
self._set_readonly(False) self._set_readonly(False)
def impl_already_build_caches(self):
return getattr(self, '_cache_paths', None) is not None
def impl_build_force_store_values(self, config, force_store_values): def impl_build_force_store_values(self, config, force_store_values):
session = config._impl_values._p_.getsession() session = config._impl_values._p_.getsession()
@ -226,6 +170,279 @@ class OptionDescription(BaseOption, StorageOptionDescription):
if value_set: if value_set:
config._impl_values._p_.commit() config._impl_values._p_.commit()
def impl_build_cache_option(self, _currpath=None, cache_path=None,
cache_option=None):
if self.impl_is_readonly() or (_currpath is None and getattr(self, '_cache_paths', None) is not None):
# cache already set
return
if _currpath is None:
save = True
_currpath = []
else:
save = False
if cache_path is None:
cache_path = []
cache_option = []
for option in self._impl_getchildren(dyn=False):
attr = option.impl_getname()
path = str('.'.join(_currpath + [attr]))
cache_option.append(option)
cache_path.append(path)
if option.impl_is_optiondescription():
_currpath.append(attr)
option.impl_build_cache_option(_currpath, cache_path,
cache_option)
_currpath.pop()
if save:
_setattr = object.__setattr__
_setattr(self, '_cache_paths', (tuple(cache_option), tuple(cache_path)))
class OptionDescriptionWalk(CacheOptionDescription):
__slots__ = ('_children',)
def impl_get_options_paths(self, bytype, byname, _subpath, only_first, context):
find_results = []
def _rebuild_dynpath(path, suffix, dynopt):
found = False
spath = path.split('.')
for length in xrange(1, len(spath)):
subpath = '.'.join(spath[0:length])
subopt = self.impl_get_opt_by_path(subpath)
if dynopt == subopt:
found = True
break
if not found: # pragma: no cover
raise ConfigError(_('cannot find dynpath'))
subpath = subpath + suffix
for slength in xrange(length, len(spath)):
subpath = subpath + '.' + spath[slength] + suffix
return subpath
def _filter_by_name(path, option):
name = option.impl_getname()
if option._is_subdyn():
if byname.startswith(name):
found = False
for suffix in option._subdyn._impl_get_suffixes(
context):
if byname == name + suffix:
found = True
path = _rebuild_dynpath(path, suffix,
option._subdyn)
option = option._impl_to_dyn(
name + suffix, path)
break
if not found:
return False
else:
if not byname == name:
return False
find_results.append((path, option))
return True
def _filter_by_type(path, option):
if isinstance(option, bytype):
#if byname is not None, check option byname in _filter_by_name
#not here
if byname is None:
if option._is_subdyn():
name = option.impl_getname()
for suffix in option._subdyn._impl_get_suffixes(
context):
spath = _rebuild_dynpath(path, suffix,
option._subdyn)
find_results.append((spath, option._impl_to_dyn(
name + suffix, spath)))
else:
find_results.append((path, option))
return True
return False
def _filter(path, option):
if bytype is not None:
retval = _filter_by_type(path, option)
if byname is None:
return retval
if byname is not None:
return _filter_by_name(path, option)
opts, paths = self._cache_paths
for index in xrange(0, len(paths)):
option = opts[index]
if option.impl_is_optiondescription():
continue
path = paths[index]
if _subpath is not None and not path.startswith(_subpath + '.'):
continue
if bytype == byname is None:
if option._is_subdyn():
name = option.impl_getname()
for suffix in option._subdyn._impl_get_suffixes(
context):
spath = _rebuild_dynpath(path, suffix,
option._subdyn)
find_results.append((spath, option._impl_to_dyn(
name + suffix, spath)))
else:
find_results.append((path, option))
else:
if _filter(path, option) is False:
continue
if only_first:
return find_results
return find_results
def _impl_st_getchildren(self, context, only_dyn=False):
for child in self._children[1]:
if only_dyn is False or child.impl_is_dynoptiondescription():
yield(child)
def _getattr(self, name, suffix=undefined, context=undefined, dyn=True):
error = False
if suffix is not undefined:
if undefined in [suffix, context]: # pragma: no cover
raise ConfigError(_("suffix and context needed if "
"it's a dyn option"))
if name.endswith(suffix):
oname = name[:-len(suffix)]
child = self._children[1][self._children[0].index(oname)]
return self._impl_get_dynchild(child, suffix)
else:
error = True
else:
if name in self._children[0]:
child = self._children[1][self._children[0].index(name)]
if dyn and child.impl_is_dynoptiondescription():
error = True
else:
return child
else:
child = self._impl_search_dynchild(name, context=context)
if child != []:
return child
error = True
if error:
raise AttributeError(_('unknown Option {0} '
'in OptionDescription {1}'
'').format(name, self.impl_getname()))
def impl_getpaths(self, include_groups=False, _currpath=None):
"""returns a list of all paths in self, recursively
_currpath should not be provided (helps with recursion)
"""
return _impl_getpaths(self, include_groups, _currpath)
def impl_get_opt_by_path(self, path):
if getattr(self, '_cache_paths', None) is None:
raise ConfigError(_('use impl_get_opt_by_path only with root OptionDescription'))
if path not in self._cache_paths[1]:
raise AttributeError(_('no option for path {0}').format(path))
return self._cache_paths[0][self._cache_paths[1].index(path)]
def impl_get_path_by_opt(self, opt):
if getattr(self, '_cache_paths', None) is None:
raise ConfigError(_('use impl_get_path_by_opt only with root OptionDescription'))
if opt not in self._cache_paths[0]:
raise AttributeError(_('no option {0} found').format(opt))
return self._cache_paths[1][self._cache_paths[0].index(opt)]
def _impl_getchildren(self, dyn=True, context=undefined):
for child in self._impl_st_getchildren(context):
cname = child.impl_getname()
if dyn and child.impl_is_dynoptiondescription():
path = cname
for value in child._impl_get_suffixes(context):
yield SynDynOptionDescription(child,
cname + value,
path + value, value)
else:
yield child
def impl_getchildren(self):
return list(self._impl_getchildren())
def __getattr__(self, name, context=undefined):
if name.startswith('_'): # or name.startswith('impl_'):
return object.__getattribute__(self, name)
if '.' in name:
path = name.split('.')[0]
subpath = '.'.join(name.split('.')[1:])
return self.__getattr__(path, context=context).__getattr__(subpath, context=context)
return self._getattr(name, context=context)
def _impl_search_dynchild(self, name, context):
ret = []
for child in self._impl_st_getchildren(context, only_dyn=True):
cname = child.impl_getname()
if name.startswith(cname):
path = cname
for value in child._impl_get_suffixes(context):
if name == cname + value:
return SynDynOptionDescription(child, name, path + value, value)
return ret
def _impl_get_dynchild(self, child, suffix):
name = child.impl_getname() + suffix
path = self.impl_getname() + suffix + '.' + name
if isinstance(child, OptionDescription):
return SynDynOptionDescription(child, name, path, suffix)
else:
return child._impl_to_dyn(name, path)
class OptionDescription(OptionDescriptionWalk):
"""Config's schema (organisation, group) and container of Options
The `OptionsDescription` objects lives in the `tiramisu.config.Config`.
"""
__slots__ = ('_group_type',)
def __init__(self, name, doc, children, requires=None, properties=None):
"""
:param children: a list of options (including optiondescriptions)
"""
super(OptionDescription, self).__init__(name, doc=doc,
requires=requires,
properties=properties,
callback=False)
child_names = []
dynopt_names = []
for child in children:
name = child.impl_getname()
child_names.append(name)
if isinstance(child, DynOptionDescription):
dynopt_names.append(name)
#better performance like this
valid_child = copy(child_names)
valid_child.sort()
old = None
for child in valid_child:
if child == old: # pragma: optional cover
raise ConflictError(_('duplicate option name: '
'{0}').format(child))
if dynopt_names:
for dynopt in dynopt_names:
if child != dynopt and child.startswith(dynopt):
raise ConflictError(_('option must not start as '
'dynoptiondescription'))
old = child
_setattr = object.__setattr__
_setattr(self, '_children', (tuple(child_names), tuple(children)))
_setattr(self, '_cache_consistencies', None)
# the group_type is useful for filtering OptionDescriptions in a config
_setattr(self, '_group_type', groups.default)
def impl_getdoc(self):
return self.impl_get_information('doc')
def impl_validate(self, *args, **kwargs):
"""usefull for OptionDescription"""
pass
# ____________________________________________________________ # ____________________________________________________________
def impl_set_group_type(self, group_type): def impl_set_group_type(self, group_type):
"""sets a given group object to an OptionDescription """sets a given group object to an OptionDescription
@ -260,6 +477,9 @@ class OptionDescription(BaseOption, StorageOptionDescription):
raise ValueError(_('group_type: {0}' raise ValueError(_('group_type: {0}'
' not allowed').format(group_type)) ' not allowed').format(group_type))
def impl_get_group_type(self):
return self._group_type
def __getstate__(self): def __getstate__(self):
raise NotImplementedError() raise NotImplementedError()
@ -275,49 +495,6 @@ class OptionDescription(BaseOption, StorageOptionDescription):
raise ValueError(_("invalid suffix: {0} for option").format(val)) raise ValueError(_("invalid suffix: {0} for option").format(val))
return values return values
def _impl_search_dynchild(self, name, context):
ret = []
for child in self._impl_st_getchildren(context, only_dyn=True):
cname = child.impl_getname()
if name.startswith(cname):
path = cname
for value in child._impl_get_suffixes(context):
if name == cname + value:
return SynDynOptionDescription(child, name, path + value, value)
return ret
def _impl_get_dynchild(self, child, suffix):
name = child.impl_getname() + suffix
path = self.impl_getname() + suffix + '.' + name
if isinstance(child, OptionDescription):
return SynDynOptionDescription(child, name, path, suffix)
else:
return child._impl_to_dyn(name, path)
def _impl_getchildren(self, dyn=True, context=undefined):
for child in self._impl_st_getchildren(context):
cname = child.impl_getname()
if dyn and child.impl_is_dynoptiondescription():
path = cname
for value in child._impl_get_suffixes(context):
yield SynDynOptionDescription(child,
cname + value,
path + value, value)
else:
yield child
def impl_getchildren(self):
return list(self._impl_getchildren())
def __getattr__(self, name, context=undefined):
if name.startswith('_'): # or name.startswith('impl_'):
return object.__getattribute__(self, name)
if '.' in name:
path = name.split('.')[0]
subpath = '.'.join(name.split('.')[1:])
return self.__getattr__(path, context=context).__getattr__(subpath, context=context)
return self._getattr(name, context=context)
class DynOptionDescription(OptionDescription): class DynOptionDescription(OptionDescription):
def __init__(self, name, doc, children, requires=None, properties=None, def __init__(self, name, doc, children, requires=None, properties=None,

View File

@ -114,6 +114,7 @@ log = getLogger('tiramisu')
#import logging #import logging
#logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.DEBUG) #logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.DEBUG)
debug = False debug = False
static_set = frozenset()
# ____________________________________________________________ # ____________________________________________________________
@ -261,7 +262,7 @@ class Property(object):
def _append(self, propname, save=True): def _append(self, propname, save=True):
if self._opt is not None and self._opt.impl_getrequires() is not None \ if self._opt is not None and self._opt.impl_getrequires() is not None \
and propname in self._opt.impl_get_calc_properties(): # pragma: optional cover and propname in getattr(self._opt, '_calc_properties', static_set): # pragma: optional cover
raise ValueError(_('cannot append {0} property for option {1}: ' raise ValueError(_('cannot append {0} property for option {1}: '
'this property is calculated').format( 'this property is calculated').format(
propname, self._opt.impl_getname())) propname, self._opt.impl_getname()))

View File

@ -77,8 +77,8 @@ class StorageType(object):
storage_type = StorageType() storage_type = StorageType()
storage_option_type = StorageType() #storage_option_type = StorageType()
storage_option_type.set(DEFAULT_STORAGE) #storage_option_type.set(DEFAULT_STORAGE)
default_validation = StorageType() default_validation = StorageType()
default_validation.set(DEFAULT_STORAGE) default_validation.set(DEFAULT_STORAGE)
@ -109,14 +109,14 @@ def get_storages(context, session_id, persistent):
return properties, permissives, values, session_id return properties, permissives, values, session_id
def get_storages_option(type_): #def get_storages_option(type_):
imp = storage_option_type.get() # imp = storage_option_type.get()
if type_ == 'base': # if type_ == 'base':
return imp.StorageBase # return imp.StorageBase
elif type_ == 'masterslaves': # elif type_ == 'masterslaves':
return imp.StorageMasterSlaves # return imp.StorageMasterSlaves
else: # else:
return imp.StorageOptionDescription # return imp.StorageOptionDescription
def get_default_values_storages(): def get_default_values_storages():
@ -136,9 +136,9 @@ def get_default_settings_storages():
def list_sessions(type_): # pragma: optional cover def list_sessions(type_): # pragma: optional cover
"""List all available session (persistent or not persistent) """List all available session (persistent or not persistent)
""" """
if type_ == 'option': #if type_ == 'option':
return storage_option_type.get().list_sessions() # return storage_option_type.get().list_sessions()
else: #else:
return storage_type.get().list_sessions() return storage_type.get().list_sessions()
@ -149,9 +149,9 @@ def delete_session(type_, session_id): # pragma: optional cover
""" """
storage_module = storage_type.get() storage_module = storage_type.get()
session = storage_module.storage.getsession() session = storage_module.storage.getsession()
if type_ == 'option': #if type_ == 'option':
storage_option_type.get().delete_session(session_id, session) # storage_option_type.get().delete_session(session_id, session)
else: #else:
storage_module.value.delete_session(session_id, session) storage_module.value.delete_session(session_id, session)
storage_module.storage.delete_session(session_id, session) storage_module.storage.delete_session(session_id, session)
if session: if session:

View File

@ -25,7 +25,6 @@ use it. But if something goes wrong, you will lost your modifications.
from .value import Values from .value import Values
from .setting import Properties, Permissives from .setting import Properties, Permissives
from .storage import setting, Storage, list_sessions, delete_session from .storage import setting, Storage, list_sessions, delete_session
from .option import StorageBase, StorageOptionDescription, StorageMasterSlaves
__all__ = ('setting', 'Values', 'Properties', 'Permissives', 'Storage', 'list_sessions', __all__ = ('setting', 'Values', 'Properties', 'Permissives', 'Storage', 'list_sessions',
'delete_session', 'StorageBase', 'StorageOptionDescription', 'StorageMasterSlaves') 'delete_session')

View File

@ -1,503 +0,0 @@
# -*- coding: utf-8 -*-
""
# Copyright (C) 2014-2017 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
#
# ____________________________________________________________
import sys
from ...i18n import _
from ...setting import undefined
from ...error import ConfigError
static_tuple = tuple()
static_set = frozenset()
if sys.version_info[0] >= 3: # pragma: no cover
xrange = range
#____________________________________________________________
#
# Base
#('_name', '_informations', '_multi', '_multitype', '_warnings_only', '_extra', '_readonly', '_subdyn)
class StorageBase(object):
__slots__ = ('_name',
'_informations',
'_extra',
'_warnings_only',
'_allow_empty_list',
#multi
'_multi',
'_unique',
#value
'_default',
'_default_multi',
#calcul
'_subdyn',
'_requires',
'_properties',
'_calc_properties',
'_val_call',
#
'_consistencies',
'_master_slaves',
'_choice_values',
'_choice_values_params',
#other
'_has_dependency',
'_dependencies',
'__weakref__'
)
def __init__(self, name, multi, warnings_only, doc, extra, calc_properties,
requires, properties, allow_empty_list, unique, opt=undefined,
session=None):
_setattr = object.__setattr__
_setattr(self, '_name', name)
if doc is not undefined:
if sys.version_info[0] < 3 and isinstance(doc, str):
doc = doc.decode('utf8')
_setattr(self, '_informations', {'doc': doc})
if multi != 1:
_setattr(self, '_multi', multi)
if extra is not None:
_setattr(self, '_extra', extra)
if warnings_only is True:
_setattr(self, '_warnings_only', warnings_only)
if calc_properties is not undefined:
_setattr(self, '_calc_properties', calc_properties)
if requires is not undefined:
_setattr(self, '_requires', requires)
if properties is not undefined:
_setattr(self, '_properties', properties)
if opt is not undefined:
_setattr(self, '_opt', opt)
if allow_empty_list is not undefined:
_setattr(self, '_allow_empty_list', allow_empty_list)
if unique is not undefined:
setattr(self, '_unique', unique)
def _set_default_values(self, default, default_multi, is_multi):
_setattr = object.__setattr__
if (is_multi and default != []) or \
(not is_multi and default is not None):
if is_multi:
default = tuple(default)
_setattr(self, '_default', default)
if is_multi and default_multi is not None:
err = self._validate(default_multi)
if err:
raise ValueError(_("invalid default_multi value {0} "
"for option {1}: {2}").format(
str(default_multi),
self.impl_getname(), str(err)))
_setattr(self, '_default_multi', default_multi)
# 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")
"""
if self.impl_is_readonly():
raise AttributeError(_("'{0}' ({1}) object attribute '{2}' is"
" read-only").format(
self.__class__.__name__,
self,
#self.impl_getname(),
key))
self._informations[key] = value
def impl_get_information(self, key, default=undefined):
"""retrieves one information's item
:param key: the item string (ex: "help")
"""
dico = self._informations
if isinstance(dico, tuple):
if key in dico[0]:
return dico[1][dico[0].index(key)]
elif self._is_string(dico):
if key == 'doc':
return dico
elif isinstance(dico, dict):
if key in dico:
return dico[key]
if default is not undefined:
return default
raise ValueError(_("information's item not found: {0}").format(
key))
def _add_consistency(self, func, all_cons_opts, params):
cons = (func, all_cons_opts, params)
consistencies = getattr(self, '_consistencies', None)
if consistencies is None:
self._consistencies = [cons]
else:
consistencies.append(cons)
def _del_consistency(self):
self._consistencies.pop(-1)
def _get_consistencies(self):
return getattr(self, '_consistencies', static_tuple)
def _has_consistencies(self):
return hasattr(self, '_consistencies')
def _set_callback(self, callback, callback_params):
val = getattr(self, '_val_call', (None,))[0]
if callback_params is None or callback_params == {}:
val_call = (callback,)
else:
val_call = tuple([callback, callback_params])
self._val_call = (val, val_call)
def impl_set_choice_values_params(self, values, values_params, session):
self._choice_values = values
if values_params is not None:
self._choice_values_params = values_params
def impl_get_callback(self):
call = getattr(self, '_val_call', (None, None))[1]
if call is None:
ret_call = (None, {})
elif len(call) == 1:
ret_call = (call[0], {})
else:
ret_call = call
return ret_call
def impl_get_choice_values_params(self):
return getattr(self, '_choice_values_params', {})
def impl_get_calc_properties(self):
return getattr(self, '_calc_properties', static_set)
def impl_getrequires(self):
return getattr(self, '_requires', static_tuple)
def _set_validator(self, validator, validator_params):
if validator_params is None:
val_call = (validator,)
else:
val_call = (validator, validator_params)
self._val_call = (val_call, None)
def impl_get_validator(self):
val = getattr(self, '_val_call', (None,))[0]
if val is None:
ret_val = (None, {})
elif len(val) == 1:
ret_val = (val[0], {})
else:
ret_val = val
return ret_val
def _get_id(self):
return id(self)
def _impl_getsubdyn(self):
return self._subdyn
def _impl_getopt(self):
return self._opt
def _set_readonly(self, has_extra):
if not self.impl_is_readonly():
_setattr = object.__setattr__
dico = self._informations
keys = tuple(dico.keys())
if len(keys) == 1:
dico = dico['doc']
else:
dico = tuple([keys, tuple(dico.values())])
_setattr(self, '_informations', dico)
if has_extra:
extra = getattr(self, '_extra', None)
if extra is not None:
_setattr(self, '_extra', tuple([tuple(extra.keys()), tuple(extra.values())]))
def impl_getproperties(self):
return self._properties
def _impl_setsubdyn(self, subdyn):
self._subdyn = subdyn
def _is_string(self, infos):
if sys.version_info[0] >= 3: # pragma: no cover
return isinstance(infos, str)
else:
return isinstance(infos, str) or isinstance(infos, unicode)
def impl_is_readonly(self):
return not isinstance(getattr(self, '_informations', dict()), dict)
def impl_getname(self):
return self._name
def impl_is_multi(self):
return getattr(self, '_multi', 1) != 1
def impl_is_submulti(self):
return getattr(self, '_multi', 1) == 2
def impl_allow_empty_list(self):
return getattr(self, '_allow_empty_list', undefined)
def impl_is_unique(self):
return getattr(self, '_unique', False)
def _get_extra(self, key):
extra = self._extra
if isinstance(extra, tuple):
return extra[1][extra[0].index(key)]
else:
return extra[key]
def _is_warnings_only(self):
return getattr(self, '_warnings_only', False)
def impl_getdefault(self):
"accessing the default value"
is_multi = self.impl_is_multi()
default = getattr(self, '_default', undefined)
if default is undefined:
if is_multi:
default = []
else:
default = None
else:
if is_multi:
default = list(default)
return default
def impl_getdefault_multi(self):
"accessing the default value for a multi"
return getattr(self, '_default_multi', None)
def _get_master_slave(self):
return getattr(self, '_master_slaves', None)
def _set_master_slaves(self, option):
self._master_slaves = option
def getsession(self):
pass
def commit(self, session):
pass
class StorageOptionDescription(StorageBase):
__slots__ = ('_children', '_cache_paths', '_cache_consistencies',
'_group_type', '_cache_force_store_values')
def _add_children(self, child_names, children):
_setattr = object.__setattr__
_setattr(self, '_children', (tuple(child_names), tuple(children)))
def impl_already_build_caches(self):
return getattr(self, '_cache_paths', None) is not None
def impl_get_opt_by_path(self, path):
if getattr(self, '_cache_paths', None) is None:
raise ConfigError(_('use impl_get_opt_by_path only with root OptionDescription'))
if path not in self._cache_paths[1]:
raise AttributeError(_('no option for path {0}').format(path))
return self._cache_paths[0][self._cache_paths[1].index(path)]
def impl_get_path_by_opt(self, opt):
if getattr(self, '_cache_paths', None) is None:
raise ConfigError(_('use impl_get_path_by_opt only with root OptionDescription'))
if opt not in self._cache_paths[0]:
raise AttributeError(_('no option {0} found').format(opt))
return self._cache_paths[1][self._cache_paths[0].index(opt)]
def impl_get_group_type(self):
return self._group_type
def impl_build_cache_option(self, _currpath=None, cache_path=None,
cache_option=None):
if self.impl_is_readonly() or (_currpath is None and getattr(self, '_cache_paths', None) is not None):
# cache already set
return
if _currpath is None:
save = True
_currpath = []
else:
save = False
if cache_path is None:
cache_path = []
cache_option = []
for option in self._impl_getchildren(dyn=False):
attr = option.impl_getname()
path = str('.'.join(_currpath + [attr]))
cache_option.append(option)
cache_path.append(path)
if option.impl_is_optiondescription():
_currpath.append(attr)
option.impl_build_cache_option(_currpath, cache_path,
cache_option)
_currpath.pop()
if save:
_setattr = object.__setattr__
_setattr(self, '_cache_paths', (tuple(cache_option), tuple(cache_path)))
def impl_get_options_paths(self, bytype, byname, _subpath, only_first, context):
find_results = []
def _rebuild_dynpath(path, suffix, dynopt):
found = False
spath = path.split('.')
for length in xrange(1, len(spath)):
subpath = '.'.join(spath[0:length])
subopt = self.impl_get_opt_by_path(subpath)
if dynopt == subopt:
found = True
break
if not found: # pragma: no cover
raise ConfigError(_('cannot find dynpath'))
subpath = subpath + suffix
for slength in xrange(length, len(spath)):
subpath = subpath + '.' + spath[slength] + suffix
return subpath
def _filter_by_name(path, option):
name = option.impl_getname()
if option._is_subdyn():
if byname.startswith(name):
found = False
for suffix in option._subdyn._impl_get_suffixes(
context):
if byname == name + suffix:
found = True
path = _rebuild_dynpath(path, suffix,
option._subdyn)
option = option._impl_to_dyn(
name + suffix, path)
break
if not found:
return False
else:
if not byname == name:
return False
find_results.append((path, option))
return True
def _filter_by_type(path, option):
if isinstance(option, bytype):
#if byname is not None, check option byname in _filter_by_name
#not here
if byname is None:
if option._is_subdyn():
name = option.impl_getname()
for suffix in option._subdyn._impl_get_suffixes(
context):
spath = _rebuild_dynpath(path, suffix,
option._subdyn)
find_results.append((spath, option._impl_to_dyn(
name + suffix, spath)))
else:
find_results.append((path, option))
return True
return False
def _filter(path, option):
if bytype is not None:
retval = _filter_by_type(path, option)
if byname is None:
return retval
if byname is not None:
return _filter_by_name(path, option)
opts, paths = self._cache_paths
for index in xrange(0, len(paths)):
option = opts[index]
if option.impl_is_optiondescription():
continue
path = paths[index]
if _subpath is not None and not path.startswith(_subpath + '.'):
continue
if bytype == byname is None:
if option._is_subdyn():
name = option.impl_getname()
for suffix in option._subdyn._impl_get_suffixes(
context):
spath = _rebuild_dynpath(path, suffix,
option._subdyn)
find_results.append((spath, option._impl_to_dyn(
name + suffix, spath)))
else:
find_results.append((path, option))
else:
if _filter(path, option) is False:
continue
if only_first:
return find_results
return find_results
def _impl_st_getchildren(self, context, only_dyn=False):
for child in self._children[1]:
if only_dyn is False or child.impl_is_dynoptiondescription():
yield(child)
def _getattr(self, name, suffix=undefined, context=undefined, dyn=True):
error = False
if suffix is not undefined:
if undefined in [suffix, context]: # pragma: no cover
raise ConfigError(_("suffix and context needed if "
"it's a dyn option"))
if name.endswith(suffix):
oname = name[:-len(suffix)]
child = self._children[1][self._children[0].index(oname)]
return self._impl_get_dynchild(child, suffix)
else:
error = True
else:
if name in self._children[0]:
child = self._children[1][self._children[0].index(name)]
if dyn and child.impl_is_dynoptiondescription():
error = True
else:
return child
else:
child = self._impl_search_dynchild(name, context=context)
if child != []:
return child
error = True
if error:
raise AttributeError(_('unknown Option {0} '
'in OptionDescription {1}'
'').format(name, self.impl_getname()))
class StorageMasterSlaves(object):
__slots__ = ('master', 'slaves')
def __init__(self, master, slaves):
self.master = master
self.slaves = tuple(slaves)
def _sm_getmaster(self):
return self.master
def _sm_getslaves(self):
return self.slaves

View File

@ -1,981 +0,0 @@
# -*- 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.i18n import _
from tiramisu.setting import groups, undefined
from tiramisu.error import ConfigError
from .util import SqlAlchemyBase
import util
from sqlalchemy import not_, or_, and_, inspect
from sqlalchemy.ext.declarative import declared_attr
from sqlalchemy.ext.associationproxy import association_proxy
from sqlalchemy import Column, Integer, String, Boolean, PickleType, \
ForeignKey, Table
from sqlalchemy.orm import relationship, backref
from sqlalchemy.orm.collections import attribute_mapped_collection
from itertools import chain
def load_requires(collection_type, proxy):
def getter(obj):
if obj is None:
return None
ret = []
requires = getattr(obj, proxy.value_attr)
session = util.Session()
for require in requires:
option = session.query(_Base).filter_by(id=require.option).first()
ret.append(tuple([option, require.expected, require.action, require.inverse, require.transitive, require.same_action]))
return tuple(ret)
def setter(obj, value):
setattr(obj, proxy.value_attr, value)
return getter, setter
class _Require(SqlAlchemyBase):
__tablename__ = "require"
id = Column(Integer, primary_key=True)
requires_id = Column(Integer, ForeignKey("baseoption.id"), nullable=False)
requires = relationship('_RequireOption')
def __init__(self, requires):
for require in requires:
self.requires.append(_RequireOption(require))
class _RequireOption(SqlAlchemyBase):
__tablename__ = 'requireoption'
id = Column(Integer, primary_key=True)
require_id = Column(Integer, ForeignKey("require.id"), nullable=False)
option = Column(Integer, nullable=False)
_expected = relationship("_RequireExpected", collection_class=list,
cascade="all, delete-orphan")
expected = association_proxy("_expected", "expected")
#expected = Column(String)
action = Column(String, nullable=False)
inverse = Column(Boolean, default=False)
transitive = Column(Boolean, default=True)
same_action = Column(Boolean, default=True)
def __init__(self, values):
option, expected, action, inverse, transitive, same_action = values
self.option = option.id
self.expected = expected
self.action = action
self.inverse = inverse
self.transitive = transitive
self.same_action = same_action
class _RequireExpected(SqlAlchemyBase):
__tablename__ = 'expected'
id = Column(Integer, primary_key=True)
require = Column(Integer, ForeignKey('requireoption.id'), nullable=False)
expected = Column(PickleType)
def __init__(self, expected):
#FIXME ne pas creer plusieurs fois la meme _expected_
#FIXME pareil avec calc_properties
self.expected = expected
class _CalcProperties(SqlAlchemyBase):
__tablename__ = 'calcproperty'
id = Column(Integer, primary_key=True)
require = Column(Integer, ForeignKey('baseoption.id'), nullable=False)
name = Column(PickleType)
def __init__(self, name):
#FIXME ne pas creer plusieurs fois la meme _expected_
#FIXME pareil avec calc_properties
self.name = name
#____________________________________________________________
#
# properties
class _PropertyOption(SqlAlchemyBase):
__tablename__ = 'propertyoption'
id = Column(Integer, primary_key=True)
option = Column(Integer, ForeignKey('baseoption.id'), nullable=False)
name = Column(String)
def __init__(self, name):
self.name = name
#____________________________________________________________
#
# information
class _Information(SqlAlchemyBase):
__tablename__ = 'information'
id = Column(Integer, primary_key=True)
option = Column(String, ForeignKey('baseoption.id'), nullable=False)
key = Column(String)
value = Column(PickleType)
# def __init__(self, option, key, value):
# self.option = option
# self.key = key
# self.value = value
#____________________________________________________________
#
# callback
def load_callback_parm(collection_type, proxy):
def getter(obj):
if obj is None:
return None
ret = []
requires = getattr(obj, proxy.value_attr)
session = util.Session()
for require in requires:
if require.value is not None:
ret.append(require.value)
else:
option = session.query(_Base).filter_by(id=require.option).first()
ret.append((option, require.force_permissive))
return tuple(ret)
def setter(obj, value):
setattr(obj, proxy.value_attr, value)
return getter, setter
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=undefined, force_permissive=undefined, value=undefined):
if value is not undefined:
self.value = value
elif option is not undefined:
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'))
key = Column(String)
params = relationship('_CallbackParamOption')
def __init__(self, key, params):
self.key = key
for param in params:
if isinstance(param, tuple):
if param == (None,):
self.params.append(_CallbackParamOption())
else:
self.params.append(_CallbackParamOption(option=param[0],
force_permissive=param[1]))
else:
self.params.append(_CallbackParamOption(value=param))
#____________________________________________________________
#
# choice
class _ChoiceParamOption(SqlAlchemyBase):
__tablename__ = 'choice_param_option'
id = Column(Integer, primary_key=True)
choice = Column(Integer, index=True)
option = Column(Integer)
force_permissive = Column(Boolean)
value = Column(PickleType)
def __init__(self, choice, option=undefined, force_permissive=undefined, value=undefined):
self.choice = choice.id
if value is not undefined:
self.value = value
elif option is not undefined:
self.option = option.id
self.force_permissive = force_permissive
class _ChoiceParam(SqlAlchemyBase):
__tablename__ = 'choice_param'
id = Column(Integer, primary_key=True)
option = Column(Integer, index=True)
key = Column(String)
def __init__(self, option, key):
self.option = option.id
self.key = key
#def load_choice_parm(collection_type, proxy):
# def getter(obj):
# if obj is None:
# return None
# ret = []
# requires = getattr(obj, proxy.value_attr)
# session = util.Session()
# for require in requires:
# if require.value is not None:
# ret.append(require.value)
# else:
# option = session.query(_Base).filter_by(id=require.option).first()
# ret.append((option, require.force_permissive))
# return tuple(ret)
#
# def setter(obj, value):
# setattr(obj, proxy.value_attr, value)
# return getter, setter
#
#
#class _ChoiceParamOption(SqlAlchemyBase):
# __tablename__ = 'choice_param_option'
# id = Column(Integer, primary_key=True)
# valid_param = Column(Integer, ForeignKey('choice_param.id'))
# option = Column(Integer)
# force_permissive = Column(Boolean)
# value = Column(PickleType)
#
# def __init__(self, option=undefined, force_permissive=undefined, value=undefined):
# if value is not undefined:
# self.value = value
# elif option is not undefined:
# self.option = option.id
# self.force_permissive = force_permissive
#
#
#class _ChoiceParam(SqlAlchemyBase):
# __tablename__ = 'choice_param'
# id = Column(Integer, primary_key=True)
# choice = Column(Integer, ForeignKey('baseoption.id'))
# key = Column(String)
# params = relationship('_ChoiceParamOption')
#
# def __init__(self, key, params):
# self.key = key
# for param in params:
# if isinstance(param, tuple):
# if param == (None,):
# self.params.append(_ChoiceParamOption())
# else:
# self.params.append(_ChoiceParamOption(option=param[0],
# force_permissive=param[1]))
# else:
# self.params.append(_ChoiceParamOption(value=param))
#____________________________________________________________
#
# validator
def load_validator_parm(collection_type, proxy):
def getter(obj):
if obj is None:
return None
ret = []
requires = getattr(obj, proxy.value_attr)
session = util.Session()
for require in requires:
if require.value is not None:
ret.append(require.value)
else:
option = session.query(_Base).filter_by(id=require.option).first()
ret.append((option, require.force_permissive))
return tuple(ret)
def setter(obj, value):
setattr(obj, proxy.value_attr, value)
return getter, setter
class _ValidatorParamOption(SqlAlchemyBase):
__tablename__ = 'validator_param_option'
id = Column(Integer, primary_key=True)
validator_param = Column(Integer, ForeignKey('validator_param.id'))
option = Column(Integer)
force_permissive = Column(Boolean)
value = Column(PickleType)
def __init__(self, option=undefined, force_permissive=undefined, value=undefined):
if value is not undefined:
self.value = value
elif option is not undefined:
self.option = option.id
self.force_permissive = force_permissive
class _ValidatorParam(SqlAlchemyBase):
__tablename__ = 'validator_param'
id = Column(Integer, primary_key=True)
validator = Column(Integer, ForeignKey('baseoption.id'))
key = Column(String)
params = relationship('_ValidatorParamOption')
def __init__(self, key, params):
self.key = key
for param in params:
if isinstance(param, tuple):
if param == (None,):
self.params.append(_ValidatorParamOption())
else:
self.params.append(_ValidatorParamOption(option=param[0],
force_permissive=param[1]))
else:
self.params.append(_ValidatorParamOption(value=param))
#____________________________________________________________
#
# consistency
consistency_table = Table('consistencyopt', SqlAlchemyBase.metadata,
Column('id', Integer, primary_key=True),
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)
params = Column(PickleType)
def __init__(self, func, all_cons_opts, params):
self.func = func
for option in all_cons_opts[1:]:
option._consistencies.append(self)
self.params = params
class _Parent(SqlAlchemyBase):
__tablename__ = 'parent'
id = Column(Integer, primary_key=True)
child_id = Column(Integer)
child_name = Column(String)
parent_id = Column(Integer)
def __init__(self, parent, child):
self.parent_id = parent.id
self.child_id = child.id
self.child_name = child._name
#____________________________________________________________
#
# Base
class _Base(SqlAlchemyBase):
__tablename__ = 'baseoption'
id = Column(Integer, primary_key=True)
_name = Column(String)
#FIXME not autoload
# _infos = relationship("_Information",
# collection_class=attribute_mapped_collection('key'),
# cascade="all, delete-orphan")
# _informations = association_proxy("_infos", "value")
_informations = relationship("_Information")
_default = Column(PickleType)
_default_multi = Column(PickleType)
_subdyn = Column(Integer)
_dyn = Column(String)
_opt = Column(Integer)
_master_slaves = Column(Integer)
_choice_values = Column(PickleType)
#_cho_params = relationship('_ChoiceParam',
# collection_class=attribute_mapped_collection('key'))
#_choice_values_params = association_proxy("_cho_params", "params",
# getset_factory=load_choice_parm)
_reqs = relationship("_Require", collection_class=list)
_requires = association_proxy("_reqs", "requires", getset_factory=load_requires)
_multi = Column(Integer)
######
_callback = Column(PickleType)
_call_params = relationship('_CallbackParam',
collection_class=attribute_mapped_collection('key'))
_callback_params = association_proxy("_call_params", "params",
getset_factory=load_callback_parm)
_validator = Column(PickleType)
_val_params = relationship('_ValidatorParam',
collection_class=attribute_mapped_collection('key'))
_validator_params = association_proxy("_val_params", "params",
getset_factory=load_validator_parm)
######
#FIXME not autoload
_props = relationship("_PropertyOption", collection_class=set)
_properties = association_proxy("_props", "name")
_calc_props = relationship("_CalcProperties", collection_class=set)
_calc_properties = association_proxy("_calc_props", "name")
_warnings_only = Column(Boolean)
_allow_empty_list = Column(Boolean)
_readonly = Column(Boolean, default=False)
_consistencies = relationship('_Consistency', secondary=consistency_table,
backref=backref('options',
enable_typechecks=False))
_stated = Column(Boolean)
_type = Column(String(50))
__mapper_args__ = {
'polymorphic_identity': 'optionsql',
'polymorphic_on': _type
}
_extra = Column(PickleType)
#FIXME devrait etre une table
_group_type = Column(String)
_is_build_cache = Column(Boolean, default=False)
def __init__(self, name, multi, warnings_only, doc, extra, calc_properties,
requires, properties, allow_empty_list, opt=undefined, session=None):
self._name = name
if multi is not undefined:
self._multi = multi
if warnings_only is not undefined:
self._warnings_only = warnings_only
if allow_empty_list is not undefined:
self._allow_empty_list = allow_empty_list
if doc is not undefined:
self._informations = [_Information(key='doc', value=doc)]
#self._informations = {'doc': doc}
if opt is not undefined:
self._opt = opt.id
if extra is not undefined:
self._extra = extra
if calc_properties is not undefined:
self._calc_properties = calc_properties
if requires is not undefined:
self._requires = requires
if properties is not undefined:
self._properties = properties
session.add(self)
def getsession(self):
return util.Session()
def commit(self, session):
session.commit()
del(session)
def _add_consistency(self, func, all_cons_opts, params):
_Consistency(func, all_cons_opts, params)
def _set_default_values(self, default, default_multi, is_multi):
self._default = default
if self.impl_is_multi() and default_multi is not None:
err = self._validate(default_multi)
if err:
raise err
self._default_multi = default_multi
def _get_consistencies(self):
return [(consistency.func, consistency.options, consistency.params)
for consistency in self._consistencies]
def _get_id(self):
return self.id
def impl_get_callback(self):
a=self.getsession().query(_Base).filter_by(id=self.id).first()
ret = self._callback
if ret is None:
return (None, {})
params = self._callback_params
if params is None:
params = {}
return ret, params
def impl_get_validator(self):
ret = self._validator
if ret is None:
return (None, {})
return ret, self._validator_params
def _impl_getsubdyn(self):
session = self.getsession()
return session.query(_Base).filter_by(id=self._subdyn).first()
def _impl_getopt(self):
session = self.getsession()
return session.query(_Base).filter_by(id=self._opt).first()
def impl_getname(self):
return self._name
def impl_getrequires(self):
session = self.getsession()
requires = session.query(_Require).filter_by(requires_id=self.id).all()
for require in requires:
_ret = []
for req in require.requires:
_ret.append((session.query(_Base).filter_by(id=req.option).first(),
req.expected,
req.action,
req.inverse,
req.transitive,
req.same_action))
yield(_ret)
def impl_getdefault(self):
ret = self._default
if self.impl_is_multi():
if ret is None:
return []
return list(ret)
return ret
def impl_getdefault_multi(self):
if self.impl_is_multi():
return self._default_multi
def _get_extra(self, key):
return self._extra[key]
def _impl_setopt(self, opt):
self._opt = opt.id
def _impl_setsubdyn(self, subdyn):
session = self.getsession()
self._subdyn = subdyn.id
self.commit(session)
def _set_readonly(self, has_extra):
session = self.getsession()
opt = session.query(_Base).filter_by(id=self.id).first()
opt._readonly = True
session.commit()
self._readonly = True
def _set_callback(self, callback, callback_params):
self._callback = callback
if callback_params is not None:
opt._callback_params = callback_params
#session = self.getsession()
#opt = session.query(_Base).filter_by(id=self.id).first()
#opt._callback = callback
#if callback_params is not None:
# opt._callback_params = callback_params
#session.commit()
def impl_set_choice_values_params(self, values, values_params, session):
self._choice_values = values
if values_params is not None:
for key, params in values_params.items():
choice = _ChoiceParam(self, key)
session.add(choice)
session.commit()
for param in params:
if isinstance(param, tuple):
if param == (None,):
session.add(_ChoiceParamOption(choice))
else:
session.add(_ChoiceParamOption(choice, option=param[0], force_permissive=param[1]))
else:
session.add(_ChoiceParamOption(choice, value=param))
session.commit()
def impl_get_choice_values_params(self):
session = self.getsession()
params = {}
for param in session.query(_ChoiceParam).filter_by(option=self.id).all():
_params = []
for _param in session.query(_ChoiceParamOption).filter_by(choice=param.id).all():
if _param.value:
_params.append(_param.value)
elif _param.option:
_params.append((session.query(_Base).filter_by(id=_param.option).first(),
_param.force_permissive))
else:
_params.append((None,))
params[param.key] = _params
return params
def _set_validator(self, validator, validator_params):
self._validator = validator
if validator_params is not None:
self._validator_params = validator_params
def impl_is_readonly(self):
session = self.getsession()
opt = session.query(_Base).filter_by(id=self.id).first()
if opt is None or opt._readonly is None:
return False
return opt._readonly
def impl_is_multi(self):
return self._multi == 0 or self._multi == 2
def impl_is_submulti(self):
return self._multi == 2
def impl_allow_empty_list(self):
try:
return self._allow_empty_list
except AttributeError:
return undefined
def _is_warnings_only(self):
return self._warnings_only
def impl_get_calc_properties(self):
session = self.getsession()
return session.query(_CalcProperties).filter_by(require=self.id).all()
#try:
# return self._calc_properties
#except AttributeError:
# return frozenset()
# information
def impl_set_information(self, key, value):
session = self.getsession()
val = session.query(_Information).filter_by(
option=self.id, key=key).first()
if val is None:
session.add(_Information(self, key, value))
else:
val.value = value
session.commit()
def impl_get_information(self, key, default=undefined):
"""retrieves one information's item
:param key: the item string (ex: "help")
"""
session = self.getsession()
val = session.query(_Information).filter_by(
option=self.id, key=key).first()
if not val:
if default is not undefined:
return default
raise ValueError(_("information's item not found: {0}").format(
key))
return val.value
def _impl_getattributes(self):
slots = set()
mapper = inspect(self)
for column in mapper.attrs:
slots.add(column.key)
return slots
def impl_getproperties(self):
session = self.getsession()
for prop in session.query(_PropertyOption).filter_by(option=self.id).all():
yield prop.name
def _set_master_slaves(self, option):
session = self.getsession()
opt = session.query(_Base).filter_by(id=self.id).first()
opt._master_slaves = option._p_.id
self.commit(session)
def _get_master_slave(self):
session = self.getsession()
return session.query(StorageMasterSlaves).filter_by(id=self._master_slaves).first()
class Cache(SqlAlchemyBase):
__tablename__ = 'cache'
id = Column(Integer, primary_key=True)
path = Column(String, nullable=False, index=True)
descr = Column(Integer, nullable=False, index=True)
parent = Column(Integer, nullable=False, index=True)
option = Column(Integer, nullable=False, index=True)
opt_type = Column(String, nullable=False, index=True)
is_subdyn = Column(Boolean, nullable=False, index=True)
subdyn_path = Column(String)
def __init__(self, descr, parent, option, path, subdyn_path):
#context
self.descr = descr.id
self.parent = parent.id
self.option = option.id
self.path = path
self.opt_type = option.__class__.__name__
if subdyn_path:
self.is_subdyn = True
self.subdyn_path = subdyn_path
else:
self.is_subdyn = False
self.subdyn_path = None
class StorageOptionDescription(object):
def impl_already_build_caches(self):
cache = self._is_build_cache
if cache is None:
cache = False
return cache
def impl_get_opt_by_path(self, path):
session = self.getsession()
ret = session.query(Cache).filter_by(descr=self.id, path=path).first()
if ret is None:
raise AttributeError(_('no option for path {0}').format(path))
return session.query(_Base).filter_by(id=ret.option).first()
def impl_get_path_by_opt(self, opt):
session = self.getsession()
ret = session.query(Cache).filter_by(descr=self.id,
option=opt.id).first()
if ret is None:
ret = session.query(Cache).filter_by(descr=self.id).first()
if ret is None:
raise ConfigError(_('use impl_get_path_by_opt only with root OptionDescription'))
raise AttributeError(_('no option {0} found').format(opt))
return ret.path
def impl_get_group_type(self):
return getattr(groups, self._group_type)
def impl_build_cache_option(self, descr=None, _currpath=None,
subdyn_path=None, session=None):
if self.impl_is_readonly() or (_currpath is None and getattr(self, '_cache_paths', None) is not None):
# cache already set
return
if descr is None:
save = True
descr = self
_currpath = []
session = self.getsession()
else:
save = False
for option in self._impl_getchildren(dyn=False):
attr = option.impl_getname()
if isinstance(option, StorageOptionDescription):
sub = subdyn_path
if option.impl_is_dynoptiondescription():
sub = '.'.join(_currpath)
session.add(Cache(descr, self, option,
str('.'.join(_currpath + [attr])),
sub))
_currpath.append(attr)
option.impl_build_cache_option(descr,
_currpath,
sub, session)
_currpath.pop()
else:
if subdyn_path:
subdyn_path = '.'.join(_currpath)
session.add(Cache(descr, self, option,
str('.'.join(_currpath + [attr])),
subdyn_path))
if save:
self._is_build_cache = True
self.commit(session)
def impl_get_options_paths(self, bytype, byname, _subpath, only_first,
context):
def _build_ret_opt(opt, option, suffix, name):
subdyn_path = opt.subdyn_path
dynpaths = opt.path[len(subdyn_path):].split('.')
path = subdyn_path
dot = False
for dynpath in dynpaths:
if dot:
path += '.'
path += dynpath + suffix
dot = True
_opt = option._impl_to_dyn(name + suffix, path)
return (path, _opt)
session = self.getsession()
sqlquery = session.query(Cache).filter_by(descr=self.id)
if bytype is None:
sqlquery = sqlquery.filter(and_(not_(
Cache.opt_type == 'OptionDescription'),
not_(Cache.opt_type == 'DynOptionDescription')))
else:
sqlquery = sqlquery.filter_by(opt_type=bytype.__name__)
query = ''
or_query = ''
if _subpath is not None:
query += _subpath + '.%'
#if byname is not None:
# or_query = query + byname
# query += '%.' + byname
if query != '':
filter_query = Cache.path.like(query)
if or_query != '':
filter_query = or_(Cache.path == or_query, filter_query)
sqlquery = sqlquery.filter(filter_query)
#if only_first:
# opt = sqlquery.first()
# if opt is None:
# return tuple()
# option = util.session.query(_Base).filter_by(id=opt.option).first()
# return ((opt.path, option),)
#else:
ret = []
for opt in sqlquery.all():
option = session.query(_Base).filter_by(id=opt.option).first()
if opt.is_subdyn:
name = option.impl_getname()
if byname is not None:
if byname.startswith(name):
found = False
dynoption = option._impl_getsubdyn()
for suffix in dynoption._impl_get_suffixes(
context):
if byname == name + suffix:
found = True
break
if not found:
continue
ret_opt = _build_ret_opt(opt, option, suffix, name)
else:
ret_opt = _build_ret_opt(opt, option, suffix, name)
else:
if not only_first:
ret_opt = []
dynoption = option._impl_getsubdyn()
for suffix in dynoption._impl_get_suffixes(context):
val = _build_ret_opt(opt, option, suffix, name)
if only_first:
ret_opt = val
else:
ret_opt.append(val)
else:
if byname is not None and byname != option.impl_getname():
continue
ret_opt = (opt.path, option)
if only_first:
return ret_opt
if isinstance(ret_opt, list):
if ret_opt != []:
ret.extend(ret_opt)
else:
ret.append(ret_opt)
return ret
def _add_children(self, child_names, children):
session = self.getsession()
for child in children:
session.add(_Parent(self, child))
self.commit(session)
def _impl_st_getchildren(self, context, only_dyn=False):
session = self.getsession()
if only_dyn is False or context is undefined:
for child in session.query(_Parent).filter_by(
parent_id=self.id).all():
yield(session.query(_Base).filter_by(id=child.child_id
).first())
else:
descr = context.cfgimpl_get_description().id
for child in session.query(Cache).filter_by(descr=descr,
parent=self.id
).all():
yield(session.query(_Base).filter_by(id=child.option).first())
def _getattr(self, name, suffix=undefined, context=undefined, dyn=True):
error = False
if suffix is not undefined:
try:
if undefined in [suffix, context]: # pragma: optional cover
raise ConfigError(_("suffix and context needed if "
"it's a dyn option"))
if name.endswith(suffix):
session = self.getsession()
oname = name[:-len(suffix)]
#child = self._children[1][self._children[0].index(oname)]
child = session.query(_Parent).filter_by(
parent_id=self.id, child_name=oname).first()
if child is None:
error = True
else:
opt = session.query(_Base).filter_by(
id=child.child_id).first()
return self._impl_get_dynchild(opt, suffix)
else:
error = True
except ValueError: # pragma: optional cover
error = True
else:
session = self.getsession()
child = session.query(_Parent).filter_by(parent_id=self.id,
child_name=name
).first()
if child is None:
child = self._impl_search_dynchild(name, context=context)
if child != []:
return child
error = True
if error is False:
return session.query(_Base).filter_by(id=child.child_id
).first()
if error:
raise AttributeError(_('unknown Option {0} in OptionDescription {1}'
'').format(name, self.impl_getname()))
def _get_force_store_value(self):
#only option in current tree
session = self.getsession()
current_ids = tuple(chain(*session.query(Cache.option).filter_by(
descr=self.id).all()))
for prop in session.query(_PropertyOption).filter(
_PropertyOption.option.in_(current_ids),
_PropertyOption.name == 'force_store_value').all():
opt = session.query(_Base).filter_by(id=prop.option).first()
path = self.impl_get_path_by_opt(opt)
yield (opt, path)
class StorageBase(_Base):
@declared_attr
def __mapper_args__(self):
return {'polymorphic_identity': self.__name__.lower()}
class _Slave(SqlAlchemyBase):
__tablename__ = 'slaves'
id = Column(Integer, primary_key=True)
master_id = Column(Integer, index=True, nullable=False)
slave_id = Column(Integer)
def __init__(self, master, slave):
self.master_id = master.id
self.slave_id = slave.id
class StorageMasterSlaves(SqlAlchemyBase):
__tablename__ = 'masterslaves2'
id = Column(Integer, primary_key=True)
master = Column(Integer)
def __init__(self, master, slaves):
session = util.Session()
self.master = master.id
session.add(self)
session.commit()
for slave in slaves:
sl = _Slave(self, slave)
session.add(sl)
session.commit()
def _sm_getslaves(self):
session = util.Session()
for slave in session.query(_Slave).filter_by(master_id=self.master).all():
yield(session.query(_Base).filter_by(id=slave.slave_id).first())
def _sm_getmaster(self):
session = util.Session()
return session.query(_Base).filter_by(id=self.master).first()