works on sqlalchemy storage
This commit is contained in:
parent
c75867720f
commit
4217508f3f
12 changed files with 446 additions and 166 deletions
|
@ -7,6 +7,8 @@ from tiramisu.option import BoolOption, IntOption, StrOption, OptionDescription,
|
||||||
import weakref
|
import weakref
|
||||||
|
|
||||||
|
|
||||||
|
IS_DEREFABLE = True
|
||||||
|
|
||||||
def test_deref_storage():
|
def test_deref_storage():
|
||||||
b = BoolOption('b', '')
|
b = BoolOption('b', '')
|
||||||
o = OptionDescription('od', '', [b])
|
o = OptionDescription('od', '', [b])
|
||||||
|
@ -44,16 +46,23 @@ def test_deref_config():
|
||||||
|
|
||||||
|
|
||||||
def test_deref_option():
|
def test_deref_option():
|
||||||
|
global IS_DEREFABLE
|
||||||
b = BoolOption('b', '')
|
b = BoolOption('b', '')
|
||||||
o = OptionDescription('od', '', [b])
|
o = OptionDescription('od', '', [b])
|
||||||
w = weakref.ref(b)
|
w = weakref.ref(b)
|
||||||
del(b)
|
del(b)
|
||||||
assert w() is not None
|
try:
|
||||||
|
assert w() is not None
|
||||||
|
except AssertionError:
|
||||||
|
IS_DEREFABLE = False
|
||||||
|
return
|
||||||
del(o)
|
del(o)
|
||||||
assert w() is None
|
assert w() is None
|
||||||
|
|
||||||
|
|
||||||
def test_deref_optiondescription():
|
def test_deref_optiondescription():
|
||||||
|
if not IS_DEREFABLE:
|
||||||
|
return
|
||||||
b = BoolOption('b', '')
|
b = BoolOption('b', '')
|
||||||
o = OptionDescription('od', '', [b])
|
o = OptionDescription('od', '', [b])
|
||||||
w = weakref.ref(o)
|
w = weakref.ref(o)
|
||||||
|
@ -64,6 +73,8 @@ def test_deref_optiondescription():
|
||||||
|
|
||||||
|
|
||||||
def test_deref_option_cache():
|
def test_deref_option_cache():
|
||||||
|
if not IS_DEREFABLE:
|
||||||
|
return
|
||||||
b = BoolOption('b', '')
|
b = BoolOption('b', '')
|
||||||
o = OptionDescription('od', '', [b])
|
o = OptionDescription('od', '', [b])
|
||||||
o.impl_build_cache_option()
|
o.impl_build_cache_option()
|
||||||
|
@ -86,6 +97,8 @@ def test_deref_optiondescription_cache():
|
||||||
|
|
||||||
|
|
||||||
def test_deref_option_config():
|
def test_deref_option_config():
|
||||||
|
if not IS_DEREFABLE:
|
||||||
|
return
|
||||||
b = BoolOption('b', '')
|
b = BoolOption('b', '')
|
||||||
o = OptionDescription('od', '', [b])
|
o = OptionDescription('od', '', [b])
|
||||||
c = Config(o)
|
c = Config(o)
|
||||||
|
|
|
@ -27,7 +27,7 @@ def return_dynval(suffix, value='val'):
|
||||||
|
|
||||||
|
|
||||||
def return_list2(suffix):
|
def return_list2(suffix):
|
||||||
return [suffix, 'val2']
|
return [str(suffix), 'val2']
|
||||||
|
|
||||||
|
|
||||||
def return_list(val=None):
|
def return_list(val=None):
|
||||||
|
|
|
@ -17,6 +17,7 @@ def test_symlink_option():
|
||||||
descr = OptionDescription("opt", "",
|
descr = OptionDescription("opt", "",
|
||||||
[linkopt, OptionDescription("s1", "", [boolopt])])
|
[linkopt, OptionDescription("s1", "", [boolopt])])
|
||||||
config = Config(descr)
|
config = Config(descr)
|
||||||
|
assert config.s1.b is False
|
||||||
setattr(config, "s1.b", True)
|
setattr(config, "s1.b", True)
|
||||||
setattr(config, "s1.b", False)
|
setattr(config, "s1.b", False)
|
||||||
assert config.s1.b is False
|
assert config.s1.b is False
|
||||||
|
|
|
@ -211,7 +211,7 @@ class SubConfig(object):
|
||||||
elif isinstance(child, SymLinkOption) and \
|
elif isinstance(child, SymLinkOption) and \
|
||||||
not isinstance(child, DynSymLinkOption): # pragma: no dynoptiondescription cover
|
not isinstance(child, DynSymLinkOption): # pragma: no dynoptiondescription cover
|
||||||
path = context.cfgimpl_get_description().impl_get_path_by_opt(
|
path = context.cfgimpl_get_description().impl_get_path_by_opt(
|
||||||
child._opt)
|
child._impl_getopt())
|
||||||
context._setattr(path, value, force_permissive=force_permissive)
|
context._setattr(path, value, force_permissive=force_permissive)
|
||||||
else:
|
else:
|
||||||
subpath = self._get_subpath(name)
|
subpath = self._get_subpath(name)
|
||||||
|
@ -253,7 +253,8 @@ class SubConfig(object):
|
||||||
return homeconfig.getattr(name, force_permissive=force_permissive,
|
return homeconfig.getattr(name, force_permissive=force_permissive,
|
||||||
validate=validate)
|
validate=validate)
|
||||||
context = self._cfgimpl_get_context()
|
context = self._cfgimpl_get_context()
|
||||||
opt_or_descr = self.cfgimpl_get_description().__getattr__(name, context=context)
|
opt_or_descr = self.cfgimpl_get_description().__getattr__(
|
||||||
|
name, context=context)
|
||||||
subpath = self._get_subpath(name)
|
subpath = self._get_subpath(name)
|
||||||
if isinstance(opt_or_descr, DynSymLinkOption):
|
if isinstance(opt_or_descr, DynSymLinkOption):
|
||||||
return self.cfgimpl_get_values()._get_cached_item(
|
return self.cfgimpl_get_values()._get_cached_item(
|
||||||
|
@ -262,7 +263,7 @@ class SubConfig(object):
|
||||||
force_permissive=force_permissive)
|
force_permissive=force_permissive)
|
||||||
elif isinstance(opt_or_descr, SymLinkOption): # pragma: no dynoptiondescription cover
|
elif isinstance(opt_or_descr, SymLinkOption): # pragma: no dynoptiondescription cover
|
||||||
path = context.cfgimpl_get_description().impl_get_path_by_opt(
|
path = context.cfgimpl_get_description().impl_get_path_by_opt(
|
||||||
opt_or_descr._opt)
|
opt_or_descr._impl_getopt())
|
||||||
return context.getattr(path, validate=validate,
|
return context.getattr(path, validate=validate,
|
||||||
force_permissive=force_permissive)
|
force_permissive=force_permissive)
|
||||||
elif opt_or_descr.impl_is_optiondescription():
|
elif opt_or_descr.impl_is_optiondescription():
|
||||||
|
@ -319,6 +320,7 @@ class SubConfig(object):
|
||||||
:param first: return only one option if True, a list otherwise
|
:param first: return only one option if True, a list otherwise
|
||||||
:return: find list or an exception if nothing has been found
|
:return: find list or an exception if nothing has been found
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def _filter_by_value():
|
def _filter_by_value():
|
||||||
if byvalue is undefined:
|
if byvalue is undefined:
|
||||||
return True
|
return True
|
||||||
|
@ -478,7 +480,7 @@ class SubConfig(object):
|
||||||
descr = self.cfgimpl_get_description()
|
descr = self.cfgimpl_get_description()
|
||||||
if not dyn and descr.impl_is_dynoptiondescription():
|
if not dyn and descr.impl_is_dynoptiondescription():
|
||||||
context_descr = self._cfgimpl_get_context().cfgimpl_get_description()
|
context_descr = self._cfgimpl_get_context().cfgimpl_get_description()
|
||||||
return context_descr.impl_get_path_by_opt(descr._opt)
|
return context_descr.impl_get_path_by_opt(descr._impl_getopt())
|
||||||
return self._impl_path
|
return self._impl_path
|
||||||
|
|
||||||
|
|
||||||
|
@ -489,8 +491,8 @@ class _CommonConfig(SubConfig):
|
||||||
def _impl_build_all_caches(self):
|
def _impl_build_all_caches(self):
|
||||||
if not self.cfgimpl_get_description().impl_already_build_caches():
|
if not self.cfgimpl_get_description().impl_already_build_caches():
|
||||||
self.cfgimpl_get_description().impl_build_cache_consistency()
|
self.cfgimpl_get_description().impl_build_cache_consistency()
|
||||||
self.cfgimpl_get_description().impl_validate_options()
|
|
||||||
self.cfgimpl_get_description().impl_build_cache_option()
|
self.cfgimpl_get_description().impl_build_cache_option()
|
||||||
|
self.cfgimpl_get_description().impl_validate_options()
|
||||||
|
|
||||||
def read_only(self):
|
def read_only(self):
|
||||||
"read only is a global config's setting, see `settings.py`"
|
"read only is a global config's setting, see `settings.py`"
|
||||||
|
@ -504,7 +506,9 @@ class _CommonConfig(SubConfig):
|
||||||
"""convenience method to retrieve an option's owner
|
"""convenience method to retrieve an option's owner
|
||||||
from the config itself
|
from the config itself
|
||||||
"""
|
"""
|
||||||
if not isinstance(opt, Option) and not isinstance(opt, SymLinkOption): # pragma: optional cover
|
if not isinstance(opt, Option) and \
|
||||||
|
not isinstance(opt, SymLinkOption) and \
|
||||||
|
not isinstance(opt, DynSymLinkOption): # pragma: optional cover
|
||||||
raise TypeError(_('opt in getowner must be an option not {0}'
|
raise TypeError(_('opt in getowner must be an option not {0}'
|
||||||
'').format(type(opt)))
|
'').format(type(opt)))
|
||||||
return self.cfgimpl_get_values().getowner(opt,
|
return self.cfgimpl_get_values().getowner(opt,
|
||||||
|
|
|
@ -103,11 +103,11 @@ class Base(StorageBase):
|
||||||
if not valid_name(name): # pragma: optional cover
|
if not valid_name(name): # pragma: optional cover
|
||||||
raise ValueError(_("invalid name: {0} for option").format(name))
|
raise ValueError(_("invalid name: {0} for option").format(name))
|
||||||
if requires is not None:
|
if requires is not None:
|
||||||
self._calc_properties, self._requires = validate_requires_arg(
|
calc_properties, requires = validate_requires_arg(
|
||||||
requires, name)
|
requires, name)
|
||||||
#else:
|
else:
|
||||||
# self._calc_properties = frozenset()
|
calc_properties = frozenset()
|
||||||
# self._requires = []
|
requires = undefined
|
||||||
if not multi and default_multi is not None: # pragma: optional cover
|
if not multi and default_multi is not None: # pragma: optional cover
|
||||||
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))
|
||||||
|
@ -127,17 +127,18 @@ class Base(StorageBase):
|
||||||
if validator is not None:
|
if validator is not None:
|
||||||
validate_callback(validator, validator_params, 'validator')
|
validate_callback(validator, validator_params, 'validator')
|
||||||
self._set_validator(validator, validator_params)
|
self._set_validator(validator, validator_params)
|
||||||
if self.impl_get_calc_properties() != frozenset([]) and properties is not tuple(): # pragma: optional cover
|
if calc_properties != frozenset([]) and properties is not tuple(): # pragma: optional cover
|
||||||
set_forbidden_properties = self.impl_get_calc_properties() & set(properties)
|
set_forbidden_properties = calc_properties & set(properties)
|
||||||
if set_forbidden_properties != frozenset():
|
if set_forbidden_properties != frozenset():
|
||||||
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)))
|
||||||
super(Base, self).__init__(name, _multi, warnings_only, doc, extra)
|
StorageBase.__init__(self, name, _multi, warnings_only, doc, extra,
|
||||||
|
calc_properties, requires, properties)
|
||||||
self._set_default_values(default, default_multi)
|
self._set_default_values(default, default_multi)
|
||||||
if callback is not False:
|
if callback is not False:
|
||||||
self.impl_set_callback(callback, callback_params)
|
self.impl_set_callback(callback, callback_params)
|
||||||
self._properties = properties
|
self.commit()
|
||||||
|
|
||||||
def impl_set_callback(self, callback, callback_params=None):
|
def impl_set_callback(self, callback, callback_params=None):
|
||||||
if callback is None and callback_params is not None: # pragma: optional cover
|
if callback is None and callback_params is not None: # pragma: optional cover
|
||||||
|
@ -275,12 +276,12 @@ class BaseOption(Base):
|
||||||
except AttributeError: # pragma: optional cover
|
except AttributeError: # pragma: optional cover
|
||||||
raise SystemError(_('cannot serialize Option, '
|
raise SystemError(_('cannot serialize Option, '
|
||||||
'only in OptionDescription'))
|
'only in OptionDescription'))
|
||||||
slots = set()
|
if isinstance(self, SymLinkOption):
|
||||||
for subclass in self.__class__.__mro__:
|
slots = frozenset(['_name', '_state_opt', '_stated'])
|
||||||
if subclass is not object:
|
else:
|
||||||
slots.update(subclass.__slots__)
|
slots = self._impl_getattributes()
|
||||||
slots -= frozenset(['_cache_paths', '_cache_consistencies',
|
slots -= frozenset(['_cache_paths', '_cache_consistencies',
|
||||||
'__weakref__'])
|
'__weakref__'])
|
||||||
states = {}
|
states = {}
|
||||||
for slot in slots:
|
for slot in slots:
|
||||||
# remove variable if save variable converted
|
# remove variable if save variable converted
|
||||||
|
@ -338,9 +339,10 @@ class BaseOption(Base):
|
||||||
"""
|
"""
|
||||||
if name not in ('_option', '_is_build_cache') \
|
if name not in ('_option', '_is_build_cache') \
|
||||||
and not isinstance(value, tuple) and \
|
and not isinstance(value, tuple) and \
|
||||||
not name.startswith('_state'):
|
not name.startswith('_state') and \
|
||||||
|
not name == '_sa_instance_state':
|
||||||
is_readonly = False
|
is_readonly = False
|
||||||
# never change _name
|
# never change _name dans _opt
|
||||||
if name == '_name':
|
if name == '_name':
|
||||||
try:
|
try:
|
||||||
if self.impl_getname() is not None:
|
if self.impl_getname() is not None:
|
||||||
|
@ -348,13 +350,21 @@ class BaseOption(Base):
|
||||||
is_readonly = True
|
is_readonly = True
|
||||||
except (KeyError, AttributeError):
|
except (KeyError, AttributeError):
|
||||||
pass
|
pass
|
||||||
|
elif name == '_opt':
|
||||||
|
try:
|
||||||
|
if self._impl_getopt() is not None:
|
||||||
|
#so _opt is already set
|
||||||
|
is_readonly = True
|
||||||
|
except (KeyError, AttributeError):
|
||||||
|
pass
|
||||||
elif name != '_readonly':
|
elif name != '_readonly':
|
||||||
is_readonly = self.impl_is_readonly()
|
is_readonly = self.impl_is_readonly()
|
||||||
if is_readonly: # pragma: optional cover
|
if is_readonly: # pragma: optional cover
|
||||||
raise AttributeError(_("'{0}' ({1}) object attribute '{2}' is"
|
raise AttributeError(_("'{0}' ({1}) object attribute '{2}' is"
|
||||||
" read-only").format(
|
" read-only").format(
|
||||||
self.__class__.__name__,
|
self.__class__.__name__,
|
||||||
self.impl_getname(),
|
self,
|
||||||
|
#self.impl_getname(),
|
||||||
name))
|
name))
|
||||||
super(BaseOption, self).__setattr__(name, value)
|
super(BaseOption, self).__setattr__(name, value)
|
||||||
|
|
||||||
|
@ -844,29 +854,31 @@ def validate_requires_arg(requires, name):
|
||||||
|
|
||||||
|
|
||||||
class SymLinkOption(OnlyOption):
|
class SymLinkOption(OnlyOption):
|
||||||
__slots__ = ('_opt', '_state_opt', '_readonly')
|
# __slots__ = ('_opt', '_state_opt')
|
||||||
|
|
||||||
def __init__(self, name, opt):
|
def __init__(self, name, opt):
|
||||||
if not isinstance(opt, Option): # pragma: optional cover
|
if not isinstance(opt, Option): # pragma: optional cover
|
||||||
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))
|
||||||
self._opt = opt
|
super(Base, self).__init__(name, undefined, undefined, undefined,
|
||||||
self._set_readonly()
|
undefined, undefined, undefined, undefined,
|
||||||
super(Base, self).__init__(name, undefined, undefined, undefined, undefined)
|
opt)
|
||||||
|
self.commit()
|
||||||
|
|
||||||
def __getattr__(self, name, context=undefined):
|
def __getattr__(self, name, context=undefined):
|
||||||
if name in ('_opt', '_opt_type', '_readonly', 'impl_getpath', '_name', '_state_opt'):
|
if name in ('_opt', '_opt_type', '_readonly', 'impl_getpath', '_name',
|
||||||
|
'_state_opt', '_impl_setopt'):
|
||||||
return object.__getattr__(self, name)
|
return object.__getattr__(self, name)
|
||||||
else:
|
else:
|
||||||
return getattr(self._opt, name)
|
return getattr(self._impl_getopt(), name)
|
||||||
|
|
||||||
def _impl_getstate(self, descr):
|
def _impl_getstate(self, descr):
|
||||||
self._stated = True
|
self._stated = True
|
||||||
self._state_opt = descr.impl_get_path_by_opt(self._opt)
|
self._state_opt = descr.impl_get_path_by_opt(self._impl_getopt())
|
||||||
|
|
||||||
def _impl_setstate(self, descr):
|
def _impl_setstate(self, descr):
|
||||||
self._opt = descr.impl_get_opt_by_path(self._state_opt)
|
self._impl_setopt(descr.impl_get_opt_by_path(self._state_opt))
|
||||||
del(self._state_opt)
|
del(self._state_opt)
|
||||||
try:
|
try:
|
||||||
del(self._stated)
|
del(self._stated)
|
||||||
|
@ -875,46 +887,56 @@ class SymLinkOption(OnlyOption):
|
||||||
self._set_readonly()
|
self._set_readonly()
|
||||||
|
|
||||||
def impl_get_information(self, key, default=undefined):
|
def impl_get_information(self, key, default=undefined):
|
||||||
return self._opt.impl_get_information(key, default)
|
return self._impl_getopt().impl_get_information(key, default)
|
||||||
|
|
||||||
def _set_readonly(self):
|
|
||||||
self._readonly = True
|
|
||||||
|
|
||||||
def impl_is_readonly(self):
|
def impl_is_readonly(self):
|
||||||
try:
|
return True
|
||||||
return self._readonly
|
|
||||||
except AttributeError:
|
|
||||||
return False
|
|
||||||
|
|
||||||
def impl_getproperties(self):
|
def impl_getproperties(self):
|
||||||
return self._opt._properties
|
return self._impl_getopt()._properties
|
||||||
|
|
||||||
def impl_get_callback(self):
|
def impl_get_callback(self):
|
||||||
return self._opt.impl_get_callback()
|
return self._impl_getopt().impl_get_callback()
|
||||||
|
|
||||||
def impl_has_callback(self):
|
def impl_has_callback(self):
|
||||||
"to know if a callback has been defined or not"
|
"to know if a callback has been defined or not"
|
||||||
return self._opt.impl_has_callback()
|
return self._impl_getopt().impl_has_callback()
|
||||||
|
|
||||||
|
def impl_is_multi(self):
|
||||||
|
return self._impl_getopt().impl_is_multi()
|
||||||
|
|
||||||
def _is_subdyn(self):
|
def _is_subdyn(self):
|
||||||
try:
|
try:
|
||||||
return self._opt._subdyn is not None
|
return self._impl_getopt()._subdyn is not None
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
class DynSymLinkOption(SymLinkOption):
|
class DynSymLinkOption(object):
|
||||||
__slots__ = ('_dyn',)
|
__slots__ = ('_dyn', '_opt', '_name')
|
||||||
|
|
||||||
def __init__(self, name, opt, dyn):
|
def __init__(self, name, opt, dyn):
|
||||||
|
self._name = name
|
||||||
self._dyn = dyn
|
self._dyn = dyn
|
||||||
super(DynSymLinkOption, self).__init__(name, opt)
|
self._opt = opt
|
||||||
|
|
||||||
|
def __getattr__(self, name, context=undefined):
|
||||||
|
if name in ('_opt', '_opt_type', '_readonly', 'impl_getpath', '_name', '_state_opt'):
|
||||||
|
return object.__getattr__(self, name)
|
||||||
|
else:
|
||||||
|
return getattr(self._impl_getopt(), name)
|
||||||
|
|
||||||
|
def impl_getname(self):
|
||||||
|
return self._name
|
||||||
|
|
||||||
|
def _impl_getopt(self):
|
||||||
|
return self._opt
|
||||||
|
|
||||||
def impl_getsuffix(self):
|
def impl_getsuffix(self):
|
||||||
return self._dyn.split('.')[-1][len(self._opt.impl_getname()):]
|
return self._dyn.split('.')[-1][len(self._impl_getopt().impl_getname()):]
|
||||||
|
|
||||||
def impl_getpath(self, context):
|
def impl_getpath(self, context):
|
||||||
path = self._opt.impl_getpath(context)
|
path = self._impl_getopt().impl_getpath(context)
|
||||||
base_path = '.'.join(path.split('.')[:-2])
|
base_path = '.'.join(path.split('.')[:-2])
|
||||||
if self.impl_is_master_slaves() and base_path is not '':
|
if self.impl_is_master_slaves() and base_path is not '':
|
||||||
base_path = base_path + self.impl_getsuffix()
|
base_path = base_path + self.impl_getsuffix()
|
||||||
|
@ -925,5 +947,7 @@ class DynSymLinkOption(SymLinkOption):
|
||||||
|
|
||||||
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):
|
||||||
return self._opt.impl_validate(value, context, validate, force_index,
|
return self._impl_getopt().impl_validate(value, context, validate,
|
||||||
force_submulti_index, current_opt=self)
|
force_index,
|
||||||
|
force_submulti_index,
|
||||||
|
current_opt=self)
|
||||||
|
|
|
@ -168,7 +168,7 @@ class OptionDescription(BaseOption, StorageOptionDescription):
|
||||||
return True
|
return True
|
||||||
#consistencies is something like [('_cons_not_equal', (opt1, opt2))]
|
#consistencies is something like [('_cons_not_equal', (opt1, opt2))]
|
||||||
if isinstance(option, DynSymLinkOption):
|
if isinstance(option, DynSymLinkOption):
|
||||||
consistencies = self._cache_consistencies.get(option._opt)
|
consistencies = self._cache_consistencies.get(option._impl_getopt())
|
||||||
else:
|
else:
|
||||||
consistencies = self._cache_consistencies.get(option)
|
consistencies = self._cache_consistencies.get(option)
|
||||||
if consistencies is not None:
|
if consistencies is not None:
|
||||||
|
@ -177,7 +177,7 @@ class OptionDescription(BaseOption, StorageOptionDescription):
|
||||||
#all_cons_opts[0] is the option where func is set
|
#all_cons_opts[0] is the option where func is set
|
||||||
if isinstance(option, DynSymLinkOption):
|
if isinstance(option, DynSymLinkOption):
|
||||||
subpath = '.'.join(option._dyn.split('.')[:-1])
|
subpath = '.'.join(option._dyn.split('.')[:-1])
|
||||||
namelen = len(option._opt.impl_getname())
|
namelen = len(option._impl_getopt().impl_getname())
|
||||||
suffix = option.impl_getname()[namelen:]
|
suffix = option.impl_getname()[namelen:]
|
||||||
opts = []
|
opts = []
|
||||||
for opt in all_cons_opts:
|
for opt in all_cons_opts:
|
||||||
|
@ -361,6 +361,9 @@ class SynDynOptionDescription(object):
|
||||||
def impl_getpaths(self, include_groups=False, _currpath=None):
|
def impl_getpaths(self, include_groups=False, _currpath=None):
|
||||||
return _impl_getpaths(self, include_groups, _currpath)
|
return _impl_getpaths(self, include_groups, _currpath)
|
||||||
|
|
||||||
|
def _impl_getopt(self):
|
||||||
|
return self._opt
|
||||||
|
|
||||||
|
|
||||||
def _impl_getpaths(klass, include_groups, _currpath):
|
def _impl_getpaths(klass, include_groups, _currpath):
|
||||||
"""returns a list of all paths in klass, recursively
|
"""returns a list of all paths in klass, recursively
|
||||||
|
|
|
@ -61,7 +61,8 @@ class StorageBase(object):
|
||||||
'__weakref__'
|
'__weakref__'
|
||||||
)
|
)
|
||||||
|
|
||||||
def __init__(self, name, multi, warnings_only, doc, extra):
|
def __init__(self, name, multi, warnings_only, doc, extra, calc_properties,
|
||||||
|
requires, properties, opt=undefined):
|
||||||
self._name = name
|
self._name = name
|
||||||
if doc is not undefined:
|
if doc is not undefined:
|
||||||
self._informations = {'doc': doc}
|
self._informations = {'doc': doc}
|
||||||
|
@ -72,6 +73,15 @@ class StorageBase(object):
|
||||||
if warnings_only is True:
|
if warnings_only is True:
|
||||||
self._warnings_only = warnings_only
|
self._warnings_only = warnings_only
|
||||||
|
|
||||||
|
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
|
||||||
|
if opt is not undefined:
|
||||||
|
self._opt = opt
|
||||||
|
|
||||||
def _set_default_values(self, default, default_multi):
|
def _set_default_values(self, default, default_multi):
|
||||||
if self.impl_is_multi() and default is None:
|
if self.impl_is_multi() and default is None:
|
||||||
default = []
|
default = []
|
||||||
|
@ -214,6 +224,9 @@ class StorageBase(object):
|
||||||
def _impl_getsubdyn(self):
|
def _impl_getsubdyn(self):
|
||||||
return self._subdyn
|
return self._subdyn
|
||||||
|
|
||||||
|
def _impl_getopt(self):
|
||||||
|
return self._opt
|
||||||
|
|
||||||
def _set_readonly(self):
|
def _set_readonly(self):
|
||||||
if not self.impl_is_readonly():
|
if not self.impl_is_readonly():
|
||||||
dico = self._informations
|
dico = self._informations
|
||||||
|
@ -233,6 +246,9 @@ class StorageBase(object):
|
||||||
def _impl_setsubdyn(self, subdyn):
|
def _impl_setsubdyn(self, subdyn):
|
||||||
self._subdyn = subdyn
|
self._subdyn = subdyn
|
||||||
|
|
||||||
|
def _impl_setopt(self, opt):
|
||||||
|
self._opt = opt
|
||||||
|
|
||||||
def _impl_convert_informations(self, descr, load=False):
|
def _impl_convert_informations(self, descr, load=False):
|
||||||
if not load:
|
if not load:
|
||||||
infos = self._informations
|
infos = self._informations
|
||||||
|
@ -255,6 +271,13 @@ class StorageBase(object):
|
||||||
self._set_readonly()
|
self._set_readonly()
|
||||||
del(self._state_readonly)
|
del(self._state_readonly)
|
||||||
|
|
||||||
|
def _impl_getattributes(self):
|
||||||
|
slots = set()
|
||||||
|
for subclass in self.__class__.__mro__:
|
||||||
|
if subclass is not object:
|
||||||
|
slots.update(subclass.__slots__)
|
||||||
|
return slots
|
||||||
|
|
||||||
def impl_is_readonly(self):
|
def impl_is_readonly(self):
|
||||||
try:
|
try:
|
||||||
return not isinstance(self._informations, dict)
|
return not isinstance(self._informations, dict)
|
||||||
|
@ -320,7 +343,10 @@ class StorageOptionDescription(StorageBase):
|
||||||
'_group_type', '_is_build_cache', '_state_group_type')
|
'_group_type', '_is_build_cache', '_state_group_type')
|
||||||
|
|
||||||
def __init__(self, name, multi, warnings_only, doc, extra):
|
def __init__(self, name, multi, warnings_only, doc, extra):
|
||||||
super(StorageOptionDescription, self).__init__(name, multi, warnings_only, doc, None)
|
super(StorageOptionDescription, self).__init__(name, multi,
|
||||||
|
warnings_only, doc,
|
||||||
|
None, undefined,
|
||||||
|
undefined, undefined)
|
||||||
self._cache_paths = None
|
self._cache_paths = None
|
||||||
|
|
||||||
def _add_children(self, child_names, children):
|
def _add_children(self, child_names, children):
|
||||||
|
|
|
@ -23,7 +23,7 @@ from tiramisu.error import ConfigError
|
||||||
from .util import SqlAlchemyBase
|
from .util import SqlAlchemyBase
|
||||||
import util
|
import util
|
||||||
|
|
||||||
from sqlalchemy import not_, or_
|
from sqlalchemy import not_, or_, and_, inspect
|
||||||
from sqlalchemy.ext.declarative import declared_attr
|
from sqlalchemy.ext.declarative import declared_attr
|
||||||
from sqlalchemy.ext.associationproxy import association_proxy
|
from sqlalchemy.ext.associationproxy import association_proxy
|
||||||
from sqlalchemy import Column, Integer, String, Boolean, PickleType, \
|
from sqlalchemy import Column, Integer, String, Boolean, PickleType, \
|
||||||
|
@ -199,6 +199,7 @@ class _CallbackParam(SqlAlchemyBase):
|
||||||
#
|
#
|
||||||
# consistency
|
# consistency
|
||||||
consistency_table = Table('consistencyopt', SqlAlchemyBase.metadata,
|
consistency_table = Table('consistencyopt', SqlAlchemyBase.metadata,
|
||||||
|
Column('id', Integer, primary_key=True),
|
||||||
Column('left_id', Integer, ForeignKey('consistency.id')),
|
Column('left_id', Integer, ForeignKey('consistency.id')),
|
||||||
Column('right_id', Integer, ForeignKey('baseoption.id'))
|
Column('right_id', Integer, ForeignKey('baseoption.id'))
|
||||||
)
|
)
|
||||||
|
@ -214,6 +215,7 @@ class _Consistency(SqlAlchemyBase):
|
||||||
self.func = func
|
self.func = func
|
||||||
for option in all_cons_opts:
|
for option in all_cons_opts:
|
||||||
option._consistencies.append(self)
|
option._consistencies.append(self)
|
||||||
|
print type(option._consistencies)
|
||||||
self.params = params
|
self.params = params
|
||||||
|
|
||||||
|
|
||||||
|
@ -245,6 +247,8 @@ class _Base(SqlAlchemyBase):
|
||||||
_default = Column(PickleType)
|
_default = Column(PickleType)
|
||||||
_default_multi = Column(PickleType)
|
_default_multi = Column(PickleType)
|
||||||
_subdyn = Column(Integer)
|
_subdyn = Column(Integer)
|
||||||
|
_dyn = Column(String)
|
||||||
|
_opt = Column(Integer)
|
||||||
_choice_values = Column(PickleType)
|
_choice_values = Column(PickleType)
|
||||||
_cho_params = relationship('_CallbackParam',
|
_cho_params = relationship('_CallbackParam',
|
||||||
collection_class=
|
collection_class=
|
||||||
|
@ -268,19 +272,18 @@ class _Base(SqlAlchemyBase):
|
||||||
_validator_params = association_proxy("_val_params", "params",
|
_validator_params = association_proxy("_val_params", "params",
|
||||||
getset_factory=load_callback_parm)
|
getset_factory=load_callback_parm)
|
||||||
######
|
######
|
||||||
#FIXME pas 2 fois la meme properties dans la base ...
|
|
||||||
#FIXME not autoload
|
#FIXME not autoload
|
||||||
#FIXME normalement tuple ... transforme en set !
|
|
||||||
_props = relationship("_PropertyOption", collection_class=set)
|
_props = relationship("_PropertyOption", collection_class=set)
|
||||||
_properties = association_proxy("_props", "name")
|
_properties = association_proxy("_props", "name")
|
||||||
#FIXME fusion avec expected
|
|
||||||
_calc_props = relationship("_CalcProperties", collection_class=set)
|
_calc_props = relationship("_CalcProperties", collection_class=set)
|
||||||
_calc_properties = association_proxy("_calc_props", "name")
|
_calc_properties = association_proxy("_calc_props", "name")
|
||||||
_warnings_only = Column(Boolean)
|
_warnings_only = Column(Boolean)
|
||||||
_readonly = Column(Boolean, default=False)
|
_readonly = Column(Boolean, default=False)
|
||||||
_consistencies = relationship('_Consistency', secondary=consistency_table,
|
_consistencies = relationship('_Consistency', secondary=consistency_table,
|
||||||
backref=backref('options', enable_typechecks=False))
|
backref=backref('options',
|
||||||
|
enable_typechecks=False))
|
||||||
_type = Column(String(50))
|
_type = Column(String(50))
|
||||||
|
_stated = Column(Boolean)
|
||||||
__mapper_args__ = {
|
__mapper_args__ = {
|
||||||
'polymorphic_identity': 'option',
|
'polymorphic_identity': 'option',
|
||||||
'polymorphic_on': _type
|
'polymorphic_on': _type
|
||||||
|
@ -290,9 +293,27 @@ class _Base(SqlAlchemyBase):
|
||||||
_group_type = Column(String)
|
_group_type = Column(String)
|
||||||
_is_build_cache = Column(Boolean, default=False)
|
_is_build_cache = Column(Boolean, default=False)
|
||||||
|
|
||||||
def __init__(self):
|
#def __init__(self):
|
||||||
|
def __init__(self, name, multi, warnings_only, doc, extra, calc_properties,
|
||||||
|
requires, properties, opt=undefined):
|
||||||
util.session.add(self)
|
util.session.add(self)
|
||||||
self.commit()
|
self._name = name
|
||||||
|
if multi is not undefined:
|
||||||
|
self._multi = multi
|
||||||
|
if warnings_only is not undefined:
|
||||||
|
self._warnings_only = warnings_only
|
||||||
|
if doc is not undefined:
|
||||||
|
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
|
||||||
|
|
||||||
def commit(self):
|
def commit(self):
|
||||||
util.session.commit()
|
util.session.commit()
|
||||||
|
@ -300,6 +321,15 @@ class _Base(SqlAlchemyBase):
|
||||||
def _add_consistency(self, func, all_cons_opts, params):
|
def _add_consistency(self, func, all_cons_opts, params):
|
||||||
_Consistency(func, all_cons_opts, params)
|
_Consistency(func, all_cons_opts, params)
|
||||||
|
|
||||||
|
def _set_default_values(self, default, default_multi):
|
||||||
|
if self.impl_is_multi() and default is None:
|
||||||
|
default = []
|
||||||
|
self.impl_validate(default)
|
||||||
|
self._default = default
|
||||||
|
if self.impl_is_multi() and default_multi is not None:
|
||||||
|
self._validate(default_multi)
|
||||||
|
self._default_multi = default_multi
|
||||||
|
|
||||||
def _get_consistencies(self):
|
def _get_consistencies(self):
|
||||||
return [(consistency.func, consistency.options, consistency.params)
|
return [(consistency.func, consistency.options, consistency.params)
|
||||||
for consistency in self._consistencies]
|
for consistency in self._consistencies]
|
||||||
|
@ -307,11 +337,109 @@ class _Base(SqlAlchemyBase):
|
||||||
def _get_id(self):
|
def _get_id(self):
|
||||||
return self.id
|
return self.id
|
||||||
|
|
||||||
|
def impl_get_callback(self):
|
||||||
|
ret = self._callback
|
||||||
|
if ret is None:
|
||||||
|
return (None, {})
|
||||||
|
return ret, self._callback_params
|
||||||
|
|
||||||
|
def impl_get_validator(self):
|
||||||
|
ret = self._validator
|
||||||
|
if ret is None:
|
||||||
|
return (None, {})
|
||||||
|
return ret, self._validator_params
|
||||||
|
|
||||||
def _impl_getsubdyn(self):
|
def _impl_getsubdyn(self):
|
||||||
return self._subdyn
|
return util.session.query(_Base).filter_by(id=self._subdyn).first()
|
||||||
|
|
||||||
|
def _impl_getopt(self):
|
||||||
|
return util.session.query(_Base).filter_by(id=self._opt).first()
|
||||||
|
|
||||||
|
def impl_getname(self):
|
||||||
|
return self._name
|
||||||
|
|
||||||
|
def impl_getrequires(self):
|
||||||
|
return self._requires
|
||||||
|
|
||||||
|
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):
|
def _impl_setsubdyn(self, subdyn):
|
||||||
self._subdyn = subdyn.id
|
self._subdyn = subdyn.id
|
||||||
|
self.commit()
|
||||||
|
|
||||||
|
def _set_readonly(self):
|
||||||
|
self._readonly = True
|
||||||
|
|
||||||
|
def _set_callback(self, callback, callback_params):
|
||||||
|
self._callback = callback
|
||||||
|
if callback_params is not None:
|
||||||
|
self._callback_params = callback_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):
|
||||||
|
try:
|
||||||
|
return self._readonly
|
||||||
|
except AttributeError:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def impl_is_multi(self):
|
||||||
|
return self._multi == 0 or self._multi == 2
|
||||||
|
|
||||||
|
def impl_is_submulti(self):
|
||||||
|
return self._multi == 2
|
||||||
|
|
||||||
|
def _is_warnings_only(self):
|
||||||
|
return self._warnings_only
|
||||||
|
|
||||||
|
def impl_get_calc_properties(self):
|
||||||
|
try:
|
||||||
|
return self._calc_properties
|
||||||
|
except AttributeError:
|
||||||
|
return frozenset()
|
||||||
|
|
||||||
|
# information
|
||||||
|
def impl_set_information(self, key, value):
|
||||||
|
self._informations[key] = value
|
||||||
|
|
||||||
|
def impl_get_information(self, key, default=undefined):
|
||||||
|
"""retrieves one information's item
|
||||||
|
|
||||||
|
:param key: the item string (ex: "help")
|
||||||
|
"""
|
||||||
|
if default is not undefined:
|
||||||
|
return self._informations.get(key, default)
|
||||||
|
try:
|
||||||
|
return self._informations[key]
|
||||||
|
except KeyError: # pragma: optional cover
|
||||||
|
raise ValueError(_("information's item not found: {0}").format(
|
||||||
|
key))
|
||||||
|
|
||||||
|
def _impl_getattributes(self):
|
||||||
|
slots = set()
|
||||||
|
mapper = inspect(self)
|
||||||
|
for column in mapper.attrs:
|
||||||
|
slots.add(column.key)
|
||||||
|
return slots
|
||||||
|
|
||||||
|
|
||||||
class Cache(SqlAlchemyBase):
|
class Cache(SqlAlchemyBase):
|
||||||
|
@ -326,16 +454,18 @@ class Cache(SqlAlchemyBase):
|
||||||
subdyn_path = Column(String)
|
subdyn_path = Column(String)
|
||||||
|
|
||||||
def __init__(self, descr, parent, option, path, subdyn_path):
|
def __init__(self, descr, parent, option, path, subdyn_path):
|
||||||
|
#context
|
||||||
self.descr = descr.id
|
self.descr = descr.id
|
||||||
self.parent = parent.id
|
self.parent = parent.id
|
||||||
self.option = option.id
|
self.option = option.id
|
||||||
self.path = path
|
self.path = path
|
||||||
self.opt_type = option.__class__.__name__
|
self.opt_type = option.__class__.__name__
|
||||||
#is_subdyn = option._is_subdyn()
|
if subdyn_path:
|
||||||
is_subdyn = option.impl_is_dynoptiondescription()
|
self.is_subdyn = True
|
||||||
self.is_subdyn = is_subdyn
|
|
||||||
if is_subdyn:
|
|
||||||
self.subdyn_path = subdyn_path
|
self.subdyn_path = subdyn_path
|
||||||
|
else:
|
||||||
|
self.is_subdyn = False
|
||||||
|
self.subdyn_path = None
|
||||||
|
|
||||||
|
|
||||||
class StorageOptionDescription(object):
|
class StorageOptionDescription(object):
|
||||||
|
@ -368,36 +498,59 @@ class StorageOptionDescription(object):
|
||||||
save = False
|
save = False
|
||||||
for option in self._impl_getchildren(dyn=False):
|
for option in self._impl_getchildren(dyn=False):
|
||||||
attr = option.impl_getname()
|
attr = option.impl_getname()
|
||||||
util.session.add(Cache(descr, self, option,
|
|
||||||
str('.'.join(_currpath + [attr])), subdyn_path))
|
|
||||||
if isinstance(option, StorageOptionDescription):
|
if isinstance(option, StorageOptionDescription):
|
||||||
|
sub = subdyn_path
|
||||||
if option.impl_is_dynoptiondescription():
|
if option.impl_is_dynoptiondescription():
|
||||||
subdyn_path = '.'.join(_currpath)
|
sub = '.'.join(_currpath)
|
||||||
|
util.session.add(Cache(descr, self, option,
|
||||||
|
str('.'.join(_currpath + [attr])),
|
||||||
|
sub))
|
||||||
_currpath.append(attr)
|
_currpath.append(attr)
|
||||||
option.impl_build_cache_option(descr,
|
option.impl_build_cache_option(descr,
|
||||||
_currpath,
|
_currpath,
|
||||||
subdyn_path)
|
sub)
|
||||||
_currpath.pop()
|
_currpath.pop()
|
||||||
|
else:
|
||||||
|
if subdyn_path:
|
||||||
|
subdyn_path = '.'.join(_currpath)
|
||||||
|
util.session.add(Cache(descr, self, option,
|
||||||
|
str('.'.join(_currpath + [attr])),
|
||||||
|
subdyn_path))
|
||||||
if save:
|
if save:
|
||||||
self._is_build_cache = True
|
self._is_build_cache = True
|
||||||
util.session.commit()
|
util.session.commit()
|
||||||
|
|
||||||
def impl_get_options_paths(self, bytype, byname, _subpath, only_first,
|
def impl_get_options_paths(self, bytype, byname, _subpath, only_first,
|
||||||
context):
|
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)
|
||||||
|
|
||||||
sqlquery = util.session.query(Cache).filter_by(descr=self.id)
|
sqlquery = util.session.query(Cache).filter_by(descr=self.id)
|
||||||
if bytype is None:
|
if bytype is None:
|
||||||
sqlquery = sqlquery.filter(not_(
|
sqlquery = sqlquery.filter(and_(not_(
|
||||||
Cache.opt_type == 'OptionDescription'))
|
Cache.opt_type == 'OptionDescription'),
|
||||||
|
not_(Cache.opt_type == 'DynOptionDescription')))
|
||||||
else:
|
else:
|
||||||
sqlquery = sqlquery.filter_by(opt_type=bytype.__name__)
|
sqlquery = sqlquery.filter_by(opt_type=bytype.__name__)
|
||||||
|
|
||||||
query = ''
|
query = ''
|
||||||
or_query = ''
|
or_query = ''
|
||||||
if _subpath is not None:
|
if _subpath is not None:
|
||||||
query += _subpath + '.'
|
query += _subpath + '.%'
|
||||||
if byname is not None:
|
#if byname is not None:
|
||||||
or_query = query + byname
|
# or_query = query + byname
|
||||||
query += '%.' + byname
|
# query += '%.' + byname
|
||||||
if query != '':
|
if query != '':
|
||||||
filter_query = Cache.path.like(query)
|
filter_query = Cache.path.like(query)
|
||||||
if or_query != '':
|
if or_query != '':
|
||||||
|
@ -415,28 +568,41 @@ class StorageOptionDescription(object):
|
||||||
option = util.session.query(_Base).filter_by(id=opt.option).first()
|
option = util.session.query(_Base).filter_by(id=opt.option).first()
|
||||||
if opt.is_subdyn:
|
if opt.is_subdyn:
|
||||||
name = option.impl_getname()
|
name = option.impl_getname()
|
||||||
if byname is not None and byname.startswith(name):
|
if byname is not None:
|
||||||
found = False
|
if byname.startswith(name):
|
||||||
for suffix in option._subdyn._impl_get_suffixes(
|
found = False
|
||||||
context):
|
dynoption = option._impl_getsubdyn()
|
||||||
if byname == name + suffix:
|
for suffix in dynoption._impl_get_suffixes(
|
||||||
found = True
|
context):
|
||||||
subdyn_path = opt.subdyn_path
|
if byname == name + suffix:
|
||||||
dynpaths = opt.path[len(subdyn_path):].split('.')
|
found = True
|
||||||
|
break
|
||||||
path = subdyn_path
|
if not found:
|
||||||
for dynpath in dynpaths:
|
continue
|
||||||
path += '.' + dynpath + suffix
|
ret_opt = _build_ret_opt(opt, option, suffix, name)
|
||||||
option = option._impl_to_dyn(
|
else:
|
||||||
name + suffix, path)
|
ret_opt = _build_ret_opt(opt, option, suffix, name)
|
||||||
break
|
else:
|
||||||
if not found:
|
if not only_first:
|
||||||
break
|
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:
|
else:
|
||||||
|
if byname is not None and byname != option.impl_getname():
|
||||||
|
continue
|
||||||
ret_opt = (opt.path, option)
|
ret_opt = (opt.path, option)
|
||||||
if only_first:
|
if only_first:
|
||||||
return ret_opt
|
return ret_opt
|
||||||
ret.append(ret_opt)
|
if isinstance(ret_opt, list):
|
||||||
|
if ret_opt != []:
|
||||||
|
ret.extend(ret_opt)
|
||||||
|
else:
|
||||||
|
ret.append(ret_opt)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def _add_children(self, child_names, children):
|
def _add_children(self, child_names, children):
|
||||||
|
@ -453,8 +619,7 @@ class StorageOptionDescription(object):
|
||||||
descr = context.cfgimpl_get_description().id
|
descr = context.cfgimpl_get_description().id
|
||||||
for child in util.session.query(Cache).filter_by(descr=descr,
|
for child in util.session.query(Cache).filter_by(descr=descr,
|
||||||
parent=self.id
|
parent=self.id
|
||||||
).filter_by(
|
).all():
|
||||||
is_subdyn=True).all():
|
|
||||||
yield(util.session.query(_Base).filter_by(id=child.option).first())
|
yield(util.session.query(_Base).filter_by(id=child.option).first())
|
||||||
|
|
||||||
def _getattr(self, name, suffix=undefined, context=undefined, dyn=True):
|
def _getattr(self, name, suffix=undefined, context=undefined, dyn=True):
|
||||||
|
|
|
@ -65,12 +65,13 @@ class Settings(Cache, SqlAlchemyBase):
|
||||||
cascade="all, delete-orphan")
|
cascade="all, delete-orphan")
|
||||||
_permissives = association_proxy("_perms", "permissives")
|
_permissives = association_proxy("_perms", "permissives")
|
||||||
|
|
||||||
def __init__(self, storage):
|
#def __init__(self, storage):
|
||||||
super(Settings, self).__init__(storage)
|
# super(Settings, self).__init__(storage)
|
||||||
|
|
||||||
# properties
|
# properties
|
||||||
def setproperties(self, path, properties):
|
def setproperties(self, path, properties):
|
||||||
self._properties[path] = properties
|
self._properties[path] = properties
|
||||||
|
util.session.commit()
|
||||||
|
|
||||||
def getproperties(self, path, default_properties):
|
def getproperties(self, path, default_properties):
|
||||||
return self._properties.get(path, set(default_properties))
|
return self._properties.get(path, set(default_properties))
|
||||||
|
@ -80,10 +81,12 @@ class Settings(Cache, SqlAlchemyBase):
|
||||||
|
|
||||||
def reset_all_properties(self):
|
def reset_all_properties(self):
|
||||||
self._properties.clear()
|
self._properties.clear()
|
||||||
|
util.session.commit()
|
||||||
|
|
||||||
def delproperties(self, path):
|
def delproperties(self, path):
|
||||||
try:
|
try:
|
||||||
del(self._properties[path])
|
del(self._properties[path])
|
||||||
|
util.session.commit()
|
||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
|
@ -15,45 +15,59 @@
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
from tiramisu.i18n import _
|
from tiramisu.i18n import _
|
||||||
from tiramisu.error import ConfigError
|
|
||||||
from ..util import SerializeObject
|
from ..util import SerializeObject
|
||||||
|
from .util import SqlAlchemyBase
|
||||||
|
import util
|
||||||
|
from sqlalchemy import Column, Integer, String
|
||||||
|
|
||||||
|
|
||||||
class Setting(SerializeObject):
|
class Setting(SerializeObject):
|
||||||
"""Dictionary storage has no particular setting.
|
""":param extension: database file extension (by default: db)
|
||||||
|
:param dir_database: root database directory (by default: /tmp)
|
||||||
"""
|
"""
|
||||||
pass
|
#FIXME
|
||||||
|
extension = 'db'
|
||||||
|
dir_database = '/tmp'
|
||||||
|
|
||||||
|
|
||||||
setting = Setting()
|
setting = Setting()
|
||||||
_list_sessions = []
|
|
||||||
|
|
||||||
|
class Session(SqlAlchemyBase):
|
||||||
|
__tablename__ = 'session'
|
||||||
|
id = Column(Integer, primary_key=True)
|
||||||
|
session = Column(String, index=True)
|
||||||
|
|
||||||
|
def __init__(self, session_id):
|
||||||
|
self.session = session_id
|
||||||
|
|
||||||
|
|
||||||
def list_sessions(): # pragma: optional cover
|
def list_sessions(): # pragma: optional cover
|
||||||
return _list_sessions
|
ret = []
|
||||||
|
for val in util.session.query(Session).all():
|
||||||
|
ret.append(val.session)
|
||||||
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def delete_session(session_id): # pragma: optional cover
|
def delete_session(session_id): # pragma: optional cover
|
||||||
raise ConfigError(_('dictionary storage cannot delete session'))
|
#Must remove all values for this session!
|
||||||
|
util.session.delete(util.session.query(Session).filter_by(session=session_id).first())
|
||||||
|
util.session.commit()
|
||||||
|
|
||||||
|
|
||||||
class Storage(object):
|
class Storage(object):
|
||||||
__slots__ = ('session_id', 'persistent')
|
__slots__ = ('session_id', 'persistent')
|
||||||
storage = 'dictionary'
|
storage = 'sqlalchemy'
|
||||||
#if object could be serializable
|
#if object could be serializable
|
||||||
serializable = True
|
serializable = True
|
||||||
|
|
||||||
def __init__(self, session_id, persistent, test=False):
|
def __init__(self, session_id, persistent, test=False):
|
||||||
if not test and session_id in _list_sessions: # pragma: optional cover
|
if util.session.query(Session).filter_by(session=session_id).first(): # pragma: optional cover
|
||||||
raise ValueError(_('session already used'))
|
raise ValueError(_('session already used'))
|
||||||
if persistent: # pragma: optional cover
|
|
||||||
raise ValueError(_('a dictionary cannot be persistent'))
|
|
||||||
self.session_id = session_id
|
self.session_id = session_id
|
||||||
self.persistent = persistent
|
self.persistent = persistent
|
||||||
_list_sessions.append(self.session_id)
|
util.session.add(Session(session_id))
|
||||||
|
util.session.commit()
|
||||||
|
|
||||||
def __del__(self):
|
def __del__(self):
|
||||||
try:
|
delete_session(self.session_id)
|
||||||
_list_sessions.remove(self.session_id)
|
|
||||||
except AttributeError: # pragma: optional cover
|
|
||||||
pass
|
|
||||||
|
|
|
@ -16,18 +16,12 @@
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
|
|
||||||
#FIXME : il me faut une classe pour le owner !
|
|
||||||
#FIXME : pas si simple que ca ... parce que on lit un owner pour une config ...
|
|
||||||
#FIXME : mais ca serait peut etre logique
|
|
||||||
#FIXME : c'est en fait dans le Setting qu'il faut faire ca ... a voir après
|
|
||||||
|
|
||||||
|
|
||||||
from ..util import Cache
|
from ..util import Cache
|
||||||
from .util import SqlAlchemyBase
|
from .util import SqlAlchemyBase
|
||||||
from sqlalchemy import Column, Integer, String, PickleType, ForeignKey
|
import util
|
||||||
from sqlalchemy.orm import relationship
|
from sqlalchemy import Column, Integer, String, PickleType
|
||||||
from sqlalchemy.orm.collections import attribute_mapped_collection
|
from tiramisu.setting import owners
|
||||||
from sqlalchemy.ext.associationproxy import association_proxy
|
|
||||||
|
|
||||||
|
|
||||||
#____________________________________________________________
|
#____________________________________________________________
|
||||||
|
@ -36,90 +30,114 @@ from sqlalchemy.ext.associationproxy import association_proxy
|
||||||
class _Vinformation(SqlAlchemyBase):
|
class _Vinformation(SqlAlchemyBase):
|
||||||
__tablename__ = 'vinformation'
|
__tablename__ = 'vinformation'
|
||||||
id = Column(Integer, primary_key=True)
|
id = Column(Integer, primary_key=True)
|
||||||
values = Column(Integer, ForeignKey('values.id'))
|
session = Column(String, index=True)
|
||||||
|
path = Column(String, index=True)
|
||||||
key = Column(String)
|
key = Column(String)
|
||||||
value = Column(PickleType)
|
value = Column(PickleType)
|
||||||
|
|
||||||
def __init__(self, key, value):
|
def __init__(self, session, key, value):
|
||||||
|
self.session = session
|
||||||
self.key = key
|
self.key = key
|
||||||
self.value = value
|
self.value = value
|
||||||
|
|
||||||
|
|
||||||
class _Value(SqlAlchemyBase):
|
class Value(SqlAlchemyBase):
|
||||||
__tablename__ = 'value'
|
__tablename__ = 'value'
|
||||||
id = Column(Integer, primary_key=True)
|
id = Column(Integer, primary_key=True)
|
||||||
values = Column(Integer, ForeignKey('values.id'), nullable=False)
|
session = Column(String, index=True)
|
||||||
path = Column(String, nullable=True, unique=True, index=True)
|
path = Column(String, index=True)
|
||||||
#FIXME a revoir avec le owner dans le setting
|
key = Column(String)
|
||||||
owner = Column(String, nullable=False)
|
value = Column(PickleType)
|
||||||
value = Column(PickleType, nullable=False)
|
owner = Column(String)
|
||||||
|
|
||||||
def __init__(self, key, value):
|
def __init__(self, session, path, value, owner):
|
||||||
self.path = key
|
self.session = session
|
||||||
self.value = value[0]
|
self.path = path
|
||||||
self.owner = value[1]
|
self.value = value
|
||||||
|
self.owner = owner
|
||||||
|
|
||||||
|
|
||||||
class Values(Cache, SqlAlchemyBase):
|
class Values(Cache):
|
||||||
__tablename__ = 'values'
|
|
||||||
id = Column(Integer, primary_key=True)
|
|
||||||
_vals = relationship("_Value",
|
|
||||||
collection_class=attribute_mapped_collection('key'),
|
|
||||||
cascade="all, delete-orphan")
|
|
||||||
_informations = association_proxy("_vals", "value")
|
|
||||||
_infos = relationship("_Vinformation",
|
|
||||||
collection_class=attribute_mapped_collection('key'),
|
|
||||||
cascade="all, delete-orphan")
|
|
||||||
_informations = association_proxy("_infos", "value")
|
|
||||||
|
|
||||||
def __init__(self, storage):
|
|
||||||
"""init plugin means create values storage
|
|
||||||
"""
|
|
||||||
self._values = {}
|
|
||||||
self._informations = {}
|
|
||||||
super(Values, self).__init__(storage)
|
|
||||||
|
|
||||||
# value
|
# value
|
||||||
def setvalue(self, path, value, owner):
|
def setvalue(self, path, value, owner):
|
||||||
"""set value for a path
|
"""set value for a path
|
||||||
a specified value must be associated to an owner
|
a specified value must be associated to an owner
|
||||||
"""
|
"""
|
||||||
self._values[path] = (owner, value)
|
val = util.session.query(Value).filter_by(
|
||||||
|
path=path, session=self._storage.session_id).first()
|
||||||
|
if val is None:
|
||||||
|
util.session.add(Value(self._storage.session_id, path, value,
|
||||||
|
owner))
|
||||||
|
else:
|
||||||
|
val.value = value
|
||||||
|
val.owner = owner
|
||||||
|
util.session.commit()
|
||||||
|
|
||||||
def getvalue(self, path):
|
def getvalue(self, path):
|
||||||
"""get value for a path
|
"""get value for a path
|
||||||
return: only value, not the owner
|
return: only value, not the owner
|
||||||
"""
|
"""
|
||||||
return self._values[path][1]
|
val = util.session.query(Value).filter_by(
|
||||||
|
path=path, session=self._storage.session_id).first()
|
||||||
|
if not val:
|
||||||
|
raise KeyError('no value found')
|
||||||
|
return val.value
|
||||||
|
|
||||||
def hasvalue(self, path):
|
def hasvalue(self, path):
|
||||||
"""if path has a value
|
"""if path has a value
|
||||||
return: boolean
|
return: boolean
|
||||||
"""
|
"""
|
||||||
return path in self._values
|
return util.session.query(Value).filter_by(
|
||||||
|
path=path, session=self._storage.session_id).first() is not None
|
||||||
|
|
||||||
def resetvalue(self, path):
|
def resetvalue(self, path):
|
||||||
"""remove value means delete value in storage
|
"""remove value means delete value in storage
|
||||||
"""
|
"""
|
||||||
del(self._values[path])
|
val = util.session.query(Value).filter_by(
|
||||||
|
path=path, session=self._storage.session_id).first()
|
||||||
|
if val is not None:
|
||||||
|
util.session.delete(val)
|
||||||
|
util.session.commit()
|
||||||
|
|
||||||
def get_modified_values(self):
|
def get_modified_values(self):
|
||||||
"""return all values in a dictionary
|
"""return all values in a dictionary
|
||||||
example: {'path1': (owner, 'value1'), 'path2': (owner, 'value2')}
|
example: {'path1': (owner, 'value1'), 'path2': (owner, 'value2')}
|
||||||
"""
|
"""
|
||||||
return self._values
|
ret = {}
|
||||||
|
for val in util.session.query(Value).filter_by(
|
||||||
|
session=self._storage.session_id).all():
|
||||||
|
ret[val.path] = (val.owner, val.value)
|
||||||
|
return ret
|
||||||
|
|
||||||
# owner
|
# owner
|
||||||
def setowner(self, path, owner):
|
def setowner(self, path, owner):
|
||||||
"""change owner for a path
|
"""change owner for a path
|
||||||
"""
|
"""
|
||||||
self._values[path] = (owner, self._values[path][1])
|
val = util.session.query(Value).filter_by(
|
||||||
|
path=path, session=self._storage.session_id).first()
|
||||||
|
if val is None:
|
||||||
|
raise KeyError('no value found')
|
||||||
|
else:
|
||||||
|
val.owner = owner
|
||||||
|
util.session.commit()
|
||||||
|
|
||||||
def getowner(self, path, default):
|
def getowner(self, path, default):
|
||||||
"""get owner for a path
|
"""get owner for a path
|
||||||
return: owner object
|
return: owner object
|
||||||
"""
|
"""
|
||||||
return self._values.get(path, (default, None))[0]
|
val = util.session.query(Value).filter_by(
|
||||||
|
path=path, session=self._storage.session_id).first()
|
||||||
|
if val is None:
|
||||||
|
return default
|
||||||
|
else:
|
||||||
|
owner = val.owner
|
||||||
|
# autocreate owners
|
||||||
|
try:
|
||||||
|
return getattr(owners, owner)
|
||||||
|
except AttributeError:
|
||||||
|
owners.addowner(owner)
|
||||||
|
return getattr(owners, owner)
|
||||||
|
|
||||||
def set_information(self, key, value):
|
def set_information(self, key, value):
|
||||||
"""updates the information's attribute
|
"""updates the information's attribute
|
||||||
|
@ -128,14 +146,23 @@ class Values(Cache, SqlAlchemyBase):
|
||||||
:param key: information's key (ex: "help", "doc"
|
:param key: information's key (ex: "help", "doc"
|
||||||
:param value: information's value (ex: "the help string")
|
:param value: information's value (ex: "the help string")
|
||||||
"""
|
"""
|
||||||
self._informations[key] = value
|
pass
|
||||||
|
val = util.session.query(_Vinformation).filter_by(
|
||||||
|
key=key, session=self._storage.session_id).first()
|
||||||
|
if val is None:
|
||||||
|
util.session.add(_Vinformation(self._storage.session_id, key,
|
||||||
|
value))
|
||||||
|
else:
|
||||||
|
val.value = value
|
||||||
|
util.session.commit()
|
||||||
|
|
||||||
def get_information(self, key):
|
def get_information(self, key):
|
||||||
"""retrieves one information's item
|
"""retrieves one information's item
|
||||||
|
|
||||||
:param key: the item string (ex: "help")
|
:param key: the item string (ex: "help")
|
||||||
"""
|
"""
|
||||||
if key in self._informations:
|
val = util.session.query(_Vinformation).filter_by(
|
||||||
return self._informations[key]
|
key=key, session=self._storage.session_id).first()
|
||||||
else: # pragma: optional cover
|
if not val:
|
||||||
raise ValueError("not found")
|
raise ValueError("not found")
|
||||||
|
return val.value
|
||||||
|
|
|
@ -346,7 +346,7 @@ class Values(object):
|
||||||
"""
|
"""
|
||||||
if isinstance(opt, SymLinkOption) and \
|
if isinstance(opt, SymLinkOption) and \
|
||||||
not isinstance(opt, DynSymLinkOption):
|
not isinstance(opt, DynSymLinkOption):
|
||||||
opt = opt._opt
|
opt = opt._impl_getopt()
|
||||||
path = opt.impl_getpath(self._getcontext())
|
path = opt.impl_getpath(self._getcontext())
|
||||||
return self._getowner(opt, path, force_permissive=force_permissive)
|
return self._getowner(opt, path, force_permissive=force_permissive)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue