From 93fe29b651ef0c017557333790a4d2a09156934a Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Thu, 16 Nov 2017 21:30:07 +0100 Subject: [PATCH] - add api.owner.get() to get default owner for a context + tests - slave: get length for a specified slave and test - add test for deref objects and default_multi - add issubmulti, getdefault, getdefaultmulti - start metaconfig support in api --- test/api/test_multi.py | 46 +------- test/api/test_owner.py | 244 +++++++++++++++++++++++++++++++---------- tiramisu/__init__.py | 8 +- tiramisu/api.py | 54 +++++++-- tiramisu/config.py | 185 ++++++++++++++++++++++--------- tiramisu/setting.py | 2 +- 6 files changed, 371 insertions(+), 168 deletions(-) diff --git a/test/api/test_multi.py b/test/api/test_multi.py index 6379e1d..9695a0b 100644 --- a/test/api/test_multi.py +++ b/test/api/test_multi.py @@ -177,7 +177,8 @@ def test_callback_submulti_list_list(): cfg = Config(od) cfg.read_write() api = getapi(cfg) - owner = cfg.cfgimpl_get_settings().getowner() + owner = api.owner.get() + assert owner == 'user' assert api.option('multi').value.get() == [['val', 'val']] assert api.option('multi').owner.isdefault() api.option('multi').value.set([['val', 'val'], undefined]) @@ -203,46 +204,3 @@ def test_callback_submulti_list_list(): # multi.append() # assert conf1.multi == [['val', None]] # assert meta.multi == [['val']] - - -# ____________________________________________________________ -# Master Slaves - - -def test_values_with_master_and_slaves_submulti(): - ip_admin_eth0 = StrOption('ip_admin_eth0', "ip reseau autorise", multi=True) - netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-reseau", multi=submulti) - interface1 = MasterSlaves('f_ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0]) - conf = OptionDescription('conf', '', [interface1]) - cfg = Config(conf) - api = getapi(cfg) - cfg.read_write() - owner = cfg.cfgimpl_get_settings().getowner() - #FIXME - assert interface1.impl_get_group_type() == groups.master - assert api.option('f_ip_admin_eth0.ip_admin_eth0').owner.isdefault() - #FIXME raises(IndexError, "api.option('f_ip_admin_eth0.netmask_admin_eth0', 0).value.get()") - api.option('f_ip_admin_eth0.ip_admin_eth0').value.set(['192.168.230.145']) - assert api.option('f_ip_admin_eth0.ip_admin_eth0').value.get() == ['192.168.230.145'] - assert api.option('f_ip_admin_eth0.netmask_admin_eth0', 0).value.get() == [] - #FIXME raises(IndexError, "api.option('f_ip_admin_eth0.netmask_admin_eth0', 1).value.get()") - assert api.option('f_ip_admin_eth0.ip_admin_eth0').owner.get() == owner - assert api.option('f_ip_admin_eth0.netmask_admin_eth0', 0).owner.isdefault() - api.option('f_ip_admin_eth0.ip_admin_eth0').value.set(['192.168.230.145', '192.168.230.147']) - assert api.option('f_ip_admin_eth0.netmask_admin_eth0', 0).value.get() == [] - assert api.option('f_ip_admin_eth0.netmask_admin_eth0', 1).value.get() == [] - #FIXME raises(IndexError, "api.option('f_ip_admin_eth0.netmask_admin_eth0', 2).value.get()") - #FIXME raises(IndexError, "api.option('f_ip_admin_eth0.netmask_admin_eth0', 2).value.set(['255.255.255.0'])") - api.option('f_ip_admin_eth0.netmask_admin_eth0', 0).value.set(['255.255.255.0']) - assert api.option('f_ip_admin_eth0.netmask_admin_eth0', 0).value.get() == ['255.255.255.0'] - assert api.option('f_ip_admin_eth0.netmask_admin_eth0', 1).value.get() == [] - api.option('f_ip_admin_eth0.netmask_admin_eth0', 1).value.set(['255.255.255.255']) - assert api.option('f_ip_admin_eth0.netmask_admin_eth0', 0).value.get() == ['255.255.255.0'] - assert api.option('f_ip_admin_eth0.netmask_admin_eth0', 1).value.get() == ['255.255.255.255'] - assert api.option('f_ip_admin_eth0.ip_admin_eth0').value.get() == ['192.168.230.145', '192.168.230.147'] - raises(ValueError, "api.option('f_ip_admin_eth0.ip_admin_eth0').value.set(['192.168.230.145'])") - api.option('f_ip_admin_eth0.ip_admin_eth0').value.pop(1) - assert api.option('f_ip_admin_eth0.ip_admin_eth0').value.get() == ['192.168.230.145'] - assert api.option('f_ip_admin_eth0.netmask_admin_eth0', 0).value.get() == ['255.255.255.0'] - #FIXME raises(IndexError, "api.option('f_ip_admin_eth0.netmask_admin_eth0', 1).value.get()") - diff --git a/test/api/test_owner.py b/test/api/test_owner.py index e168642..6fa9739 100644 --- a/test/api/test_owner.py +++ b/test/api/test_owner.py @@ -1,20 +1,37 @@ """test API """ +import weakref import pytest from py.test import raises -import weakref from .autopath import do_autopath do_autopath() -from tiramisu import Config, StrOption, OptionDescription, MasterSlaves, DynOptionDescription, \ - getapi +from tiramisu import Config, MetaConfig, \ + StrOption, OptionDescription, MasterSlaves, DynOptionDescription, \ + getapi, submulti, undefined from tiramisu.error import PropertiesOptionError, APIError from collections import OrderedDict ICON = u'\u2937' OPTIONS_TYPE = {'str': {'type': str, 'option': StrOption} - } + } PROPERTIES = ['hidden', 'disabled'] + +OWNER = 'user' + +# multi is False +FIRST_VALUE = 'myvalue' +SECOND_VALUE = 'myvalue1' +EMPTY_VALUE = None +# multi is True +LIST_FIRST_VALUE = ['myvalue'] +LIST_SECOND_VALUE = ['myvalue', 'myvalue1'] +LIST_EMPTY_VALUE = [] +# multi is submulti +SUBLIST_FIRST_VALUE = [['myvalue']] +SUBLIST_SECOND_VALUE = [['myvalue'], ['myvalue1', 'myvalue2']] +SUBLIST_EMPTY_VALUE = [] + DISPLAY = True #DISPLAY = False @@ -94,6 +111,11 @@ def autocheck_owner_without_value(api, path, **kwargs): else: raises(PropertiesOptionError, "api.forcepermissive.option(path).owner.isdefault()") +def _getdefault(api, path, multi, isslave, submulti_): + empty_value = api.unrestraint.option(path).option.getdefault() + if isslave and empty_value == []: + empty_value = api.unrestraint.option(path).option.getdefaultmulti() + return empty_value @autocheck def autocheck_value(api, path, **kwargs): @@ -102,25 +124,27 @@ def autocheck_value(api, path, **kwargs): # check if is a multi, a master or a slave if not kwargs.get('propertyerror', False): multi = api.forcepermissive.option(path).option.ismulti() + submulti_ = api.forcepermissive.option(path).option.issubmulti() ismaster = api.forcepermissive.option(path).option.ismaster() isslave = api.forcepermissive.option(path).option.isslave() else: raises(PropertiesOptionError, "api.forcepermissive.option(path).option.ismulti()") multi = api.unrestraint.option(path).option.ismulti() + submulti_ = api.unrestraint.option(path).option.issubmulti() ismaster = api.unrestraint.option(path).option.ismaster() isslave = api.unrestraint.option(path).option.isslave() # set default value (different if value is multi or not) if not multi: - first_value = 'myvalue' - second_value = 'myvalue1' + first_value = FIRST_VALUE + second_value = SECOND_VALUE + elif submulti_ is False: + first_value = LIST_FIRST_VALUE + second_value = LIST_SECOND_VALUE else: - first_value = ['myvalue'] - second_value = ['myvalue', 'myvalue1'] - if multi and not isslave: - empty_value = [] - else: - empty_value = None + first_value = SUBLIST_FIRST_VALUE + second_value = SUBLIST_SECOND_VALUE + empty_value = _getdefault(api, path, multi, isslave, submulti_) # test default value (should be empty) without permissive # cannot test for slave (we cannot get all values for a slave) @@ -239,23 +263,63 @@ def autocheck_value(api, path, **kwargs): raises(PropertiesOptionError, "api.forcepermissive.option(path).value.get()") +@autocheck +def autocheck_value_slave(api, path, **kwargs): + multi = api.unrestraint.option(path).option.ismulti() + isslave = api.unrestraint.option(path).option.isslave() + if not isslave: + #FIXME verifier pas de len ! + return + if kwargs.get('propertyerror', False): + return + submulti_ = api.forcepermissive.option(path).option.issubmulti() + if not kwargs.get('permissive', False): + length = api.option(path).value.len() + else: + length = api.forcepermissive.option(path).value.len() + assert length == 2 + value = [] + for idx in range(length): + value.append(api.forcepermissive.option(path, idx).value.get()) + if not submulti_: + second_value = LIST_SECOND_VALUE + else: + second_value = SUBLIST_SECOND_VALUE + empty_value = _getdefault(api, path, multi, isslave, submulti_) + assert value == [empty_value, second_value[1]] + # cannot access to a slave with index too high + if submulti_ is False: + value = LIST_FIRST_VALUE[0] + else: + value = SUBLIST_FIRST_VALUE[0] + raises(IndexError, "api.forcepermissive.option(path, length).value.get()") + raises(IndexError, "api.forcepermissive.option(path, length).value.set(value)") + raises(IndexError, "api.forcepermissive.option(path, length).value.reset()") + raises(IndexError, "api.forcepermissive.option(path, length).owner.get()") + raises(IndexError, "api.forcepermissive.option(path, length).owner.isdefault()") + raises(IndexError, "api.forcepermissive.option(path, length).property.get()") + raises(IndexError, "api.forcepermissive.option(path, length).owner.set('new_user')") + raises(IndexError, "api.forcepermissive.option(path, length).property.set(('prop',))") + + @autocheck def autocheck_reset_value(api, path, **kwargs): # check if is a multi, a master or a slave multi = api.unrestraint.option(path).option.ismulti() + submulti_ = api.unrestraint.option(path).option.issubmulti() isslave = api.unrestraint.option(path).option.isslave() # set default value (different if value is multi or not) if not multi: - first_value = 'myvalue' - second_value = 'myvalue1' + first_value = FIRST_VALUE + second_value = SECOND_VALUE + elif submulti_ is False: + first_value = LIST_FIRST_VALUE + second_value = LIST_SECOND_VALUE else: - first_value = ['myvalue'] - second_value = ['myvalue', 'myvalue1'] - if multi and not isslave: - empty_value = [] - else: - empty_value = None + first_value = SUBLIST_FIRST_VALUE + second_value = SUBLIST_SECOND_VALUE + empty_value = _getdefault(api, path, multi, isslave, submulti_) # reset value without permissive if not kwargs.get('permissive', False) and not kwargs.get('propertyerror', False): @@ -332,7 +396,7 @@ def autocheck_display(api, path, **kwargs): """re set value """ #FIXME utile ? - print(api.config) + assert api.config @autocheck @@ -554,13 +618,16 @@ def autocheck_owner_with_value(api, path, **kwargs): raises(PropertiesOptionError, "api.forcepermissive.option(path).option.isslave()") isslave = api.unrestraint.option(path).option.isslave() + owner = api.owner.get() + assert owner == OWNER + # get owner without permissive if not kwargs.get('permissive', False) and not kwargs.get('propertyerror', False): if not isslave: - assert api.option(path).owner.get() == 'user' + assert api.option(path).owner.get() == owner else: - assert api.option(path, 0).owner.get() == 'user' - assert api.option(path, 1).owner.get() == 'user' + assert api.option(path, 0).owner.get() == owner + assert api.option(path, 1).owner.get() == owner else: if not isslave: raises(PropertiesOptionError, "api.option(path).owner.get()") @@ -571,10 +638,10 @@ def autocheck_owner_with_value(api, path, **kwargs): # get owner with permissive if not kwargs.get('propertyerror', False): if not isslave: - assert api.forcepermissive.option(path).owner.get() == 'user' + assert api.forcepermissive.option(path).owner.get() == owner else: assert api.forcepermissive.option(path, 0).owner.get() == 'default' - assert api.forcepermissive.option(path, 1).owner.get() == 'user' + assert api.forcepermissive.option(path, 1).owner.get() == owner else: if not isslave: raises(PropertiesOptionError, "api.forcepermissive.option(path).owner.get()") @@ -628,10 +695,11 @@ def autocheck_set_owner(api, path, **kwargs): assert api.option(path, 1).owner.get() == 'new_user' assert api.forcepermissive.option(path, 1).owner.get() == 'new_user' elif not kwargs.get('propertyerror', False): + owner = api.owner.get() if not isslave: - assert api.forcepermissive.option(path).owner.get() == 'user' + assert api.forcepermissive.option(path).owner.get() == owner else: - assert api.forcepermissive.option(path, 1).owner.get() == 'user' + assert api.forcepermissive.option(path, 1).owner.get() == owner # set owner with permissive if not kwargs.get('propertyerror', False): @@ -691,25 +759,32 @@ def autocheck_permissive(api, path, **kwargs): # check if is a multi, a master or a slave if not kwargs.get('propertyerror', False): multi = api.forcepermissive.option(path).option.ismulti() + submulti_ = api.forcepermissive.option(path).option.issubmulti() ismaster = api.forcepermissive.option(path).option.ismaster() isslave = api.forcepermissive.option(path).option.isslave() else: raises(PropertiesOptionError, "api.forcepermissive.option(path).option.ismulti()") multi = api.unrestraint.option(path).option.ismulti() + submulti_ = api.unrestraint.option(path).option.issubmulti() ismaster = api.unrestraint.option(path).option.ismaster() isslave = api.unrestraint.option(path).option.isslave() # set default value (different if value is multi or not) if not multi: - first_value = 'myvalue' - second_value = 'myvalue1' + first_value = FIRST_VALUE + second_value = SECOND_VALUE + elif submulti_ is False: + first_value = LIST_FIRST_VALUE + second_value = LIST_SECOND_VALUE else: - first_value = ['myvalue'] - second_value = ['myvalue', 'myvalue1'] + first_value = SUBLIST_FIRST_VALUE + second_value = SUBLIST_SECOND_VALUE if multi and not isslave: - empty_value = [] + empty_value = LIST_EMPTY_VALUE + elif submulti_ and isslave: + empty_value = SUBLIST_EMPTY_VALUE else: - empty_value = None + empty_value = EMPTY_VALUE # cannot access to hidden value without forcepermissive # and to disabled value (with forcepermissive too) @@ -765,35 +840,78 @@ def autocheck_permissive(api, path, **kwargs): -def check_all(api, path, multi, **kwargs): +def check_all(api, path, meta, multi, default, default_multi, **kwargs): if DISPLAY: - text = u' {} launch tests for {}'.format(ICON, path) - if multi: + text = u' {} launch tests for {}'.format(ICON, path, multi, default) + if multi is True: text += u' as a multi' + elif multi is submulti: + text += u' as a submulti' + if default is True: + text += u' with default' + if multi is True: + text += u' with default value' + if default_multi is True: + text += u' with default multi' text += u', kwargs: {}'.format(kwargs) print(text) for func in autocheck_registers: if DISPLAY: print(u' {} {}'.format(ICON, func.__name__)) - func(api, path, **kwargs) + try: + func(api, path, **kwargs) + except Exception as err: + msg = u'error in function {} for {}'.format(func.__name__, path) + if multi is True: + msg += u' as a multi' + elif multi is submulti: + msg += u' as a submulti' + if multi is True: + msg += u' with default value' + print(u'{}: {}'.format(msg, kwargs)) + raise err -def make_api(options, multi): +def check_deref(weakrefs): + """try if all elements are dereferenced + """ + for wrf in weakrefs: + assert wrf() is None + + +def make_api(options, meta, multi, default, default_multi): weakrefs = [] def make_option(path, option_infos): #FIXME option_type = 'str' option_properties = [] + isslave = False if option_infos is not None: for prop in PROPERTIES: if option_infos.get(prop, False) is True: option_properties.append(prop) + isslave = option_infos.get('slave', False) args = [path, "{}'s option".format(path)] kwargs = {} if option_properties != []: kwargs['properties'] = tuple(option_properties) if multi: - kwargs['multi'] = True + kwargs['multi'] = multi + if default and not submulti: + if multi is False: + value = FIRST_VALUE + elif multi is True: + value = LIST_FIRST_VALUE + else: + value = SUBLIST_EMPTY_VALUE + kwargs['default'] = value + if default_multi: + if multi is not submulti: + value = SECOND_VALUE + else: + value = LIST_SECOND_VALUE + kwargs['default_multi'] = value + tiramisu_option = OPTIONS_TYPE[option_type]['option'] obj = tiramisu_option(*args, **kwargs) weakrefs.append(weakref.ref(obj)) @@ -849,6 +967,9 @@ def make_api(options, multi): return None, None cfg = Config(rootod, session_id='conftest') weakrefs.append(weakref.ref(cfg)) + if meta: + cfg = MetaConfig([cfg], session_id='metatest') + weakrefs.append(weakref.ref(cfg)) api = getapi(cfg) weakrefs.append(weakref.ref(api)) return api, weakrefs @@ -874,8 +995,8 @@ DICT_PATHS = [ ('subod.subsubod.third', {'third': {'hidden': True}})]), #test a config with masterslaves OrderedDict([('odmaster.first', {'odmaster': {'master': True}}), - ('odmaster.second', {'second': {'disabled': True}}), - ('odmaster.third', {'third': {'hidden': True}})]), + ('odmaster.second', {'second': {'disabled': True, 'slave': True}}), + ('odmaster.third', {'third': {'hidden': True, 'slave': True}})]), ##test a config with dynoption OrderedDict([('subod.first', {'subod': {'dyn': True}}), ('subod.second', {'second': {'disabled': True}}), @@ -940,21 +1061,24 @@ def test_options(paths): return kwargs lpaths = list(paths.keys()) - for multi in (False, True): - api, weakrefs = make_api(paths, multi) - if api is None: - continue - if len(lpaths) == 9: - check_all(api, lpaths[3], multi, **get_kwargs(lpaths[0])) - check_all(api, lpaths[4], multi, **get_kwargs(lpaths[1])) - check_all(api, lpaths[5], multi, **get_kwargs(lpaths[2])) - check_all(api, lpaths[6], multi, **get_kwargs(lpaths[0])) - check_all(api, lpaths[7], multi, **get_kwargs(lpaths[1])) - check_all(api, lpaths[8], multi, **get_kwargs(lpaths[2])) - else: - check_all(api, lpaths[0], multi, **get_kwargs(lpaths[0])) - check_all(api, lpaths[1], multi, **get_kwargs(lpaths[1])) - check_all(api, lpaths[2], multi, **get_kwargs(lpaths[2])) - del(api) - for wr in weakrefs: - assert wr() is None + for meta in (False, True): + for default_multi in (False, True): + for default in (False, True): + for multi in (False, True, submulti): + if multi is False and default_multi: + continue + api, weakrefs = make_api(paths, meta, multi, default, default_multi) + if api is None: + continue + if len(lpaths) == 9: + check_all(api, lpaths[3], meta, multi, default, default_multi, **get_kwargs(lpaths[0])) + check_all(api, lpaths[4], meta, multi, default, default_multi, **get_kwargs(lpaths[1])) + check_all(api, lpaths[5], meta, multi, default, default_multi, **get_kwargs(lpaths[2])) + check_all(api, lpaths[6], meta, multi, default, default_multi, **get_kwargs(lpaths[0])) + check_all(api, lpaths[7], meta, multi, default, default_multi, **get_kwargs(lpaths[1])) + check_all(api, lpaths[8], meta, multi, default, default_multi, **get_kwargs(lpaths[2])) + else: + for lpath in lpaths: + check_all(api, lpath, meta, multi, default, default_multi, **get_kwargs(lpath)) + del api + check_deref(weakrefs) diff --git a/tiramisu/__init__.py b/tiramisu/__init__.py index a1620df..5a7821e 100644 --- a/tiramisu/__init__.py +++ b/tiramisu/__init__.py @@ -12,7 +12,7 @@ # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . -from .config import Config +from .config import Config, MetaConfig from .option import * from .error import APIError from .api import getapi @@ -20,7 +20,11 @@ from .option import __all__ as all_options from .setting import owners, undefined -allfuncs = ['Config', 'getapi', 'APIError', 'undefined'] +allfuncs = ['MetaConfig', + 'Config' + 'getapi', + 'APIError', + 'undefined'] allfuncs.extend(all_options) del(all_options) __all__ = tuple(allfuncs) diff --git a/tiramisu/api.py b/tiramisu/api.py index 7747b91..b848a10 100644 --- a/tiramisu/api.py +++ b/tiramisu/api.py @@ -24,7 +24,7 @@ except: Multi = list -class CommonTiramisu(object): +class CommonTiramisuOption(object): icon = '\u2937' tmpl_help = u' {} {}: {}' allow_unrestraint = False @@ -63,10 +63,10 @@ class CommonTiramisu(object): if name == 'help': return self._help() else: - if not hasattr(CommonTiramisu, name): + if not hasattr(CommonTiramisuOption, name): raise APIError(_('unknown method {}').format(name)) else: - super(CommonTiramisu, self).__getattribute__(name) + super(CommonTiramisuOption, self).__getattribute__(name) def _help(self): txt = [] @@ -78,7 +78,7 @@ class CommonTiramisu(object): return '\n'.join(txt) -class TiramisuOptionOption(CommonTiramisu): +class TiramisuOptionOption(CommonTiramisuOption): """get information from an option""" allow_unrestraint = True slave_need_index = False @@ -104,6 +104,10 @@ class TiramisuOptionOption(CommonTiramisu): def ismulti(self): """test if option could have multi value""" return self.opt.impl_is_multi() + + def issubmulti(self): + """test if option could have submulti value""" + return self.opt.impl_is_submulti() def ismasterslaves(self): """test if option is a master or a slave""" @@ -123,8 +127,14 @@ class TiramisuOptionOption(CommonTiramisu): def getdoc(self): return self.opt.impl_get_display_name() + def getdefault(self): + return self.opt.impl_getdefault() -class TiramisuOptionOwner(CommonTiramisu): + def getdefaultmulti(self): + return self.opt.impl_getdefault_multi() + + +class TiramisuOptionOwner(CommonTiramisuOption): """manager option's owner""" def __init__(self, @@ -170,7 +180,7 @@ class TiramisuOptionOwner(CommonTiramisu): force_permissive=self.force_permissive) -class TiramisuOptionProperty(CommonTiramisu): +class TiramisuOptionProperty(CommonTiramisuOption): """manager option's property""" #allow_unrestraint = True slave_need_index = False @@ -212,7 +222,7 @@ class TiramisuOptionProperty(CommonTiramisu): self.settings.reset(_path=self.path) -class TiramisuOptionPermissive(CommonTiramisu): +class TiramisuOptionPermissive(CommonTiramisuOption): """manager option's property""" allow_unrestraint = True slave_need_index = False @@ -249,8 +259,9 @@ class TiramisuOptionPermissive(CommonTiramisu): # self.settings.reset(_path=path) -class TiramisuOptionValue(CommonTiramisu): +class TiramisuOptionValue(CommonTiramisuOption): """manager option's value""" + slave_need_index = False def __init__(self, opt, @@ -270,6 +281,7 @@ class TiramisuOptionValue(CommonTiramisu): force_unrestraint) def get(self): + self._test_slave_index() settings = self.config.cfgimpl_get_settings() value = self.config.getattr(self.path, index=self.index, @@ -281,6 +293,7 @@ class TiramisuOptionValue(CommonTiramisu): def set(self, value): """set a value for a specified option""" + self._test_slave_index() values = self.config.cfgimpl_get_values() if isinstance(value, list): while undefined in value: @@ -301,6 +314,8 @@ class TiramisuOptionValue(CommonTiramisu): def pop(self, index): """pop value for a specified master values """ + self._test_slave_index() + #FIXME only for master self.config.delattr(self.path, index=index, setting_properties=self.setting_properties, @@ -308,11 +323,20 @@ class TiramisuOptionValue(CommonTiramisu): def reset(self): """reset value for a value""" + self._test_slave_index() self.config.delattr(self.path, index=self.index, setting_properties=self.setting_properties, force_permissive=self.force_permissive) + def len(self): + #FIXME only for slave + subconfig_path = self.path.rsplit('.', 1)[0] + subconfig = self.config.getattr(subconfig_path, + setting_properties=self.setting_properties, + force_permissive=self.force_permissive) + return subconfig.cfgimpl_get_length() + class TiramisuOption(object): icon = '\u2937' @@ -365,6 +389,15 @@ class TiramisuOption(object): raise APIError(_('please specify a valid sub function')) +class TiramisuContext(object): + def __init__(self, config): + self.config = config + +class TiramisuContextOwner(TiramisuContext): + def get(self): + return self.config.cfgimpl_get_settings().getowner() + + class TiramisuAPI(object): icon = '\u2937' tmpl_help = ' {} {}: {}' @@ -385,7 +418,7 @@ class TiramisuAPI(object): def option(self, path, index=None): validate = not self.force_unrestraint settings = self.config.cfgimpl_get_settings() - setting_properties = settings.get_global_properties() + setting_properties = settings.get_context_properties() if validate: s_properties = setting_properties else: @@ -406,6 +439,7 @@ class TiramisuAPI(object): self.force_permissive, self.force_unrestraint) + def __getattr__(self, subfunc): if subfunc == 'forcepermissive': return TiramisuAPI(self.config, @@ -417,6 +451,8 @@ class TiramisuAPI(object): force_unrestraint=True) elif subfunc == 'help': return self._help() + elif subfunc == 'owner': + return TiramisuContextOwner(self.config) else: raise APIError(_('please specify a valid sub function')) diff --git a/tiramisu/config.py b/tiramisu/config.py index debbe9b..bedb881 100644 --- a/tiramisu/config.py +++ b/tiramisu/config.py @@ -87,6 +87,9 @@ class SubConfig(object): validate=validate, force_permissive=force_permissive) + def cfgimpl_get_length(self): + return self._impl_length + def reset_one_option_cache(self, values, settings, resetted_opts, opt, only): if 'values' in only: tresetted_opts = copy(resetted_opts) @@ -401,7 +404,7 @@ class SubConfig(object): raise ret def __getattr__(self, name): - setting_properties = self.cfgimpl_get_context().cfgimpl_get_settings().get_global_properties() + setting_properties = self.cfgimpl_get_context().cfgimpl_get_settings().get_context_properties() return self.getattr(name, setting_properties) def _get_subpath(self, name): @@ -480,9 +483,15 @@ class SubConfig(object): subpath) else: if validate: - ret = self.cfgimpl_get_description().impl_validate(context, - force_permissive, - setting_properties) + self.cfgimpl_get_description().impl_validate(context, + force_permissive, + setting_properties) + if option.impl_is_master_slaves('slave') and index is not None and \ + index >= self._impl_length: + raise IndexError(_('index ({}) is higher than the master length ({}) for "{}"' + '').format(index, + self._impl_length, + subpath)) cfg = self.cfgimpl_get_values().get_cached_value(option, path=subpath, validate=validate, @@ -859,9 +868,14 @@ class Config(_CommonConfig): "main configuration management entry" __slots__ = ('__weakref__', '_impl_test', '_impl_name') - def __init__(self, descr, session_id=None, persistent=False, - force_values=None, force_settings=None, - _duplicate=False, _force_store_values=True): + def __init__(self, + descr, + session_id=None, + persistent=False, + force_values=None, + force_settings=None, + _duplicate=False, + _force_store_values=True): """ Configuration option management master class :param descr: describes the configuration schema @@ -876,17 +890,29 @@ class Config(_CommonConfig): """ if force_settings is not None and force_values is not None: if isinstance(force_settings, tuple): - self._impl_settings = Settings(self, force_settings[0], force_settings[1]) + self._impl_settings = Settings(self, + force_settings[0], + force_settings[1]) else: self._impl_settings = force_settings - self._impl_values = Values(self, force_values) + self._impl_values = Values(self, + force_values) else: - properties, permissives, values, session_id = get_storages(self, session_id, persistent) + properties, permissives, values, session_id = get_storages(self, + session_id, + persistent) if not valid_name(session_id): # pragma: optional cover raise ValueError(_("invalid session ID: {0} for config").format(session_id)) - self._impl_settings = Settings(self, properties, permissives) - self._impl_values = Values(self, values) - super(Config, self).__init__(descr, weakref.ref(self), undefined, True, False) + self._impl_settings = Settings(self, + properties, + permissives) + self._impl_values = Values(self, + values) + super(Config, self).__init__(descr, + weakref.ref(self), + undefined, + True, + False) self._impl_meta = None #undocumented option used only in test script self._impl_test = False @@ -902,15 +928,21 @@ class Config(_CommonConfig): class GroupConfig(_CommonConfig): - __slots__ = ('__weakref__', '_impl_children', '_impl_name') + __slots__ = ('__weakref__', + '_impl_children', + '_impl_name') - def __init__(self, children, session_id=None, persistent=False, + def __init__(self, + children, + session_id=None, + persistent=False, _descr=None): if not isinstance(children, list): raise ValueError(_("groupconfig's children must be a list")) names = [] for child in children: - if not isinstance(child, _CommonConfig): + if not isinstance(child, + _CommonConfig): raise ValueError(_("groupconfig's children must be Config, MetaConfig or GroupConfig")) name_ = child._impl_name names.append(name_) @@ -921,10 +953,18 @@ class GroupConfig(_CommonConfig): raise ConflictError(_('config name must be uniq in ' 'groupconfig for {0}').format(name)) self._impl_children = children - properties, permissives, values, session_id = get_storages(self, session_id, persistent) - self._impl_settings = Settings(self, properties, permissives) + properties, permissives, values, session_id = get_storages(self, + session_id, + persistent) + self._impl_settings = Settings(self, + properties, + permissives) self._impl_values = Values(self, values) - super(GroupConfig, self).__init__(_descr, weakref.ref(self)) + super(GroupConfig, self).__init__(_descr, + weakref.ref(self), + undefined, + True, + False) self._impl_meta = None #undocumented option used only in test script self._impl_test = False @@ -958,11 +998,19 @@ class GroupConfig(_CommonConfig): ret = [] for child in self._impl_children: if isinstance(child, MetaConfig): - ret.extend(child.set_value(path, value, only_config=True, _commit=False)) + ret.extend(child.set_value(path, + value, + only_config=True, + _commit=False)) elif isinstance(child, GroupConfig): - ret.extend(child.set_value(path, value, _commit=False)) + ret.extend(child.set_value(path, + value, + _commit=False)) else: - childret = child.setattr(path, value, not_raises=True, _commit=False) + childret = child.setattr(path, + value, + not_raises=True, + _commit=False) if childret is not None: ret.append(childret) if _commit: @@ -970,8 +1018,13 @@ class GroupConfig(_CommonConfig): return ret - def find_firsts(self, byname=None, bypath=undefined, byoption=undefined, - byvalue=undefined, raise_if_not_found=True, _sub=False, + def find_firsts(self, + byname=None, + bypath=undefined, + byoption=undefined, + byvalue=undefined, + raise_if_not_found=True, + _sub=False, check_properties=True): """Find first not in current GroupConfig, but in each children """ @@ -980,32 +1033,42 @@ class GroupConfig(_CommonConfig): #if MetaConfig, all children have same OptionDescription in context #so search only one time the option for all children if bypath is undefined and byname is not None and \ - isinstance(self, MetaConfig): - bypath = self._find(bytype=None, byvalue=undefined, byname=byname, - first=True, type_='path', + isinstance(self, + MetaConfig): + bypath = self._find(bytype=None, + byvalue=undefined, + byname=byname, + first=True, + type_='path', check_properties=None, raise_if_not_found=raise_if_not_found) byname = None - byoption = self.cfgimpl_get_description( - ).impl_get_opt_by_path(bypath) + byoption = self.cfgimpl_get_description().impl_get_opt_by_path(bypath) for child in self._impl_children: if isinstance(child, GroupConfig): - ret.extend(child.find_firsts(byname=byname, bypath=bypath, + ret.extend(child.find_firsts(byname=byname, + bypath=bypath, byoption=byoption, byvalue=byvalue, check_properties=check_properties, raise_if_not_found=False, _sub=True)) - elif child._find(None, byname, byvalue, first=True, - type_='path', raise_if_not_found=False, + elif child._find(None, + byname, + byvalue, + first=True, + type_='path', + raise_if_not_found=False, check_properties=check_properties, - only_path=bypath, only_option=byoption): + only_path=bypath, + only_option=byoption): ret.append(child) if _sub: return ret else: - return GroupConfig(self._find_return_results(ret, raise_if_not_found)) + return GroupConfig(self._find_return_results(ret, + raise_if_not_found)) def __str__(self): ret = '' @@ -1022,32 +1085,38 @@ class GroupConfig(_CommonConfig): setting_properties, force_permissive=False, validate=True, - index=None, validate_properties=True, + index=None, returns_option=False): for child in self._impl_children: - if name == child._impl_name: + if name == child.impl_getname(): return child - return super(GroupConfig, self).getattr(name, force_permissive, + return super(GroupConfig, self).getattr(name, + setting_properties, + force_permissive, validate, - index=index, - setting_properties=setting_properties, validate_properties=validate_properties, - returns_option=False) + index=index, + returns_option=returns_option) class MetaConfig(GroupConfig): __slots__ = tuple() - def __init__(self, children, session_id=None, persistent=False, - optiondescription=None, _force_store_values=True): + def __init__(self, + children, + session_id=None, + persistent=False, + optiondescription=None, + _force_store_values=True): descr = None if optiondescription is not None: new_children = [] for child_session_id in children: - #FIXME _force_store_values doit etre a true si inexistant ! - new_children.append(Config(optiondescription, persistent=persistent, - session_id=child_session_id, _force_store_values=_force_store_values)) + new_children.append(Config(optiondescription, + persistent=persistent, + session_id=child_session_id, + _force_store_values=_force_store_values)) children = new_children for child in children: if not isinstance(child, _CommonConfig): @@ -1063,12 +1132,19 @@ class MetaConfig(GroupConfig): 'have the same optiondescription')) child._impl_meta = weakref.ref(self) - super(MetaConfig, self).__init__(children, session_id, persistent, + super(MetaConfig, self).__init__(children, + session_id, + persistent, descr) - def set_value(self, path, value, force_default=False, - force_dont_change_value=False, force_default_if_same=False, - only_config=False, _commit=True): + def set_value(self, + path, + value, + force_default=False, + force_dont_change_value=False, + force_default_if_same=False, + only_config=False, + _commit=True): """only_config: could be set if you want modify value in all Config included in this MetaConfig """ @@ -1077,7 +1153,9 @@ class MetaConfig(GroupConfig): raise ValueError(_('force_default, force_default_if_same or ' 'force_dont_change_value cannot be set with' ' only_config')) - return super(MetaConfig, self).set_value(path, value, _commit=_commit) + return super(MetaConfig, self).set_value(path, + value, + _commit=_commit) ret = [] if force_default or force_default_if_same or force_dont_change_value: if force_default and force_dont_change_value: @@ -1134,8 +1212,11 @@ class MetaConfig(GroupConfig): setting_properties, validate=False) - def new_config(self, session_id, persistent=False): - config = Config(self._impl_descr, session_id=session_id, + def new_config(self, + session_id, + persistent=False): + config = Config(self._impl_descr, + session_id=session_id, persistent=persistent) if config._impl_name in [child._impl_name for child in self._impl_children]: # pragma: no cover diff --git a/tiramisu/setting.py b/tiramisu/setting.py index 88a1d0c..900349e 100644 --- a/tiramisu/setting.py +++ b/tiramisu/setting.py @@ -369,7 +369,7 @@ class Settings(object): return Property(self, properties, opt, path) return properties - def get_global_properties(self): + def get_context_properties(self): return self._getproperties() def __setitem__(self, opt, value): # pragma: optional cover