better support for sqlalchemy storage
This commit is contained in:
parent
3cc2d9ca3d
commit
71f8926fca
16 changed files with 369 additions and 241 deletions
|
@ -37,6 +37,14 @@ def return_list(val=None):
|
||||||
return ['val1', 'val2']
|
return ['val1', 'val2']
|
||||||
|
|
||||||
|
|
||||||
|
def return_same_list():
|
||||||
|
return ['val1', 'val1']
|
||||||
|
|
||||||
|
|
||||||
|
def return_wrong_list():
|
||||||
|
return ['---', ' ']
|
||||||
|
|
||||||
|
|
||||||
def test_build_dyndescription():
|
def test_build_dyndescription():
|
||||||
st = StrOption('st', '')
|
st = StrOption('st', '')
|
||||||
dod = DynOptionDescription('dod', '', [st], callback=return_list)
|
dod = DynOptionDescription('dod', '', [st], callback=return_list)
|
||||||
|
@ -193,18 +201,18 @@ def test_prop_dyndescription():
|
||||||
stval2 = cfg.unwrap_from_path('od.dodval2.stval2')
|
stval2 = cfg.unwrap_from_path('od.dodval2.stval2')
|
||||||
dodval1 = cfg.unwrap_from_path('od.dodval1')
|
dodval1 = cfg.unwrap_from_path('od.dodval1')
|
||||||
dodval2 = cfg.unwrap_from_path('od.dodval2')
|
dodval2 = cfg.unwrap_from_path('od.dodval2')
|
||||||
assert str(cfg.cfgimpl_get_settings()[stval1]) == str(['test'])
|
assert str(cfg.cfgimpl_get_settings()[stval1]) in [str(['test']), str([u'test'])]
|
||||||
assert str(cfg.cfgimpl_get_settings()[stval2]) == str(['test'])
|
assert str(cfg.cfgimpl_get_settings()[stval2]) in [str(['test']), str([u'test'])]
|
||||||
cfg.cfgimpl_get_settings()[stval2].append('test2')
|
cfg.cfgimpl_get_settings()[stval2].append('test2')
|
||||||
assert str(cfg.cfgimpl_get_settings()[stval1]) == str(['test'])
|
assert str(cfg.cfgimpl_get_settings()[stval1]) in [str(['test']), str([u'test'])]
|
||||||
assert str(cfg.cfgimpl_get_settings()[stval2]) == str(['test', 'test2'])
|
assert str(cfg.cfgimpl_get_settings()[stval2]) in [str(['test', 'test2']), str([u'test', 'test2'])]
|
||||||
cfg.cfgimpl_get_settings()[stval1].remove('test')
|
cfg.cfgimpl_get_settings()[stval1].remove('test')
|
||||||
assert str(cfg.cfgimpl_get_settings()[stval1]) == str([])
|
assert str(cfg.cfgimpl_get_settings()[stval1]) == str([])
|
||||||
#
|
#
|
||||||
assert str(cfg.cfgimpl_get_settings()[dodval1]) == str([])
|
assert str(cfg.cfgimpl_get_settings()[dodval1]) == str([])
|
||||||
assert str(cfg.cfgimpl_get_settings()[dodval2]) == str([])
|
assert str(cfg.cfgimpl_get_settings()[dodval2]) == str([])
|
||||||
cfg.cfgimpl_get_settings()[dodval1].append('test1')
|
cfg.cfgimpl_get_settings()[dodval1].append('test1')
|
||||||
assert str(cfg.cfgimpl_get_settings()[dodval1]) == str(['test1'])
|
assert str(cfg.cfgimpl_get_settings()[dodval1]) in [str(['test1']), str([u'test1'])]
|
||||||
assert str(cfg.cfgimpl_get_settings()[dodval2]) == str([])
|
assert str(cfg.cfgimpl_get_settings()[dodval2]) == str([])
|
||||||
cfg.cfgimpl_get_settings()[dodval1].remove('test1')
|
cfg.cfgimpl_get_settings()[dodval1].remove('test1')
|
||||||
assert str(cfg.cfgimpl_get_settings()[dodval1]) == str([])
|
assert str(cfg.cfgimpl_get_settings()[dodval1]) == str([])
|
||||||
|
@ -402,11 +410,11 @@ def test_prop_dyndescription_context():
|
||||||
cfg = Config(od2)
|
cfg = Config(od2)
|
||||||
stval1 = cfg.unwrap_from_path('od.dodval1.stval1')
|
stval1 = cfg.unwrap_from_path('od.dodval1.stval1')
|
||||||
stval2 = cfg.unwrap_from_path('od.dodval2.stval2')
|
stval2 = cfg.unwrap_from_path('od.dodval2.stval2')
|
||||||
assert str(cfg.cfgimpl_get_settings()[stval1]) == str(['test'])
|
assert str(cfg.cfgimpl_get_settings()[stval1]) in [str(['test']), str([u'test'])]
|
||||||
assert str(cfg.cfgimpl_get_settings()[stval2]) == str(['test'])
|
assert str(cfg.cfgimpl_get_settings()[stval2]) in [str(['test']), str([u'test'])]
|
||||||
cfg.cfgimpl_get_settings()[stval2].append('test2')
|
cfg.cfgimpl_get_settings()[stval2].append('test2')
|
||||||
assert str(cfg.cfgimpl_get_settings()[stval1]) == str(['test'])
|
assert str(cfg.cfgimpl_get_settings()[stval1]) in [str(['test']), str([u'test'])]
|
||||||
assert str(cfg.cfgimpl_get_settings()[stval2]) == str(['test', 'test2'])
|
assert str(cfg.cfgimpl_get_settings()[stval2]) in [str(['test', 'test2']), str([u'test', 'test2'])]
|
||||||
cfg.cfgimpl_get_settings()[stval1].remove('test')
|
cfg.cfgimpl_get_settings()[stval1].remove('test')
|
||||||
assert str(cfg.cfgimpl_get_settings()[stval1]) == str([])
|
assert str(cfg.cfgimpl_get_settings()[stval1]) == str([])
|
||||||
|
|
||||||
|
@ -1293,13 +1301,11 @@ def test_invalid_symlink_dyndescription():
|
||||||
|
|
||||||
def test_nocallback_dyndescription():
|
def test_nocallback_dyndescription():
|
||||||
st = StrOption('st', '')
|
st = StrOption('st', '')
|
||||||
st2 = StrOption('st2', st)
|
st2 = StrOption('st2', '')
|
||||||
raises(ConfigError, "DynOptionDescription('dod', '', [st, st2])")
|
raises(ConfigError, "DynOptionDescription('dod', '', [st, st2])")
|
||||||
|
|
||||||
|
|
||||||
def test_invalid_samevalue_dyndescription():
|
def test_invalid_samevalue_dyndescription():
|
||||||
def return_same_list():
|
|
||||||
return ['val1', 'val1']
|
|
||||||
st = StrOption('st', '')
|
st = StrOption('st', '')
|
||||||
dod = DynOptionDescription('dod', '', [st], callback=return_same_list)
|
dod = DynOptionDescription('dod', '', [st], callback=return_same_list)
|
||||||
od = OptionDescription('od', '', [dod])
|
od = OptionDescription('od', '', [dod])
|
||||||
|
@ -1308,10 +1314,8 @@ def test_invalid_samevalue_dyndescription():
|
||||||
|
|
||||||
|
|
||||||
def test_invalid_name_dyndescription():
|
def test_invalid_name_dyndescription():
|
||||||
def return_same_list():
|
|
||||||
return ['---', ' ']
|
|
||||||
st = StrOption('st', '')
|
st = StrOption('st', '')
|
||||||
dod = DynOptionDescription('dod', '', [st], callback=return_same_list)
|
dod = DynOptionDescription('dod', '', [st], callback=return_wrong_list)
|
||||||
od = OptionDescription('od', '', [dod])
|
od = OptionDescription('od', '', [dod])
|
||||||
cfg = Config(od)
|
cfg = Config(od)
|
||||||
raises(ValueError, "print cfg")
|
raises(ValueError, "print cfg")
|
||||||
|
|
|
@ -382,4 +382,4 @@ def test_properties_cached():
|
||||||
setting = c.cfgimpl_get_settings()
|
setting = c.cfgimpl_get_settings()
|
||||||
option = c.cfgimpl_get_description().sub.b1
|
option = c.cfgimpl_get_description().sub.b1
|
||||||
c._setattr('sub.b1', True, force_permissive=True)
|
c._setattr('sub.b1', True, force_permissive=True)
|
||||||
assert str(setting[b1]) == "['test']"
|
assert str(setting[b1]) in ["['test']", "[u'test']"]
|
||||||
|
|
|
@ -149,7 +149,8 @@ def carry_out_calculation(option, config, callback, callback_params,
|
||||||
if isinstance(callbk, tuple):
|
if isinstance(callbk, tuple):
|
||||||
if config is undefined:
|
if config is undefined:
|
||||||
raise ContextError() # pragma: optional cover
|
raise ContextError() # pragma: optional cover
|
||||||
if len(callbk) == 1: # pragma: optional cover
|
if callbk[0] is None: # pragma: optional cover
|
||||||
|
#Not an option, set full context
|
||||||
tcparams.setdefault(key, []).append((config, False))
|
tcparams.setdefault(key, []).append((config, False))
|
||||||
else:
|
else:
|
||||||
# callbk is something link (opt, True|False)
|
# callbk is something link (opt, True|False)
|
||||||
|
|
|
@ -33,11 +33,7 @@ from tiramisu.storage import get_storages_option
|
||||||
StorageBase = get_storages_option('base')
|
StorageBase = get_storages_option('base')
|
||||||
|
|
||||||
|
|
||||||
class SubMulti(object):
|
submulti = 2
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
submulti = SubMulti()
|
|
||||||
|
|
||||||
|
|
||||||
allowed_character = '[a-z\d\-_]'
|
allowed_character = '[a-z\d\-_]'
|
||||||
|
@ -115,6 +111,9 @@ class Base(StorageBase):
|
||||||
if callback is not None:
|
if callback is not None:
|
||||||
validate_callback(callback, callback_params, 'callback')
|
validate_callback(callback, callback_params, 'callback')
|
||||||
self._callback = callback
|
self._callback = callback
|
||||||
|
if callback_params is None:
|
||||||
|
self._callback_params = {}
|
||||||
|
else:
|
||||||
self._callback_params = callback_params
|
self._callback_params = callback_params
|
||||||
|
|
||||||
def __init__(self, name, doc, default=None, default_multi=None,
|
def __init__(self, name, doc, default=None, default_multi=None,
|
||||||
|
@ -143,8 +142,13 @@ class Base(StorageBase):
|
||||||
raise ValueError(_("invalid default_multi value {0} "
|
raise ValueError(_("invalid default_multi value {0} "
|
||||||
"for option {1}: {2}").format(
|
"for option {1}: {2}").format(
|
||||||
str(default_multi), name, err))
|
str(default_multi), name, err))
|
||||||
self._multi = multi
|
if multi is True:
|
||||||
if self._multi is not False:
|
self._multi = 0
|
||||||
|
elif multi is False:
|
||||||
|
self._multi = 1
|
||||||
|
elif multi is submulti:
|
||||||
|
self._multi = submulti
|
||||||
|
if self._multi != 1:
|
||||||
if default is None:
|
if default is None:
|
||||||
default = []
|
default = []
|
||||||
self._default_multi = default_multi
|
self._default_multi = default_multi
|
||||||
|
@ -260,10 +264,10 @@ class BaseOption(Base):
|
||||||
return
|
return
|
||||||
if not load and self._callback is None:
|
if not load and self._callback is None:
|
||||||
self._state_callback = None
|
self._state_callback = None
|
||||||
self._state_callback_params = None
|
self._state_callback_params = {}
|
||||||
elif load and self._state_callback is None:
|
elif load and self._state_callback is None:
|
||||||
self._callback = None
|
self._callback = None
|
||||||
self._callback_params = None
|
self._callback_params = {}
|
||||||
del(self._state_callback)
|
del(self._state_callback)
|
||||||
del(self._state_callback_params)
|
del(self._state_callback_params)
|
||||||
else:
|
else:
|
||||||
|
@ -273,7 +277,7 @@ class BaseOption(Base):
|
||||||
else:
|
else:
|
||||||
callback = self._callback
|
callback = self._callback
|
||||||
callback_params = self._callback_params
|
callback_params = self._callback_params
|
||||||
self._state_callback_params = None
|
self._state_callback_params = {}
|
||||||
if callback_params is not None:
|
if callback_params is not None:
|
||||||
cllbck_prms = {}
|
cllbck_prms = {}
|
||||||
for key, values in callback_params.items():
|
for key, values in callback_params.items():
|
||||||
|
@ -429,6 +433,19 @@ class BaseOption(Base):
|
||||||
def impl_get_callback(self):
|
def impl_get_callback(self):
|
||||||
return self._callback, self._callback_params
|
return self._callback, self._callback_params
|
||||||
|
|
||||||
|
def impl_has_callback(self):
|
||||||
|
"to know if a callback has been defined or not"
|
||||||
|
return self._callback is not None
|
||||||
|
|
||||||
|
def _is_subdyn(self):
|
||||||
|
try:
|
||||||
|
return self._subdyn is not None
|
||||||
|
except AttributeError:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def impl_getproperties(self):
|
||||||
|
return self._properties
|
||||||
|
|
||||||
|
|
||||||
class OnlyOption(BaseOption):
|
class OnlyOption(BaseOption):
|
||||||
__slots__ = tuple()
|
__slots__ = tuple()
|
||||||
|
@ -713,18 +730,11 @@ class Option(OnlyOption):
|
||||||
"accesses the Option's doc"
|
"accesses the Option's doc"
|
||||||
return self.impl_get_information('doc')
|
return self.impl_get_information('doc')
|
||||||
|
|
||||||
def impl_has_callback(self):
|
|
||||||
"to know if a callback has been defined or not"
|
|
||||||
if self._callback is None:
|
|
||||||
return False
|
|
||||||
else:
|
|
||||||
return True
|
|
||||||
|
|
||||||
#def impl_getkey(self, value):
|
#def impl_getkey(self, value):
|
||||||
# return value
|
# return value
|
||||||
|
|
||||||
def impl_is_multi(self):
|
def impl_is_multi(self):
|
||||||
return self._multi is True or self._multi is submulti
|
return self._multi == 0 or self._multi is submulti
|
||||||
|
|
||||||
def impl_is_submulti(self):
|
def impl_is_submulti(self):
|
||||||
return self._multi is submulti
|
return self._multi is submulti
|
||||||
|
@ -746,7 +756,7 @@ class Option(OnlyOption):
|
||||||
self._name))
|
self._name))
|
||||||
warnings_only = params.get('warnings_only', False)
|
warnings_only = params.get('warnings_only', False)
|
||||||
if self._is_subdyn():
|
if self._is_subdyn():
|
||||||
dynod = self._subdyn
|
dynod = self._impl_getsubdyn()
|
||||||
else:
|
else:
|
||||||
dynod = None
|
dynod = None
|
||||||
for opt in other_opts:
|
for opt in other_opts:
|
||||||
|
@ -756,10 +766,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._subdyn:
|
if dynod != opt._impl_getsubdyn():
|
||||||
raise ConfigError(_('option in consistency must be in same'
|
raise ConfigError(_('option in consistency must be in same'
|
||||||
' dynoptiondescription'))
|
' dynoptiondescription'))
|
||||||
dynod = opt._subdyn
|
dynod = opt._impl_getsubdyn()
|
||||||
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'))
|
||||||
|
@ -847,10 +857,10 @@ class Option(OnlyOption):
|
||||||
default_multi = self._default_multi
|
default_multi = self._default_multi
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
default_multi = None
|
default_multi = None
|
||||||
if callback is not None and ((not self._multi and
|
if callback is not None and ((self._multi == 1 and
|
||||||
(self._default is not None or
|
(self._default is not None or
|
||||||
default_multi is not None))
|
default_multi is not None))
|
||||||
or (self._multi and
|
or (self._multi != 1 and
|
||||||
(self._default != [] or
|
(self._default != [] or
|
||||||
default_multi is not None))
|
default_multi is not None))
|
||||||
): # pragma: optional cover
|
): # pragma: optional cover
|
||||||
|
@ -983,6 +993,23 @@ class SymLinkOption(OnlyOption):
|
||||||
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._opt.impl_get_information(key, default)
|
||||||
|
|
||||||
|
#FIXME utile tout ca ? c'est un peu de la duplication ...
|
||||||
|
def impl_getproperties(self):
|
||||||
|
return self._opt._properties
|
||||||
|
|
||||||
|
def impl_get_callback(self):
|
||||||
|
return self._opt._callback, self._opt._callback_params
|
||||||
|
|
||||||
|
def impl_has_callback(self):
|
||||||
|
"to know if a callback has been defined or not"
|
||||||
|
return self._opt._callback is not None
|
||||||
|
|
||||||
|
def _is_subdyn(self):
|
||||||
|
try:
|
||||||
|
return self._opt._subdyn is not None
|
||||||
|
except AttributeError:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
class DynSymLinkOption(SymLinkOption):
|
class DynSymLinkOption(SymLinkOption):
|
||||||
__slots__ = ('_dyn',)
|
__slots__ = ('_dyn',)
|
||||||
|
|
|
@ -55,7 +55,7 @@ class MasterSlaves(object):
|
||||||
).format(name))
|
).format(name))
|
||||||
if validate:
|
if validate:
|
||||||
callback, callback_params = self.master.impl_get_callback()
|
callback, callback_params = self.master.impl_get_callback()
|
||||||
if callback is not None and callback_params is not None: # pragma: optional cover
|
if callback is not None and callback_params != {}: # pragma: optional cover
|
||||||
for key, callbacks in callback_params.items():
|
for key, callbacks in callback_params.items():
|
||||||
for callbk in callbacks:
|
for callbk in callbacks:
|
||||||
if isinstance(callbk, tuple):
|
if isinstance(callbk, tuple):
|
||||||
|
|
|
@ -48,11 +48,14 @@ class ChoiceOption(Option):
|
||||||
"""
|
"""
|
||||||
if isinstance(values, FunctionType):
|
if isinstance(values, FunctionType):
|
||||||
validate_callback(values, values_params, 'values')
|
validate_callback(values, values_params, 'values')
|
||||||
elif not isinstance(values, tuple): # pragma: optional cover
|
else:
|
||||||
|
if values_params is not None:
|
||||||
|
raise ValueError(_('values is not a function, so values_params must be None'))
|
||||||
|
if not isinstance(values, tuple): # pragma: optional cover
|
||||||
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))
|
||||||
self._extra = {'_choice_values': values,
|
self._choice_values = values
|
||||||
'_choice_values_params': values_params}
|
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,
|
||||||
|
@ -66,9 +69,9 @@ class ChoiceOption(Option):
|
||||||
|
|
||||||
def impl_get_values(self, context):
|
def impl_get_values(self, context):
|
||||||
#FIXME cache? but in context...
|
#FIXME cache? but in context...
|
||||||
values = self._extra['_choice_values']
|
values = self._choice_values
|
||||||
if isinstance(values, FunctionType):
|
if isinstance(values, FunctionType):
|
||||||
values_params = self._extra['_choice_values_params']
|
values_params = self._choice_values_params
|
||||||
if values_params is None:
|
if values_params is None:
|
||||||
values_params = {}
|
values_params = {}
|
||||||
values = carry_out_calculation(self, config=context,
|
values = carry_out_calculation(self, config=context,
|
||||||
|
|
|
@ -74,7 +74,6 @@ class OptionDescription(BaseOption, StorageOptionDescription):
|
||||||
'dynoptiondescription'))
|
'dynoptiondescription'))
|
||||||
old = child
|
old = child
|
||||||
self._add_children(child_names, children)
|
self._add_children(child_names, children)
|
||||||
self._cache_paths = None
|
|
||||||
self._cache_consistencies = None
|
self._cache_consistencies = None
|
||||||
# the group_type is useful for filtering OptionDescriptions in a config
|
# the group_type is useful for filtering OptionDescriptions in a config
|
||||||
self._group_type = groups.default
|
self._group_type = groups.default
|
||||||
|
@ -167,9 +166,6 @@ 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 _valid_consistency(self, option, value, context, index, submulti_idx):
|
def _valid_consistency(self, option, value, context, index, submulti_idx):
|
||||||
if self._cache_consistencies is None:
|
if self._cache_consistencies is None:
|
||||||
return True
|
return True
|
||||||
|
@ -239,7 +235,6 @@ class OptionDescription(BaseOption, StorageOptionDescription):
|
||||||
:param descr: parent :class:`tiramisu.option.OptionDescription`
|
:param descr: parent :class:`tiramisu.option.OptionDescription`
|
||||||
"""
|
"""
|
||||||
if descr is None:
|
if descr is None:
|
||||||
self._cache_paths = None
|
|
||||||
self._cache_consistencies = None
|
self._cache_consistencies = None
|
||||||
self.impl_build_cache_option()
|
self.impl_build_cache_option()
|
||||||
descr = self
|
descr = self
|
||||||
|
@ -261,8 +256,6 @@ class OptionDescription(BaseOption, StorageOptionDescription):
|
||||||
|
|
||||||
def _impl_get_suffixes(self, context):
|
def _impl_get_suffixes(self, context):
|
||||||
callback, callback_params = self.impl_get_callback()
|
callback, callback_params = self.impl_get_callback()
|
||||||
if callback_params is None:
|
|
||||||
callback_params = {}
|
|
||||||
values = carry_out_calculation(self, config=context,
|
values = carry_out_calculation(self, config=context,
|
||||||
callback=callback,
|
callback=callback,
|
||||||
callback_params=callback_params)
|
callback_params=callback_params)
|
||||||
|
@ -275,10 +268,9 @@ class OptionDescription(BaseOption, StorageOptionDescription):
|
||||||
|
|
||||||
def _impl_search_dynchild(self, name=undefined, context=undefined):
|
def _impl_search_dynchild(self, name=undefined, context=undefined):
|
||||||
ret = []
|
ret = []
|
||||||
for child in self._impl_st_getchildren():
|
for child in self._impl_st_getchildren(context, only_dyn=True):
|
||||||
cname = child.impl_getname()
|
cname = child.impl_getname()
|
||||||
if isinstance(child, DynOptionDescription) and \
|
if name is undefined or name.startswith(cname):
|
||||||
(name is undefined or name.startswith(cname)):
|
|
||||||
path = cname
|
path = cname
|
||||||
for value in child._impl_get_suffixes(context):
|
for value in child._impl_get_suffixes(context):
|
||||||
if name is undefined:
|
if name is undefined:
|
||||||
|
@ -296,7 +288,7 @@ class OptionDescription(BaseOption, StorageOptionDescription):
|
||||||
return child._impl_to_dyn(name, path)
|
return child._impl_to_dyn(name, path)
|
||||||
|
|
||||||
def _impl_getchildren(self, dyn=True, context=undefined):
|
def _impl_getchildren(self, dyn=True, context=undefined):
|
||||||
for child in self._impl_st_getchildren():
|
for child in self._impl_st_getchildren(context):
|
||||||
cname = child._name
|
cname = child._name
|
||||||
if dyn and child.impl_is_dynoptiondescription():
|
if dyn and child.impl_is_dynoptiondescription():
|
||||||
path = cname
|
path = cname
|
||||||
|
@ -310,24 +302,30 @@ class OptionDescription(BaseOption, StorageOptionDescription):
|
||||||
def impl_getchildren(self):
|
def impl_getchildren(self):
|
||||||
return list(self._impl_getchildren())
|
return list(self._impl_getchildren())
|
||||||
|
|
||||||
|
def __getattr__(self, name, context=undefined):
|
||||||
|
if name.startswith('_'): # or name.startswith('impl_'):
|
||||||
|
return object.__getattribute__(self, name)
|
||||||
|
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,
|
||||||
callback=None, callback_params=None):
|
callback=None, callback_params=None):
|
||||||
|
super(DynOptionDescription, self).__init__(name, doc, children,
|
||||||
|
requires, properties)
|
||||||
for child in children:
|
for child in children:
|
||||||
if isinstance(child, OptionDescription):
|
if isinstance(child, OptionDescription):
|
||||||
if child.impl_get_group_type() != groups.master:
|
if child.impl_get_group_type() != groups.master:
|
||||||
raise ConfigError(_('cannot set optiondescription in an '
|
raise ConfigError(_('cannot set optiondescription in an '
|
||||||
'dynoptiondescription'))
|
'dynoptiondescription'))
|
||||||
for chld in child._impl_getchildren():
|
for chld in child._impl_getchildren():
|
||||||
chld._subdyn = self
|
chld._impl_setsubdyn(self)
|
||||||
if isinstance(child, SymLinkOption):
|
if isinstance(child, SymLinkOption):
|
||||||
raise ConfigError(_('cannot set symlinkoption in an '
|
raise ConfigError(_('cannot set symlinkoption in an '
|
||||||
'dynoptiondescription'))
|
'dynoptiondescription'))
|
||||||
child._subdyn = self
|
child._impl_setsubdyn(self)
|
||||||
super(DynOptionDescription, self).__init__(name, doc, children,
|
|
||||||
requires, properties)
|
|
||||||
self.impl_set_callback(callback, callback_params)
|
self.impl_set_callback(callback, callback_params)
|
||||||
|
self.commit()
|
||||||
|
|
||||||
def _validate_callback(self, callback, callback_params):
|
def _validate_callback(self, callback, callback_params):
|
||||||
if callback is None:
|
if callback is None:
|
||||||
|
@ -346,7 +344,7 @@ class SynDynOptionDescription(object):
|
||||||
def __getattr__(self, name, context=undefined):
|
def __getattr__(self, name, context=undefined):
|
||||||
if name in dir(self._opt):
|
if name in dir(self._opt):
|
||||||
return getattr(self._opt, name)
|
return getattr(self._opt, name)
|
||||||
return self._opt._getattr(name, self._name, self._suffix, context)
|
return self._opt._getattr(name, suffix=self._suffix, context=context)
|
||||||
|
|
||||||
def impl_getname(self):
|
def impl_getname(self):
|
||||||
return self._name
|
return self._name
|
||||||
|
|
|
@ -100,6 +100,9 @@ rw_append = set(['frozen', 'disabled', 'validator', 'hidden'])
|
||||||
rw_remove = set(['permissive', 'everything_frozen', 'mandatory'])
|
rw_remove = set(['permissive', 'everything_frozen', 'mandatory'])
|
||||||
|
|
||||||
|
|
||||||
|
forbidden_set_properties = set(['force_store_value'])
|
||||||
|
|
||||||
|
|
||||||
log = getLogger('tiramisu')
|
log = getLogger('tiramisu')
|
||||||
#FIXME
|
#FIXME
|
||||||
#import logging
|
#import logging
|
||||||
|
@ -253,7 +256,7 @@ class Property(object):
|
||||||
'this property is calculated').format(
|
'this property is calculated').format(
|
||||||
propname, self._opt.impl_getname()))
|
propname, self._opt.impl_getname()))
|
||||||
self._properties.add(propname)
|
self._properties.add(propname)
|
||||||
self._setting._setproperties(self._properties, self._opt, self._path)
|
self._setting._setproperties(self._properties, self._path)
|
||||||
|
|
||||||
def remove(self, propname):
|
def remove(self, propname):
|
||||||
"""Removes a property named propname
|
"""Removes a property named propname
|
||||||
|
@ -263,8 +266,7 @@ class Property(object):
|
||||||
"""
|
"""
|
||||||
if propname in self._properties:
|
if propname in self._properties:
|
||||||
self._properties.remove(propname)
|
self._properties.remove(propname)
|
||||||
self._setting._setproperties(self._properties, self._opt,
|
self._setting._setproperties(self._properties, self._path)
|
||||||
self._path)
|
|
||||||
|
|
||||||
def extend(self, propnames):
|
def extend(self, propnames):
|
||||||
"""Extends properties to the existing properties
|
"""Extends properties to the existing properties
|
||||||
|
@ -347,7 +349,7 @@ class Settings(object):
|
||||||
else:
|
else:
|
||||||
if opt is not None and _path is None:
|
if opt is not None and _path is None:
|
||||||
_path = opt.impl_getpath(self._getcontext())
|
_path = opt.impl_getpath(self._getcontext())
|
||||||
self._p_.reset_properties(_path)
|
self._p_.delproperties(_path)
|
||||||
self._getcontext().cfgimpl_reset_cache()
|
self._getcontext().cfgimpl_reset_cache()
|
||||||
|
|
||||||
def _getproperties(self, opt=None, path=None, _is_apply_req=True):
|
def _getproperties(self, opt=None, path=None, _is_apply_req=True):
|
||||||
|
@ -367,7 +369,7 @@ class Settings(object):
|
||||||
is_cached, props = self._p_.getcache(path, ntime)
|
is_cached, props = self._p_.getcache(path, ntime)
|
||||||
if is_cached:
|
if is_cached:
|
||||||
return copy(props)
|
return copy(props)
|
||||||
props = self._p_.getproperties(path, opt._properties)
|
props = self._p_.getproperties(path, opt.impl_getproperties())
|
||||||
if _is_apply_req:
|
if _is_apply_req:
|
||||||
props = copy(props)
|
props = copy(props)
|
||||||
props |= self.apply_requires(opt, path)
|
props |= self.apply_requires(opt, path)
|
||||||
|
@ -383,32 +385,27 @@ class Settings(object):
|
||||||
"puts property propname in the Config's properties attribute"
|
"puts property propname in the Config's properties attribute"
|
||||||
props = self._p_.getproperties(None, default_properties)
|
props = self._p_.getproperties(None, default_properties)
|
||||||
props.add(propname)
|
props.add(propname)
|
||||||
self._setproperties(props, None, None)
|
self._setproperties(props, None)
|
||||||
|
|
||||||
def remove(self, propname):
|
def remove(self, propname):
|
||||||
"deletes property propname in the Config's properties attribute"
|
"deletes property propname in the Config's properties attribute"
|
||||||
props = self._p_.getproperties(None, default_properties)
|
props = self._p_.getproperties(None, default_properties)
|
||||||
if propname in props:
|
if propname in props:
|
||||||
props.remove(propname)
|
props.remove(propname)
|
||||||
self._setproperties(props, None, None)
|
self._setproperties(props, None)
|
||||||
|
|
||||||
def extend(self, propnames):
|
def extend(self, propnames):
|
||||||
for propname in propnames:
|
for propname in propnames:
|
||||||
self.append(propname)
|
self.append(propname)
|
||||||
|
|
||||||
def _setproperties(self, properties, opt, path):
|
def _setproperties(self, properties, path):
|
||||||
"""save properties for specified opt
|
"""save properties for specified path
|
||||||
(never save properties if same has option properties)
|
(never save properties if same has option properties)
|
||||||
"""
|
"""
|
||||||
if opt is None:
|
forbidden_properties = forbidden_set_properties & properties
|
||||||
self._p_.setproperties(None, properties)
|
if forbidden_properties:
|
||||||
else:
|
raise ConfigError(_('cannot add those properties: {0}').format(
|
||||||
#if opt._calc_properties is not None:
|
' '.join(forbidden_properties)))
|
||||||
# properties -= opt._calc_properties
|
|
||||||
#if set(opt._properties) == properties:
|
|
||||||
# self._p_.reset_properties(path)
|
|
||||||
#else:
|
|
||||||
# self._p_.setproperties(path, properties)
|
|
||||||
self._p_.setproperties(path, properties)
|
self._p_.setproperties(path, properties)
|
||||||
self._getcontext().cfgimpl_reset_cache()
|
self._getcontext().cfgimpl_reset_cache()
|
||||||
|
|
||||||
|
@ -622,15 +619,6 @@ class Settings(object):
|
||||||
def get_modified_permissives(self):
|
def get_modified_permissives(self):
|
||||||
return self._p_.get_modified_permissives()
|
return self._p_.get_modified_permissives()
|
||||||
|
|
||||||
def get_with_property(self, propname):
|
|
||||||
opts, paths = self._getcontext().cfgimpl_get_description(
|
|
||||||
)._cache_paths
|
|
||||||
for index in range(0, len(paths)):
|
|
||||||
opt = opts[index]
|
|
||||||
path = paths[index]
|
|
||||||
if propname in self._getproperties(opt, path, False):
|
|
||||||
yield (opt, path)
|
|
||||||
|
|
||||||
def __getstate__(self):
|
def __getstate__(self):
|
||||||
return {'_p_': self._p_, '_owner': str(self._owner)}
|
return {'_p_': self._p_, '_owner': str(self._owner)}
|
||||||
|
|
||||||
|
|
|
@ -117,15 +117,20 @@ def get_storages(context, session_id, persistent):
|
||||||
session_id = gen_id(context)
|
session_id = gen_id(context)
|
||||||
imp = storage_type.get()
|
imp = storage_type.get()
|
||||||
storage = imp.Storage(session_id, persistent)
|
storage = imp.Storage(session_id, persistent)
|
||||||
|
try:
|
||||||
return imp.Settings(storage), imp.Values(storage)
|
return imp.Settings(storage), imp.Values(storage)
|
||||||
|
except:
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
raise Exception('rah')
|
||||||
|
|
||||||
|
|
||||||
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.Base
|
return imp.StorageBase
|
||||||
else:
|
else:
|
||||||
return imp.OptionDescription
|
return imp.StorageOptionDescription
|
||||||
|
|
||||||
|
|
||||||
def list_sessions(type_): # pragma: optional cover
|
def list_sessions(type_): # pragma: optional cover
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# Copyright (C) 2013 Team tiramisu (see AUTHORS for all contributors)
|
# Copyright (C) 2013-2014 Team tiramisu (see AUTHORS for all contributors)
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify it
|
# This program is free software: you can redistribute it and/or modify it
|
||||||
# under the terms of the GNU Lesser General Public License as published by the
|
# under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
@ -25,7 +25,7 @@ use it. But if something goes wrong, you will lost your modifications.
|
||||||
from .value import Values
|
from .value import Values
|
||||||
from .setting import Settings
|
from .setting import Settings
|
||||||
from .storage import setting, Storage, list_sessions, delete_session
|
from .storage import setting, Storage, list_sessions, delete_session
|
||||||
from .option import Base, OptionDescription
|
from .option import StorageBase, StorageOptionDescription
|
||||||
|
|
||||||
__all__ = (setting, Values, Settings, Storage, list_sessions, delete_session,
|
__all__ = (setting, Values, Settings, Storage, list_sessions, delete_session,
|
||||||
Base, OptionDescription)
|
StorageBase, StorageOptionDescription)
|
||||||
|
|
|
@ -18,14 +18,14 @@
|
||||||
#
|
#
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
from tiramisu.i18n import _
|
from tiramisu.i18n import _
|
||||||
from tiramisu.setting import groups, undefined
|
from tiramisu.setting import undefined
|
||||||
from tiramisu.error import ConfigError
|
from tiramisu.error import ConfigError
|
||||||
|
|
||||||
|
|
||||||
#____________________________________________________________
|
#____________________________________________________________
|
||||||
#
|
#
|
||||||
# Base
|
# Base
|
||||||
class Base(object):
|
class StorageBase(object):
|
||||||
__slots__ = ('_name', '_requires', '_properties', '_readonly',
|
__slots__ = ('_name', '_requires', '_properties', '_readonly',
|
||||||
'_calc_properties', '_informations',
|
'_calc_properties', '_informations',
|
||||||
'_state_readonly', '_state_requires', '_stated',
|
'_state_readonly', '_state_requires', '_stated',
|
||||||
|
@ -34,13 +34,14 @@ class Base(object):
|
||||||
'_state_callback_params', '_callback_params', '_multitype',
|
'_state_callback_params', '_callback_params', '_multitype',
|
||||||
'_consistencies', '_warnings_only', '_master_slaves',
|
'_consistencies', '_warnings_only', '_master_slaves',
|
||||||
'_state_consistencies', '_extra', '_subdyn', '__weakref__',
|
'_state_consistencies', '_extra', '_subdyn', '__weakref__',
|
||||||
'_state_master_slaves')
|
'_state_master_slaves', '_choice_values',
|
||||||
|
'_choice_values_params')
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
try:
|
try:
|
||||||
self._subdyn
|
self._subdyn
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
self._subdyn = False
|
self._subdyn = None
|
||||||
try:
|
try:
|
||||||
self._consistencies
|
self._consistencies
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
|
@ -52,7 +53,7 @@ class Base(object):
|
||||||
try:
|
try:
|
||||||
self._callback_params
|
self._callback_params
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
self._callback_params = None
|
self._callback_params = {}
|
||||||
try:
|
try:
|
||||||
self._validator
|
self._validator
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
|
@ -71,19 +72,22 @@ class Base(object):
|
||||||
def _get_id(self):
|
def _get_id(self):
|
||||||
return id(self)
|
return id(self)
|
||||||
|
|
||||||
def _is_subdyn(self):
|
def _impl_getsubdyn(self):
|
||||||
try:
|
return self._subdyn
|
||||||
return self._subdyn is not False
|
|
||||||
except AttributeError:
|
def _impl_setsubdyn(self, subdyn):
|
||||||
return False
|
self._subdyn = subdyn
|
||||||
|
|
||||||
|
def commit(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class OptionDescription(Base):
|
class StorageOptionDescription(StorageBase):
|
||||||
__slots__ = ('_children', '_cache_paths', '_cache_consistencies',
|
__slots__ = ('_children', '_cache_paths', '_cache_consistencies',
|
||||||
'_group_type', '_is_build_cache', '_state_group_type')
|
'_group_type', '_is_build_cache', '_state_group_type')
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
pass
|
self._cache_paths = None
|
||||||
|
|
||||||
def _add_children(self, child_names, children):
|
def _add_children(self, child_names, children):
|
||||||
self._children = (tuple(child_names), tuple(children))
|
self._children = (tuple(child_names), tuple(children))
|
||||||
|
@ -104,10 +108,14 @@ class OptionDescription(Base):
|
||||||
raise AttributeError(_('no option {0} found').format(opt))
|
raise AttributeError(_('no option {0} found').format(opt))
|
||||||
|
|
||||||
def impl_get_group_type(self): # pragma: optional cover
|
def impl_get_group_type(self): # pragma: optional cover
|
||||||
return getattr(groups, self._group_type)
|
return self._group_type
|
||||||
|
|
||||||
def impl_build_cache_option(self, _currpath=None, cache_path=None,
|
def impl_build_cache_option(self, _currpath=None, cache_path=None,
|
||||||
cache_option=None):
|
cache_option=None):
|
||||||
|
try:
|
||||||
|
self._cache_paths
|
||||||
|
except AttributeError:
|
||||||
|
self._cache_paths = None
|
||||||
if _currpath is None and self._cache_paths is not None: # pragma: optional cover
|
if _currpath is None and self._cache_paths is not None: # pragma: optional cover
|
||||||
# cache already set
|
# cache already set
|
||||||
return
|
return
|
||||||
|
@ -145,8 +153,7 @@ class OptionDescription(Base):
|
||||||
found = True
|
found = True
|
||||||
break
|
break
|
||||||
if not found:
|
if not found:
|
||||||
#FIXME
|
raise ConfigError(_('cannot find dynpath'))
|
||||||
raise ConfigError(_('hu?'))
|
|
||||||
subpath = subpath + suffix
|
subpath = subpath + suffix
|
||||||
for slength in xrange(length, len(spath)):
|
for slength in xrange(length, len(spath)):
|
||||||
subpath = subpath + '.' + spath[slength] + suffix
|
subpath = subpath + '.' + spath[slength] + suffix
|
||||||
|
@ -226,21 +233,17 @@ class OptionDescription(Base):
|
||||||
return find_results[0]
|
return find_results[0]
|
||||||
return find_results
|
return find_results
|
||||||
|
|
||||||
def _impl_st_getchildren(self):
|
def _impl_st_getchildren(self, context, only_dyn=False):
|
||||||
return self._children[1]
|
for child in self._children[1]:
|
||||||
|
if only_dyn is False or child.impl_is_dynoptiondescription():
|
||||||
|
yield(child)
|
||||||
|
|
||||||
def __getattr__(self, name, context=undefined):
|
def _getattr(self, name, suffix=undefined, context=undefined, dyn=True):
|
||||||
if name == '_name':
|
|
||||||
return object.__getattribute__(self, name)
|
|
||||||
return self._getattr(name, context=context)
|
|
||||||
|
|
||||||
def _getattr(self, name, dyn_od=undefined, suffix=undefined,
|
|
||||||
context=undefined, dyn=True):
|
|
||||||
error = False
|
error = False
|
||||||
if suffix is not undefined:
|
if suffix is not undefined:
|
||||||
try:
|
try:
|
||||||
if undefined in [dyn_od, suffix, context]: # pragma: optional cover
|
if undefined in [suffix, context]: # pragma: optional cover
|
||||||
raise ConfigError(_("dyn_od, suffix and context needed if "
|
raise ConfigError(_("suffix and context needed if "
|
||||||
"it's a dyn option"))
|
"it's a dyn option"))
|
||||||
if name.endswith(suffix):
|
if name.endswith(suffix):
|
||||||
oname = name[:-len(suffix)]
|
oname = name[:-len(suffix)]
|
||||||
|
@ -270,3 +273,13 @@ class OptionDescription(Base):
|
||||||
raise AttributeError(_('unknown Option {0} '
|
raise AttributeError(_('unknown Option {0} '
|
||||||
'in OptionDescription {1}'
|
'in OptionDescription {1}'
|
||||||
'').format(name, self._name))
|
'').format(name, self._name))
|
||||||
|
|
||||||
|
def _get_force_store_value(self):
|
||||||
|
#FIXME faire des tests (notamment pas ajouter à un config)
|
||||||
|
#FIXME devrait faire un cache !
|
||||||
|
opts, paths = self._cache_paths
|
||||||
|
for index in range(0, len(paths)):
|
||||||
|
opt = opts[index]
|
||||||
|
path = paths[index]
|
||||||
|
if 'force_store_value' in opt._properties:
|
||||||
|
yield (opt, path)
|
||||||
|
|
|
@ -42,13 +42,12 @@ class Settings(Cache):
|
||||||
def reset_all_properties(self):
|
def reset_all_properties(self):
|
||||||
self._properties.clear()
|
self._properties.clear()
|
||||||
|
|
||||||
def reset_properties(self, path):
|
def delproperties(self, path):
|
||||||
try:
|
try:
|
||||||
del(self._properties[path])
|
del(self._properties[path])
|
||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# permissive
|
|
||||||
def setpermissive(self, path, permissive):
|
def setpermissive(self, path, permissive):
|
||||||
self._permissives[path] = frozenset(permissive)
|
self._permissives[path] = frozenset(permissive)
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
"default plugin for value: set it in a simple dictionary"
|
"default plugin for value: set it in a simple dictionary"
|
||||||
# Copyright (C) 2013 Team tiramisu (see AUTHORS for all contributors)
|
# Copyright (C) 2013-2014 Team tiramisu (see AUTHORS for all contributors)
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify it
|
# This program is free software: you can redistribute it and/or modify it
|
||||||
# under the terms of the GNU Lesser General Public License as published by the
|
# under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
# -*- 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 Lesser General Public License as published by the
|
||||||
|
# Free Software Foundation, either version 3 of the License, or (at your
|
||||||
|
# option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
||||||
|
# details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
# ____________________________________________________________
|
||||||
|
"""Default plugin for storage. All informations are store in a simple
|
||||||
|
dictionary in memory.
|
||||||
|
|
||||||
|
You cannot have persistente informations with this kind of storage.
|
||||||
|
|
||||||
|
The advantage of this solution is that you can easily create a Config and
|
||||||
|
use it. But if something goes wrong, you will lost your modifications.
|
||||||
|
"""
|
||||||
|
from .value import Values
|
||||||
|
from .setting import Settings
|
||||||
|
from .storage import Storage, list_sessions, delete_session, setting
|
||||||
|
from .option import StorageBase, StorageOptionDescription
|
||||||
|
from .util import load
|
||||||
|
|
||||||
|
|
||||||
|
load()
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = (setting, Values, Settings, Storage, list_sessions, delete_session,
|
||||||
|
StorageBase, StorageOptionDescription)
|
||||||
|
# Base, OptionDescription)
|
|
@ -18,28 +18,20 @@
|
||||||
#
|
#
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
from tiramisu.i18n import _
|
from tiramisu.i18n import _
|
||||||
from tiramisu.setting import groups
|
from tiramisu.setting import groups, undefined
|
||||||
|
from tiramisu.error import ConfigError
|
||||||
|
from .util import SqlAlchemyBase
|
||||||
|
import util
|
||||||
|
|
||||||
from sqlalchemy import not_, or_
|
from sqlalchemy import not_, or_
|
||||||
from sqlalchemy.ext.declarative import declarative_base, 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 create_engine, Column, Integer, String, Boolean, \
|
from sqlalchemy import Column, Integer, String, Boolean, PickleType, \
|
||||||
PickleType, ForeignKey, Table
|
ForeignKey, Table
|
||||||
from sqlalchemy.orm import relationship, backref
|
from sqlalchemy.orm import relationship, backref
|
||||||
from sqlalchemy.orm import sessionmaker
|
|
||||||
from sqlalchemy.orm.collections import attribute_mapped_collection
|
from sqlalchemy.orm.collections import attribute_mapped_collection
|
||||||
|
|
||||||
|
from itertools import chain
|
||||||
#FIXME
|
|
||||||
engine = create_engine('sqlite:///:memory:')
|
|
||||||
SqlAlchemyBase = declarative_base()
|
|
||||||
#FIXME a voir:
|
|
||||||
# # Organization.members will be a Query object - no loading
|
|
||||||
# # of the entire collection occurs unless requested
|
|
||||||
# lazy="dynamic",
|
|
||||||
#____________________________________________________________
|
|
||||||
#
|
|
||||||
# require
|
|
||||||
|
|
||||||
|
|
||||||
def load_requires(collection_type, proxy):
|
def load_requires(collection_type, proxy):
|
||||||
|
@ -49,7 +41,7 @@ def load_requires(collection_type, proxy):
|
||||||
ret = []
|
ret = []
|
||||||
requires = getattr(obj, proxy.value_attr)
|
requires = getattr(obj, proxy.value_attr)
|
||||||
for require in requires:
|
for require in requires:
|
||||||
option = session.query(_Base).filter_by(id=require.option).first()
|
option = util.session.query(_Base).filter_by(id=require.option).first()
|
||||||
ret.append(tuple([option, require.expected, require.action, require.inverse, require.transitive, require.same_action]))
|
ret.append(tuple([option, require.expected, require.action, require.inverse, require.transitive, require.same_action]))
|
||||||
return tuple(ret)
|
return tuple(ret)
|
||||||
|
|
||||||
|
@ -158,7 +150,7 @@ def load_callback_parm(collection_type, proxy):
|
||||||
if require.value is not None:
|
if require.value is not None:
|
||||||
ret.append(require.value)
|
ret.append(require.value)
|
||||||
else:
|
else:
|
||||||
option = session.query(_Base).filter_by(id=require.option).first()
|
option = util.session.query(_Base).filter_by(id=require.option).first()
|
||||||
ret.append((option, require.force_permissive))
|
ret.append((option, require.force_permissive))
|
||||||
return tuple(ret)
|
return tuple(ret)
|
||||||
|
|
||||||
|
@ -175,10 +167,10 @@ class _CallbackParamOption(SqlAlchemyBase):
|
||||||
force_permissive = Column(Boolean)
|
force_permissive = Column(Boolean)
|
||||||
value = Column(PickleType)
|
value = Column(PickleType)
|
||||||
|
|
||||||
def __init__(self, option=None, force_permissive=None, value=None):
|
def __init__(self, option=undefined, force_permissive=undefined, value=undefined):
|
||||||
if value is not None:
|
if value is not undefined:
|
||||||
self.value = value
|
self.value = value
|
||||||
else:
|
elif option is not undefined:
|
||||||
self.option = option.id
|
self.option = option.id
|
||||||
self.force_permissive = force_permissive
|
self.force_permissive = force_permissive
|
||||||
|
|
||||||
|
@ -194,6 +186,9 @@ class _CallbackParam(SqlAlchemyBase):
|
||||||
self.key = key
|
self.key = key
|
||||||
for param in params:
|
for param in params:
|
||||||
if isinstance(param, tuple):
|
if isinstance(param, tuple):
|
||||||
|
if param == (None,):
|
||||||
|
self.params.append(_CallbackParamOption())
|
||||||
|
else:
|
||||||
self.params.append(_CallbackParamOption(option=param[0],
|
self.params.append(_CallbackParamOption(option=param[0],
|
||||||
force_permissive=param[1]))
|
force_permissive=param[1]))
|
||||||
else:
|
else:
|
||||||
|
@ -215,7 +210,7 @@ class _Consistency(SqlAlchemyBase):
|
||||||
func = Column(PickleType)
|
func = Column(PickleType)
|
||||||
params = Column(PickleType)
|
params = Column(PickleType)
|
||||||
|
|
||||||
def __init__(self, func, all_cons_opts):
|
def __init__(self, func, all_cons_opts, params):
|
||||||
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)
|
||||||
|
@ -249,9 +244,16 @@ class _Base(SqlAlchemyBase):
|
||||||
_informations = association_proxy("_infos", "value")
|
_informations = association_proxy("_infos", "value")
|
||||||
_default = Column(PickleType)
|
_default = Column(PickleType)
|
||||||
_default_multi = Column(PickleType)
|
_default_multi = Column(PickleType)
|
||||||
|
_subdyn = Column(Integer)
|
||||||
|
_choice_values = Column(PickleType)
|
||||||
|
_cho_params = relationship('_CallbackParam',
|
||||||
|
collection_class=
|
||||||
|
attribute_mapped_collection('key'))
|
||||||
|
_choice_params = association_proxy("_cho_params", "params",
|
||||||
|
getset_factory=load_callback_parm)
|
||||||
_reqs = relationship("_Require", collection_class=list)
|
_reqs = relationship("_Require", collection_class=list)
|
||||||
_requires = association_proxy("_reqs", "requires", getset_factory=load_requires)
|
_requires = association_proxy("_reqs", "requires", getset_factory=load_requires)
|
||||||
_multi = Column(Boolean)
|
_multi = Column(Integer)
|
||||||
_multitype = Column(String)
|
_multitype = Column(String)
|
||||||
######
|
######
|
||||||
_callback = Column(PickleType)
|
_callback = Column(PickleType)
|
||||||
|
@ -264,7 +266,7 @@ class _Base(SqlAlchemyBase):
|
||||||
_val_params = relationship('_CallbackParam',
|
_val_params = relationship('_CallbackParam',
|
||||||
collection_class=
|
collection_class=
|
||||||
attribute_mapped_collection('key'))
|
attribute_mapped_collection('key'))
|
||||||
_validator_params = association_proxy("_call_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 pas 2 fois la meme properties dans la base ...
|
||||||
|
@ -290,11 +292,11 @@ class _Base(SqlAlchemyBase):
|
||||||
_is_build_cache = Column(Boolean, default=False)
|
_is_build_cache = Column(Boolean, default=False)
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
util.session.add(self)
|
||||||
self.commit()
|
self.commit()
|
||||||
|
|
||||||
def commit(self):
|
def commit(self):
|
||||||
session.add(self)
|
util.session.commit()
|
||||||
session.commit()
|
|
||||||
|
|
||||||
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)
|
||||||
|
@ -306,52 +308,35 @@ class _Base(SqlAlchemyBase):
|
||||||
def _get_id(self):
|
def _get_id(self):
|
||||||
return self.id
|
return self.id
|
||||||
|
|
||||||
# ____________________________________________________________
|
def _impl_getsubdyn(self):
|
||||||
# information
|
return self._subdyn
|
||||||
#def impl_set_information(self, key, value):
|
|
||||||
# """updates the information's attribute
|
|
||||||
# (which is a dictionary)
|
|
||||||
|
|
||||||
# :param key: information's key (ex: "help", "doc"
|
def _impl_setsubdyn(self, subdyn):
|
||||||
# :param value: information's value (ex: "the help string")
|
self._subdyn = subdyn.id
|
||||||
# """
|
|
||||||
# info = session.query(_Information).filter_by(option=self.id, key=key).first()
|
|
||||||
# #FIXME pas append ! remplacer !
|
|
||||||
# if info is None:
|
|
||||||
# self._informations.append(_Information(key, value))
|
|
||||||
# else:
|
|
||||||
# info.value = value
|
|
||||||
|
|
||||||
#def impl_get_information(self, key, default=None):
|
|
||||||
# """retrieves one information's item
|
|
||||||
|
|
||||||
# :param key: the item string (ex: "help")
|
|
||||||
# """
|
|
||||||
# info = session.query(_Information).filter_by(option=self.id, key=key).first()
|
|
||||||
# if info is not None:
|
|
||||||
# return info.value
|
|
||||||
# return self._informations[key]
|
|
||||||
# elif default is not None:
|
|
||||||
# return default
|
|
||||||
# else:
|
|
||||||
# raise ValueError(_("information's item not found: {0}").format(
|
|
||||||
# key))
|
|
||||||
|
|
||||||
|
|
||||||
class Cache(SqlAlchemyBase):
|
class Cache(SqlAlchemyBase):
|
||||||
__tablename__ = 'cache'
|
__tablename__ = 'cache'
|
||||||
id = Column(Integer, primary_key=True)
|
id = Column(Integer, primary_key=True)
|
||||||
#FIXME indexer ... les 3
|
path = Column(String, nullable=False, index=True)
|
||||||
path = Column(String, nullable=False)
|
descr = Column(Integer, nullable=False, index=True)
|
||||||
descr = Column(Integer, nullable=False)
|
parent = Column(Integer, nullable=False, index=True)
|
||||||
option = Column(Integer, nullable=False)
|
option = Column(Integer, nullable=False, index=True)
|
||||||
opt_type = Column(String, nullable=False)
|
opt_type = Column(String, nullable=False, index=True)
|
||||||
|
is_subdyn = Column(Boolean, nullable=False, index=True)
|
||||||
|
subdyn_path = Column(String)
|
||||||
|
|
||||||
def __init__(self, descr, option, path):
|
def __init__(self, descr, parent, option, path, subdyn_path):
|
||||||
self.descr = descr.id
|
self.descr = descr.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()
|
||||||
|
is_subdyn = option.impl_is_dynoptiondescription()
|
||||||
|
self.is_subdyn = is_subdyn
|
||||||
|
if is_subdyn:
|
||||||
|
self.subdyn_path = subdyn_path
|
||||||
|
|
||||||
|
|
||||||
class StorageOptionDescription(object):
|
class StorageOptionDescription(object):
|
||||||
|
@ -359,13 +344,13 @@ class StorageOptionDescription(object):
|
||||||
return self._is_build_cache
|
return self._is_build_cache
|
||||||
|
|
||||||
def impl_get_opt_by_path(self, path):
|
def impl_get_opt_by_path(self, path):
|
||||||
ret = session.query(Cache).filter_by(descr=self.id, path=path).first()
|
ret = util.session.query(Cache).filter_by(descr=self.id, path=path).first()
|
||||||
if ret is None:
|
if ret is None:
|
||||||
raise AttributeError(_('no option for path {0}').format(path))
|
raise AttributeError(_('no option for path {0}').format(path))
|
||||||
return session.query(_Base).filter_by(id=ret.option).first()
|
return util.session.query(_Base).filter_by(id=ret.option).first()
|
||||||
|
|
||||||
def impl_get_path_by_opt(self, opt):
|
def impl_get_path_by_opt(self, opt):
|
||||||
ret = session.query(Cache).filter_by(descr=self.id,
|
ret = util.session.query(Cache).filter_by(descr=self.id,
|
||||||
option=opt.id).first()
|
option=opt.id).first()
|
||||||
if ret is None:
|
if ret is None:
|
||||||
raise AttributeError(_('no option {0} found').format(opt))
|
raise AttributeError(_('no option {0} found').format(opt))
|
||||||
|
@ -374,30 +359,36 @@ class StorageOptionDescription(object):
|
||||||
def impl_get_group_type(self):
|
def impl_get_group_type(self):
|
||||||
return getattr(groups, self._group_type)
|
return getattr(groups, self._group_type)
|
||||||
|
|
||||||
def impl_build_cache_option(self, descr=None, _currpath=None):
|
def impl_build_cache_option(self, descr=None, _currpath=None,
|
||||||
|
subdyn_path=None):
|
||||||
if descr is None:
|
if descr is None:
|
||||||
save = True
|
save = True
|
||||||
descr = self
|
descr = self
|
||||||
_currpath = []
|
_currpath = []
|
||||||
else:
|
else:
|
||||||
save = False
|
save = False
|
||||||
for option in self.impl_getchildren():
|
for option in self._impl_getchildren(dyn=False):
|
||||||
attr = option.impl_getname()
|
attr = option.impl_getname()
|
||||||
session.add(Cache(descr, option,
|
util.session.add(Cache(descr, self, option,
|
||||||
str('.'.join(_currpath + [attr]))))
|
str('.'.join(_currpath + [attr])), subdyn_path))
|
||||||
if isinstance(option, StorageOptionDescription):
|
if isinstance(option, StorageOptionDescription):
|
||||||
|
if option.impl_is_dynoptiondescription():
|
||||||
|
subdyn_path = '.'.join(_currpath)
|
||||||
_currpath.append(attr)
|
_currpath.append(attr)
|
||||||
option.impl_build_cache_option(descr,
|
option.impl_build_cache_option(descr,
|
||||||
_currpath)
|
_currpath,
|
||||||
|
subdyn_path)
|
||||||
_currpath.pop()
|
_currpath.pop()
|
||||||
if save:
|
if save:
|
||||||
self._is_build_cache = True
|
self._is_build_cache = True
|
||||||
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,
|
||||||
sqlquery = session.query(Cache).filter_by(descr=self.id)
|
context):
|
||||||
|
sqlquery = util.session.query(Cache).filter_by(descr=self.id)
|
||||||
if bytype is None:
|
if bytype is None:
|
||||||
sqlquery = sqlquery.filter(not_(Cache.opt_type == 'OptionDescription'))
|
sqlquery = sqlquery.filter(not_(
|
||||||
|
Cache.opt_type == 'OptionDescription'))
|
||||||
else:
|
else:
|
||||||
sqlquery = sqlquery.filter_by(opt_type=bytype.__name__)
|
sqlquery = sqlquery.filter_by(opt_type=bytype.__name__)
|
||||||
|
|
||||||
|
@ -413,46 +404,111 @@ class StorageOptionDescription(object):
|
||||||
if or_query != '':
|
if or_query != '':
|
||||||
filter_query = or_(Cache.path == or_query, filter_query)
|
filter_query = or_(Cache.path == or_query, filter_query)
|
||||||
sqlquery = sqlquery.filter(filter_query)
|
sqlquery = sqlquery.filter(filter_query)
|
||||||
if only_first:
|
#if only_first:
|
||||||
opt = sqlquery.first()
|
# opt = sqlquery.first()
|
||||||
if opt is None:
|
# if opt is None:
|
||||||
return tuple()
|
# return tuple()
|
||||||
option = session.query(_Base).filter_by(id=opt.option).first()
|
# option = util.session.query(_Base).filter_by(id=opt.option).first()
|
||||||
return ((opt.path, option),)
|
# return ((opt.path, option),)
|
||||||
else:
|
#else:
|
||||||
ret = []
|
ret = []
|
||||||
for opt in sqlquery.all():
|
for opt in sqlquery.all():
|
||||||
option = session.query(_Base).filter_by(id=opt.option).first()
|
option = util.session.query(_Base).filter_by(id=opt.option).first()
|
||||||
ret.append((opt.path, option))
|
if opt.is_subdyn:
|
||||||
|
name = option.impl_getname()
|
||||||
|
if byname is not None and byname.startswith(name):
|
||||||
|
found = False
|
||||||
|
for suffix in option._subdyn._impl_get_suffixes(
|
||||||
|
context):
|
||||||
|
if byname == name + suffix:
|
||||||
|
found = True
|
||||||
|
subdyn_path = opt.subdyn_path
|
||||||
|
dynpaths = opt.path[len(subdyn_path):].split('.')
|
||||||
|
|
||||||
|
path = subdyn_path
|
||||||
|
for dynpath in dynpaths:
|
||||||
|
path += '.' + dynpath + suffix
|
||||||
|
option = option._impl_to_dyn(
|
||||||
|
name + suffix, path)
|
||||||
|
break
|
||||||
|
if not found:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
ret_opt = (opt.path, option)
|
||||||
|
if only_first:
|
||||||
|
return ret_opt
|
||||||
|
ret.append(ret_opt)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def _add_children(self, child_names, children):
|
def _add_children(self, child_names, children):
|
||||||
for child in children:
|
for child in children:
|
||||||
session.add(_Parent(self, child))
|
util.session.add(_Parent(self, child))
|
||||||
|
|
||||||
def impl_getchildren(self):
|
def _impl_st_getchildren(self, context, only_dyn=False):
|
||||||
for child in session.query(_Parent).filter_by(parent_id=self.id).all():
|
if only_dyn is False or context is undefined:
|
||||||
yield(session.query(_Base).filter_by(id=child.child_id).first())
|
for child in util.session.query(_Parent).filter_by(
|
||||||
#return
|
parent_id=self.id).all():
|
||||||
|
yield(util.session.query(_Base).filter_by(id=child.child_id
|
||||||
|
).first())
|
||||||
|
else:
|
||||||
|
descr = context.cfgimpl_get_description().id
|
||||||
|
for child in util.session.query(Cache).filter_by(descr=descr,
|
||||||
|
parent=self.id
|
||||||
|
).filter_by(
|
||||||
|
is_subdyn=True).all():
|
||||||
|
yield(util.session.query(_Base).filter_by(id=child.option).first())
|
||||||
|
|
||||||
def __getattr__(self, name):
|
def _getattr(self, name, suffix=undefined, context=undefined, dyn=True):
|
||||||
if name.startswith('_') or name.startswith('impl_'):
|
error = False
|
||||||
return object.__getattribute__(self, name)
|
if suffix is not undefined:
|
||||||
child = session.query(_Parent).filter_by(parent_id=self.id, child_name=name).first()
|
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):
|
||||||
|
oname = name[:-len(suffix)]
|
||||||
|
#child = self._children[1][self._children[0].index(oname)]
|
||||||
|
child = util.session.query(_Parent).filter_by(
|
||||||
|
parent_id=self.id, child_name=oname).first()
|
||||||
if child is None:
|
if child is None:
|
||||||
raise AttributeError(_('unknown Option {0} '
|
error = True
|
||||||
'in OptionDescription {1}'
|
else:
|
||||||
|
opt = util.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:
|
||||||
|
child = util.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 util.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()))
|
'').format(name, self.impl_getname()))
|
||||||
return session.query(_Base).filter_by(id=child.child_id).first()
|
|
||||||
|
def _get_force_store_value(self):
|
||||||
|
#only option in current tree
|
||||||
|
current_ids = tuple(chain(*util.session.query(Cache.option).filter_by(
|
||||||
|
descr=self.id).all()))
|
||||||
|
for prop in util.session.query(_PropertyOption).filter(
|
||||||
|
_PropertyOption.option.in_(current_ids),
|
||||||
|
_PropertyOption.name == 'force_store_value').all():
|
||||||
|
opt = util.session.query(_Base).filter_by(id=prop.option).first()
|
||||||
|
path = self.impl_get_path_by_opt(opt)
|
||||||
|
yield (opt, path)
|
||||||
|
|
||||||
|
|
||||||
class StorageBase(_Base):
|
class StorageBase(_Base):
|
||||||
@declared_attr
|
@declared_attr
|
||||||
def __mapper_args__(self):
|
def __mapper_args__(self):
|
||||||
return {'polymorphic_identity': self.__name__.lower()}
|
return {'polymorphic_identity': self.__name__.lower()}
|
||||||
|
|
||||||
|
|
||||||
#engine.echo = True
|
|
||||||
SqlAlchemyBase.metadata.create_all(engine)
|
|
||||||
Session = sessionmaker(bind=engine)
|
|
||||||
session = Session()
|
|
||||||
|
|
|
@ -80,8 +80,6 @@ class Values(object):
|
||||||
# if value has callback and is not set
|
# if value has callback and is not set
|
||||||
if opt.impl_has_callback():
|
if opt.impl_has_callback():
|
||||||
callback, callback_params = opt.impl_get_callback()
|
callback, callback_params = opt.impl_get_callback()
|
||||||
if callback_params is None:
|
|
||||||
callback_params = {}
|
|
||||||
value = carry_out_calculation(opt, config=self._getcontext(),
|
value = carry_out_calculation(opt, config=self._getcontext(),
|
||||||
callback=callback,
|
callback=callback,
|
||||||
callback_params=callback_params,
|
callback_params=callback_params,
|
||||||
|
@ -126,8 +124,8 @@ class Values(object):
|
||||||
def get_modified_values(self):
|
def get_modified_values(self):
|
||||||
context = self._getcontext()
|
context = self._getcontext()
|
||||||
if context._impl_descr is not None:
|
if context._impl_descr is not None:
|
||||||
for opt, path in context.cfgimpl_get_settings(
|
for opt, path in context.cfgimpl_get_description(
|
||||||
).get_with_property('force_store_value'):
|
)._get_force_store_value():
|
||||||
self._getowner(opt, path, force_permissive=True)
|
self._getowner(opt, path, force_permissive=True)
|
||||||
return self._p_.get_modified_values()
|
return self._p_.get_modified_values()
|
||||||
|
|
||||||
|
@ -554,7 +552,6 @@ class Multi(list):
|
||||||
self)
|
self)
|
||||||
|
|
||||||
#def __repr__(self, *args, **kwargs):
|
#def __repr__(self, *args, **kwargs):
|
||||||
# print args, kwargs
|
|
||||||
# return super(Multi, self).__repr__(*args, **kwargs)
|
# return super(Multi, self).__repr__(*args, **kwargs)
|
||||||
|
|
||||||
#def __getitem__(self, y):
|
#def __getitem__(self, y):
|
||||||
|
|
Loading…
Reference in a new issue