force_store_value is now used directly when configuration is loaded
This commit is contained in:
parent
51d14f30a4
commit
da89c1aa58
8 changed files with 120 additions and 106 deletions
|
@ -1,3 +1,6 @@
|
||||||
|
Mon Mar 7 16:10:30 2016 +0200 Emmanuel Garette <egarette@cadoles.com>
|
||||||
|
* force_store_value is now used directly when configuration is loaded
|
||||||
|
|
||||||
Sun Nov 29 23:01:28 2015 +0200 Emmanuel Garette <egarette@cadoles.com>
|
Sun Nov 29 23:01:28 2015 +0200 Emmanuel Garette <egarette@cadoles.com>
|
||||||
* requires could be apply to a slave and properties could be different
|
* requires could be apply to a slave and properties could be different
|
||||||
|
|
||||||
|
|
|
@ -3,11 +3,13 @@
|
||||||
from autopath import do_autopath
|
from autopath import do_autopath
|
||||||
do_autopath()
|
do_autopath()
|
||||||
|
|
||||||
from tiramisu.setting import owners
|
from py.test import raises
|
||||||
|
|
||||||
|
from tiramisu.setting import owners, groups
|
||||||
from tiramisu.option import ChoiceOption, BoolOption, IntOption, FloatOption, \
|
from tiramisu.option import ChoiceOption, BoolOption, IntOption, FloatOption, \
|
||||||
StrOption, OptionDescription
|
StrOption, OptionDescription
|
||||||
from tiramisu.config import Config
|
from tiramisu.config import Config
|
||||||
from tiramisu.error import PropertiesOptionError
|
from tiramisu.error import PropertiesOptionError, ConfigError
|
||||||
|
|
||||||
|
|
||||||
#____________________________________________________________
|
#____________________________________________________________
|
||||||
|
@ -38,6 +40,18 @@ def make_description_freeze():
|
||||||
return descr
|
return descr
|
||||||
|
|
||||||
|
|
||||||
|
def return_val():
|
||||||
|
return 1
|
||||||
|
|
||||||
|
|
||||||
|
def return_val2(value):
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
def return_val3(context, value):
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
def test_freeze_whole_config():
|
def test_freeze_whole_config():
|
||||||
descr = make_description_freeze()
|
descr = make_description_freeze()
|
||||||
conf = Config(descr)
|
conf = Config(descr)
|
||||||
|
@ -155,9 +169,17 @@ def test_freeze_get_multi():
|
||||||
def test_force_store_value():
|
def test_force_store_value():
|
||||||
descr = make_description_freeze()
|
descr = make_description_freeze()
|
||||||
conf = Config(descr)
|
conf = Config(descr)
|
||||||
assert conf.cfgimpl_get_values()._p_.get_modified_values() == {}
|
assert conf.cfgimpl_get_values()._p_.get_modified_values() == {'wantref': ('forced', False),
|
||||||
conf.wantref
|
'wantref2': ('forced', False),
|
||||||
assert conf.cfgimpl_get_values()._p_.get_modified_values() == {'wantref': ('user', False)}
|
'wantref3': ('forced', [False])}
|
||||||
|
conf.wantref = True
|
||||||
|
assert conf.cfgimpl_get_values()._p_.get_modified_values() == {'wantref': ('user', True),
|
||||||
|
'wantref2': ('forced', False),
|
||||||
|
'wantref3': ('forced', [False])}
|
||||||
|
del(conf.wantref)
|
||||||
|
assert conf.cfgimpl_get_values()._p_.get_modified_values() == {'wantref': ('forced', False),
|
||||||
|
'wantref2': ('forced', False),
|
||||||
|
'wantref3': ('forced', [False])}
|
||||||
|
|
||||||
|
|
||||||
def test_force_store_value_no_requirement():
|
def test_force_store_value_no_requirement():
|
||||||
|
@ -169,87 +191,47 @@ def test_force_store_value_no_requirement():
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def test_force_store_value_ro():
|
def test_force_store_value_masterslaves_slave():
|
||||||
descr = make_description_freeze()
|
b = IntOption('int', 'Test int option', multi=True)
|
||||||
|
c = StrOption('str', 'Test string option', multi=True, properties=('force_store_value',))
|
||||||
|
descr = OptionDescription("int", "", [b, c])
|
||||||
|
descr.impl_set_group_type(groups.master)
|
||||||
|
raises(ConfigError, "conf = Config(descr)")
|
||||||
|
|
||||||
|
|
||||||
|
def test_force_store_value_masterslaves():
|
||||||
|
b = IntOption('int', 'Test int option', multi=True, properties=('force_store_value',))
|
||||||
|
c = StrOption('str', 'Test string option', multi=True)
|
||||||
|
descr = OptionDescription("int", "", [b, c])
|
||||||
|
descr.impl_set_group_type(groups.master)
|
||||||
conf = Config(descr)
|
conf = Config(descr)
|
||||||
conf.read_only()
|
assert conf.cfgimpl_get_values()._p_.get_modified_values() == {'int': ('forced', [])}
|
||||||
assert conf.cfgimpl_get_values()._p_.get_modified_values() == {}
|
|
||||||
conf.wantref
|
|
||||||
assert conf.cfgimpl_get_values()._p_.get_modified_values() == {'wantref': ('user', False)}
|
|
||||||
|
|
||||||
|
|
||||||
def test_force_store_value_hidden():
|
def test_force_store_value_callback():
|
||||||
descr = make_description_freeze()
|
b = IntOption('int', 'Test int option', properties=('force_store_value',), callback=return_val)
|
||||||
|
descr = OptionDescription("int", "", [b])
|
||||||
conf = Config(descr)
|
conf = Config(descr)
|
||||||
conf.cfgimpl_get_settings().setpermissive(('hidden',))
|
assert conf.cfgimpl_get_values()._p_.get_modified_values() == {'int': ('forced', 1)}
|
||||||
conf.read_write()
|
|
||||||
assert conf.cfgimpl_get_values()._p_.get_modified_values() == {}
|
|
||||||
conf.getattr('wantref2', force_permissive=True)
|
|
||||||
assert conf.cfgimpl_get_values()._p_.get_modified_values() == {'wantref2': ('user', False)}
|
|
||||||
|
|
||||||
|
|
||||||
def test_force_store_value_owner():
|
def test_force_store_value_callback_params():
|
||||||
descr = make_description_freeze()
|
b = IntOption('int', 'Test int option', properties=('force_store_value',), callback=return_val2, callback_params={'value': (2,)})
|
||||||
|
descr = OptionDescription("int", "", [b])
|
||||||
conf = Config(descr)
|
conf = Config(descr)
|
||||||
assert conf.cfgimpl_get_values()._p_.get_modified_values() == {}
|
assert conf.cfgimpl_get_values()._p_.get_modified_values() == {'int': ('forced', 2)}
|
||||||
conf.getowner(conf.unwrap_from_path('wantref'))
|
|
||||||
assert conf.cfgimpl_get_values()._p_.get_modified_values() == {'wantref': ('user', False)}
|
|
||||||
|
|
||||||
|
|
||||||
def test_force_store_value_owner_ro():
|
def test_force_store_value_callback_params_2():
|
||||||
descr = make_description_freeze()
|
b = IntOption('int', 'Test int option', properties=('force_store_value',), callback=return_val3, callback_params={'': ((None,),), 'value': (2,)})
|
||||||
|
descr = OptionDescription("int", "", [b])
|
||||||
conf = Config(descr)
|
conf = Config(descr)
|
||||||
conf.read_only()
|
assert conf.cfgimpl_get_values()._p_.get_modified_values() == {'int': ('forced', 2)}
|
||||||
assert conf.cfgimpl_get_values()._p_.get_modified_values() == {}
|
|
||||||
conf.getowner(conf.unwrap_from_path('wantref'))
|
|
||||||
assert conf.cfgimpl_get_values()._p_.get_modified_values() == {'wantref': ('user', False)}
|
|
||||||
|
|
||||||
|
|
||||||
def test_force_store_value_owner_hidden():
|
def test_force_store_value_callback_params_with_opt():
|
||||||
descr = make_description_freeze()
|
a = IntOption('val1', "", 2)
|
||||||
|
b = IntOption('int', 'Test int option', properties=('force_store_value',), callback=return_val2, callback_params={'value': ((a, False),)})
|
||||||
|
descr = OptionDescription("int", "", [a, b])
|
||||||
conf = Config(descr)
|
conf = Config(descr)
|
||||||
conf.cfgimpl_get_settings().setpermissive(('hidden',))
|
assert conf.cfgimpl_get_values()._p_.get_modified_values() == {'int': ('forced', 2)}
|
||||||
conf.read_write()
|
|
||||||
assert conf.cfgimpl_get_values()._p_.get_modified_values() == {}
|
|
||||||
conf.getowner(conf.unwrap_from_path('wantref2'), force_permissive=True)
|
|
||||||
assert conf.cfgimpl_get_values()._p_.get_modified_values() == {'wantref2': ('user', False)}
|
|
||||||
|
|
||||||
|
|
||||||
def test_force_store_value_modified():
|
|
||||||
descr = make_description_freeze()
|
|
||||||
conf = Config(descr)
|
|
||||||
assert conf.cfgimpl_get_values()._p_.get_modified_values() == {}
|
|
||||||
conf.cfgimpl_get_values().get_modified_values()
|
|
||||||
assert conf.cfgimpl_get_values()._p_.get_modified_values() == {
|
|
||||||
'wantref': ('user', False), 'wantref2': ('user', False),
|
|
||||||
'wantref3': ('user', [False])}
|
|
||||||
|
|
||||||
|
|
||||||
def test_force_store_value_modified_ro():
|
|
||||||
descr = make_description_freeze()
|
|
||||||
conf = Config(descr)
|
|
||||||
conf.read_only()
|
|
||||||
assert conf.cfgimpl_get_values()._p_.get_modified_values() == {}
|
|
||||||
conf.cfgimpl_get_values().get_modified_values()
|
|
||||||
assert conf.cfgimpl_get_values()._p_.get_modified_values() == {
|
|
||||||
'wantref': ('user', False), 'wantref2': ('user', False),
|
|
||||||
'wantref3': ('user', [False])}
|
|
||||||
|
|
||||||
|
|
||||||
def test_force_store_value_modified_hidden():
|
|
||||||
descr = make_description_freeze()
|
|
||||||
conf = Config(descr)
|
|
||||||
conf.cfgimpl_get_settings().setpermissive(('hidden',))
|
|
||||||
conf.read_write()
|
|
||||||
assert conf.cfgimpl_get_values()._p_.get_modified_values() == {}
|
|
||||||
conf.cfgimpl_get_values().get_modified_values()
|
|
||||||
assert conf.cfgimpl_get_values()._p_.get_modified_values() == {
|
|
||||||
'wantref': ('user', False), 'wantref2': ('user', False),
|
|
||||||
'wantref3': ('user', [False])}
|
|
||||||
|
|
||||||
|
|
||||||
def test_force_store_value_multi():
|
|
||||||
descr = make_description_freeze()
|
|
||||||
conf = Config(descr)
|
|
||||||
conf.read_write()
|
|
||||||
assert conf.getowner(conf.unwrap_from_path('wantref3')) == 'user'
|
|
||||||
|
|
|
@ -540,8 +540,8 @@ class _CommonConfig(SubConfig):
|
||||||
def _impl_build_all_caches(self):
|
def _impl_build_all_caches(self):
|
||||||
descr = self.cfgimpl_get_description()
|
descr = self.cfgimpl_get_description()
|
||||||
if not descr.impl_already_build_caches():
|
if not descr.impl_already_build_caches():
|
||||||
descr.impl_build_cache()
|
|
||||||
descr.impl_build_cache_option()
|
descr.impl_build_cache_option()
|
||||||
|
descr.impl_build_cache(self)
|
||||||
|
|
||||||
def read_only(self):
|
def read_only(self):
|
||||||
"read only is a global config's setting, see `settings.py`"
|
"read only is a global config's setting, see `settings.py`"
|
||||||
|
@ -685,10 +685,10 @@ class Config(_CommonConfig):
|
||||||
self._impl_settings = Settings(self, settings)
|
self._impl_settings = Settings(self, settings)
|
||||||
self._impl_values = Values(self, values)
|
self._impl_values = Values(self, values)
|
||||||
super(Config, self).__init__(descr, weakref.ref(self))
|
super(Config, self).__init__(descr, weakref.ref(self))
|
||||||
self._impl_build_all_caches()
|
|
||||||
self._impl_meta = None
|
self._impl_meta = None
|
||||||
#undocumented option used only in test script
|
#undocumented option used only in test script
|
||||||
self._impl_test = False
|
self._impl_test = False
|
||||||
|
self._impl_build_all_caches()
|
||||||
self._impl_name = name
|
self._impl_name = name
|
||||||
|
|
||||||
def cfgimpl_reset_cache(self,
|
def cfgimpl_reset_cache(self,
|
||||||
|
|
|
@ -304,7 +304,7 @@ class BaseOption(Base):
|
||||||
"frozen" (which has noting to do with the high level "freeze"
|
"frozen" (which has noting to do with the high level "freeze"
|
||||||
propertie or "read_only" property)
|
propertie or "read_only" property)
|
||||||
"""
|
"""
|
||||||
if name not in ('_option', '_is_build_cache') and \
|
if name != '_option' and \
|
||||||
not isinstance(value, tuple) and \
|
not isinstance(value, tuple) and \
|
||||||
not name.startswith('_state') and \
|
not name.startswith('_state') and \
|
||||||
not name == '_sa_instance_state':
|
not name == '_sa_instance_state':
|
||||||
|
|
|
@ -23,7 +23,7 @@ import re
|
||||||
|
|
||||||
|
|
||||||
from ..i18n import _
|
from ..i18n import _
|
||||||
from ..setting import groups, undefined # , log
|
from ..setting import groups, undefined, owners # , log
|
||||||
from .baseoption import BaseOption, SymLinkOption
|
from .baseoption import BaseOption, SymLinkOption
|
||||||
from . import MasterSlaves
|
from . import MasterSlaves
|
||||||
from ..error import ConfigError, ConflictError
|
from ..error import ConfigError, ConflictError
|
||||||
|
@ -92,26 +92,35 @@ class OptionDescription(BaseOption, StorageOptionDescription):
|
||||||
"""
|
"""
|
||||||
return _impl_getpaths(self, include_groups, _currpath)
|
return _impl_getpaths(self, include_groups, _currpath)
|
||||||
|
|
||||||
def impl_build_cache(self, _consistencies=None, cache_option=None):
|
def impl_build_cache(self, config, path='', _consistencies=None,
|
||||||
|
cache_option=None, force_store_values=None):
|
||||||
"""validate duplicate option and set option has readonly option
|
"""validate duplicate option and set option has readonly option
|
||||||
"""
|
"""
|
||||||
if cache_option is None:
|
if cache_option is None:
|
||||||
init = True
|
init = True
|
||||||
_consistencies = {}
|
_consistencies = {}
|
||||||
cache_option = []
|
cache_option = []
|
||||||
|
force_store_values = []
|
||||||
else:
|
else:
|
||||||
init = False
|
init = False
|
||||||
for option in self._impl_getchildren(dyn=False):
|
for option in self._impl_getchildren(dyn=False):
|
||||||
#FIXME specifique id for sqlalchemy?
|
#FIXME specifique id for sqlalchemy?
|
||||||
#FIXME avec sqlalchemy ca marche le multi parent ? (dans des configs différentes)
|
#FIXME avec sqlalchemy ca marche le multi parent ? (dans des configs différentes)
|
||||||
cache_option.append(option._get_id())
|
cache_option.append(option._get_id())
|
||||||
|
if path == '':
|
||||||
|
subpath = option.impl_getname()
|
||||||
|
else:
|
||||||
|
subpath = path + '.' + option.impl_getname()
|
||||||
if isinstance(option, OptionDescription):
|
if isinstance(option, OptionDescription):
|
||||||
option._set_readonly(False)
|
option._set_readonly(False)
|
||||||
option.impl_build_cache(_consistencies, cache_option)
|
option.impl_build_cache(config, subpath, _consistencies,
|
||||||
|
cache_option, force_store_values)
|
||||||
#cannot set multi option as OptionDescription requires
|
#cannot set multi option as OptionDescription requires
|
||||||
else:
|
else:
|
||||||
option._set_readonly(True)
|
option._set_readonly(True)
|
||||||
is_multi = option.impl_is_multi()
|
is_multi = option.impl_is_multi()
|
||||||
|
if 'force_store_value' in option.impl_getproperties():
|
||||||
|
force_store_values.append((subpath, option))
|
||||||
for func, all_cons_opts, params in option._get_consistencies():
|
for func, all_cons_opts, params in option._get_consistencies():
|
||||||
option._valid_consistencies(all_cons_opts[1:])
|
option._valid_consistencies(all_cons_opts[1:])
|
||||||
if is_multi:
|
if is_multi:
|
||||||
|
@ -175,6 +184,21 @@ class OptionDescription(BaseOption, StorageOptionDescription):
|
||||||
opt.impl_getname()))
|
opt.impl_getname()))
|
||||||
self._cache_consistencies[opt] = tuple(cons)
|
self._cache_consistencies[opt] = tuple(cons)
|
||||||
self._set_readonly(False)
|
self._set_readonly(False)
|
||||||
|
for subpath, option in force_store_values:
|
||||||
|
value = config.cfgimpl_get_values()._get_cached_value(option,
|
||||||
|
path=subpath,
|
||||||
|
validate=False,
|
||||||
|
trusted_cached_properties=False,
|
||||||
|
validate_properties=True)
|
||||||
|
if option.impl_is_master_slaves('slave'):
|
||||||
|
# problem with index
|
||||||
|
raise ConfigError(_('a slave ({0}) cannot have '
|
||||||
|
'force_store_value property').format(subpath))
|
||||||
|
if option._is_subdyn():
|
||||||
|
raise ConfigError(_('a dynoption ({0}) cannot have '
|
||||||
|
'force_store_value property').format(subpath))
|
||||||
|
config._impl_values._p_.setvalue(subpath, value,
|
||||||
|
owners.forced, None)
|
||||||
|
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
def impl_set_group_type(self, group_type):
|
def impl_set_group_type(self, group_type):
|
||||||
|
|
|
@ -214,6 +214,7 @@ def populate_owners():
|
||||||
"""
|
"""
|
||||||
setattr(owners, 'default', owners.DefaultOwner('default'))
|
setattr(owners, 'default', owners.DefaultOwner('default'))
|
||||||
setattr(owners, 'user', owners.Owner('user'))
|
setattr(owners, 'user', owners.Owner('user'))
|
||||||
|
setattr(owners, 'forced', owners.Owner('forced'))
|
||||||
|
|
||||||
def addowner(name):
|
def addowner(name):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -38,6 +38,9 @@ class Values(Cache):
|
||||||
"""
|
"""
|
||||||
values = []
|
values = []
|
||||||
vidx = None
|
vidx = None
|
||||||
|
if index is None:
|
||||||
|
# raise Exception('arf')
|
||||||
|
pass
|
||||||
|
|
||||||
def _setvalue_info(nb, idx, value, vidx):
|
def _setvalue_info(nb, idx, value, vidx):
|
||||||
lst = list(self._values[nb])
|
lst = list(self._values[nb])
|
||||||
|
|
|
@ -103,9 +103,8 @@ class Values(object):
|
||||||
value = opt.impl_getdefault_multi()
|
value = opt.impl_getdefault_multi()
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def _getvalue(self, opt, path, is_default, self_properties,
|
def _getvalue(self, opt, path, self_properties, index, submulti_index,
|
||||||
index=undefined, submulti_index=undefined, with_meta=True,
|
with_meta, masterlen):
|
||||||
masterlen=undefined, returns_raise=False):
|
|
||||||
"""actually retrieves the value
|
"""actually retrieves the value
|
||||||
|
|
||||||
:param opt: the `option.Option()` object
|
:param opt: the `option.Option()` object
|
||||||
|
@ -114,6 +113,11 @@ class Values(object):
|
||||||
force_default = 'frozen' in self_properties and \
|
force_default = 'frozen' in self_properties and \
|
||||||
'force_default_on_freeze' in self_properties
|
'force_default_on_freeze' in self_properties
|
||||||
# not default value
|
# not default value
|
||||||
|
is_default = self._is_default_owner(opt, path,
|
||||||
|
validate_properties=False,
|
||||||
|
validate_meta=False,
|
||||||
|
self_properties=self_properties,
|
||||||
|
index=index)
|
||||||
if not is_default and not force_default:
|
if not is_default and not force_default:
|
||||||
if opt.impl_is_master_slaves('slave'):
|
if opt.impl_is_master_slaves('slave'):
|
||||||
return self._p_.getvalue(path, index)
|
return self._p_.getvalue(path, index)
|
||||||
|
@ -126,7 +130,8 @@ class Values(object):
|
||||||
#so return default value
|
#so return default value
|
||||||
else:
|
else:
|
||||||
return value
|
return value
|
||||||
return self._getdefaultvalue(opt, path, with_meta, index, submulti_index, returns_raise)
|
return self._getdefaultvalue(opt, path, with_meta, index,
|
||||||
|
submulti_index, True)
|
||||||
|
|
||||||
def get_modified_values(self):
|
def get_modified_values(self):
|
||||||
context = self._getcontext()
|
context = self._getcontext()
|
||||||
|
@ -172,6 +177,14 @@ class Values(object):
|
||||||
if opt.impl_is_master_slaves('master'):
|
if opt.impl_is_master_slaves('master'):
|
||||||
opt.impl_get_master_slaves().reset(opt, self, _setting_properties)
|
opt.impl_get_master_slaves().reset(opt, self, _setting_properties)
|
||||||
if hasvalue:
|
if hasvalue:
|
||||||
|
if 'force_store_value' in setting._getproperties(opt=opt,
|
||||||
|
path=path,
|
||||||
|
setting_properties=_setting_properties,
|
||||||
|
read_write=False,
|
||||||
|
apply_requires=False):
|
||||||
|
value = self._getdefaultvalue(opt, path, True, undefined, undefined, False)
|
||||||
|
self._setvalue(opt, path, value, force_owner=owners.forced)
|
||||||
|
else:
|
||||||
self._p_.resetvalue(path)
|
self._p_.resetvalue(path)
|
||||||
context.cfgimpl_reset_cache()
|
context.cfgimpl_reset_cache()
|
||||||
|
|
||||||
|
@ -300,17 +313,9 @@ class Values(object):
|
||||||
setting_properties = setting._getproperties(read_write=False)
|
setting_properties = setting._getproperties(read_write=False)
|
||||||
if self_properties is undefined:
|
if self_properties is undefined:
|
||||||
self_properties = setting._getproperties(opt, path, read_write=False, index=index)
|
self_properties = setting._getproperties(opt, path, read_write=False, index=index)
|
||||||
is_default = self._is_default_owner(opt, path,
|
|
||||||
validate_properties=False,
|
|
||||||
validate_meta=False,
|
|
||||||
self_properties=self_properties,
|
|
||||||
index=index)
|
|
||||||
config_error = None
|
config_error = None
|
||||||
value = self._getvalue(opt, path, is_default, self_properties,
|
value = self._getvalue(opt, path, self_properties, index, submulti_index,
|
||||||
index=index, submulti_index=submulti_index,
|
with_meta, masterlen)
|
||||||
with_meta=with_meta,
|
|
||||||
masterlen=masterlen,
|
|
||||||
returns_raise=True)
|
|
||||||
if isinstance(value, Exception):
|
if isinstance(value, Exception):
|
||||||
if isinstance(value, ConfigError):
|
if isinstance(value, ConfigError):
|
||||||
# For calculating properties, we need value (ie for mandatory
|
# For calculating properties, we need value (ie for mandatory
|
||||||
|
@ -351,13 +356,6 @@ class Values(object):
|
||||||
config_error = err
|
config_error = err
|
||||||
value = None
|
value = None
|
||||||
|
|
||||||
if is_default and 'force_store_value' in self_properties:
|
|
||||||
if isinstance(value, Multi):
|
|
||||||
item = list(value)
|
|
||||||
else:
|
|
||||||
item = value
|
|
||||||
self.setitem(opt, item, path, check_frozen=False,
|
|
||||||
force_permissive=force_permissive)
|
|
||||||
if validate_properties:
|
if validate_properties:
|
||||||
if config_error is not None:
|
if config_error is not None:
|
||||||
# should not raise PropertiesOptionError if option is
|
# should not raise PropertiesOptionError if option is
|
||||||
|
@ -407,10 +405,13 @@ class Values(object):
|
||||||
raise err
|
raise err
|
||||||
self._setvalue(opt, path, value)
|
self._setvalue(opt, path, value)
|
||||||
|
|
||||||
def _setvalue(self, opt, path, value):
|
def _setvalue(self, opt, path, value, force_owner=undefined):
|
||||||
context = self._getcontext()
|
context = self._getcontext()
|
||||||
context.cfgimpl_reset_cache()
|
context.cfgimpl_reset_cache()
|
||||||
|
if force_owner is undefined:
|
||||||
owner = context.cfgimpl_get_settings().getowner()
|
owner = context.cfgimpl_get_settings().getowner()
|
||||||
|
else:
|
||||||
|
owner = force_owner
|
||||||
# in storage, value must not be a multi
|
# in storage, value must not be a multi
|
||||||
if isinstance(value, Multi):
|
if isinstance(value, Multi):
|
||||||
value = list(value)
|
value = list(value)
|
||||||
|
|
Loading…
Reference in a new issue