better support for sqlalchemy storage

This commit is contained in:
Emmanuel Garette 2014-07-06 15:31:57 +02:00
parent 3cc2d9ca3d
commit 71f8926fca
16 changed files with 369 additions and 241 deletions

View file

@ -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")

View file

@ -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']"]

View file

@ -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)

View file

@ -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',)

View file

@ -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):

View file

@ -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,

View file

@ -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

View file

@ -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)}

View file

@ -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

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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

View file

@ -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)

View file

@ -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()

View file

@ -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):