From 5eb2f04202e184a48c56dea4fee05d85f9519525 Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Tue, 10 Apr 2018 12:33:51 +0200 Subject: [PATCH] find in api return an api object --- test/auto/test_auto.py | 5 +- test/test_config_api.py | 157 +++++++++++++----------- test/test_dyn_optiondescription.py | 23 +++- test/test_masterslaves.py | 2 +- test/test_metaconfig.py | 18 +-- test/test_option_setting.py | 6 +- test/test_symlink.py | 18 +++ tiramisu/api.py | 62 ++++++++-- tiramisu/config.py | 157 ++++++++---------------- tiramisu/option/dynoptiondescription.py | 5 +- tiramisu/option/optiondescription.py | 68 +++++----- tiramisu/storage/dictionary/setting.py | 12 +- tiramisu/storage/dictionary/value.py | 14 +-- 13 files changed, 280 insertions(+), 267 deletions(-) diff --git a/test/auto/test_auto.py b/test/auto/test_auto.py index 0ff0767..a1309e1 100644 --- a/test/auto/test_auto.py +++ b/test/auto/test_auto.py @@ -1074,6 +1074,7 @@ def autocheck_option_get(api, pathread, pathwrite, confread, confwrite, **kwargs @autocheck def autocheck_find(api, pathread, pathwrite, confread, confwrite, **kwargs): def _getoption(opt): + opt = opt.option.get() if opt.impl_is_dynsymlinkoption(): opt = opt.impl_getopt() return opt @@ -1088,7 +1089,7 @@ def autocheck_find(api, pathread, pathwrite, confread, confwrite, **kwargs): name = pathread.rsplit('.', 1)[1] else: name = pathread - option = _getoption(api.unrestraint.option(pathread).option.get()) + option = _getoption(api.unrestraint.option(pathread)) def do(conf): if not kwargs.get('permissive', False) and not kwargs.get('propertyerror', False): @@ -1102,8 +1103,6 @@ def autocheck_find(api, pathread, pathwrite, confread, confwrite, **kwargs): raises(AttributeError, "api.forcepermissive.config(conf).option.find(name, first=True)") assert option == _getoption(api.unrestraint.config(conf).option.find(name, first=True)) assert [option] == _getoptions(api.unrestraint.config(conf).option.find(name)) - assert pathread == api.unrestraint.config(conf).option.find(name, 'path', first=True) - assert [pathread] == api.unrestraint.config(conf).option.find(name, 'path') do(confread) if confread != confwrite: do(confwrite) diff --git a/test/test_config_api.py b/test/test_config_api.py index 6d15b9b..1da2b68 100644 --- a/test/test_config_api.py +++ b/test/test_config_api.py @@ -14,8 +14,8 @@ from tiramisu.error import PropertiesOptionError def make_description(): gcoption = ChoiceOption('name', 'GC name', ('ref', 'framework'), 'ref') gcdummy = BoolOption('dummy', 'dummy', default=False) - prop = BoolOption('prop', '', properties=('disabled',)) - prop2 = BoolOption('prop', '', properties=('hidden',)) + prop = BoolOption('prop', 'prop 1', properties=('disabled',)) + prop2 = BoolOption('prop', 'prop 2', properties=('hidden',)) objspaceoption = ChoiceOption('objspace', 'Object space', ('std', 'thunk'), 'std') booloption = BoolOption('bool', 'Test boolean option', default=True) @@ -165,96 +165,111 @@ def test_find_in_config(): api.permissive.set(frozenset(['hidden'])) ret = api.option.find('dummy') assert len(ret) == 1 - _is_same_opt(ret[0], api.option('gc.dummy').option.get()) + _is_same_opt(ret[0].option.get(), api.option('gc.dummy').option.get()) # - ret = api.option.find('dummy', first=True) + ret = api.option.find('dummy', first=True).option.get() _is_same_opt(ret, api.option('gc.dummy').option.get()) # ret = api.option.find('float') assert len(ret) == 2 - _is_same_opt(ret[0], api.option('gc.float').option.get()) - _is_same_opt(ret[1], api.option('float').option.get()) + _is_same_opt(ret[0].option.get(), api.option('gc.float').option.get()) + _is_same_opt(ret[1].option.get(), api.option('float').option.get()) # - _is_same_opt(api.option.find('bool', first=True), api.option('gc.gc2.bool').option.get()) - #_is_same_opt(conf.find_first(byname='bool', byvalue=True), conf.unwrap_from_path('bool')) - #_is_same_opt(conf.find_first(byname='dummy'), conf.unwrap_from_path('gc.dummy')) - #_is_same_opt(conf.find_first(byname='float'), conf.unwrap_from_path('gc.float')) + _is_same_opt(api.option.find('bool', first=True).option.get(), api.option('gc.gc2.bool').option.get()) + _is_same_opt(api.option.find('bool', value=True, first=True).option.get(), api.option('bool').option.get()) + _is_same_opt(api.option.find('dummy', first=True).option.get(), api.option('gc.dummy').option.get()) + _is_same_opt(api.option.find('float', first=True).option.get(), api.option('gc.float').option.get()) + #FIXME cannot find an option without name #ret = conf.find(bytype=ChoiceOption) #assert len(ret) == 2 #_is_same_opt(ret[0], conf.unwrap_from_path('gc.name')) #_is_same_opt(ret[1], conf.unwrap_from_path('objspace')) + # #_is_same_opt(conf.find_first(bytype=ChoiceOption), conf.unwrap_from_path('gc.name')) #ret = conf.find(byvalue='ref') #assert len(ret) == 1 #_is_same_opt(ret[0], conf.unwrap_from_path('gc.name')) #_is_same_opt(conf.find_first(byvalue='ref'), conf.unwrap_from_path('gc.name')) - #ret = conf.find(byname='prop') - #assert len(ret) == 1 - #_is_same_opt(ret[0], conf.unwrap_from_path('gc.prop')) - #conf.read_write() - #raises(AttributeError, "assert conf.find(byname='prop')") - #ret = conf.find(byname='prop', check_properties=False) - #assert len(ret) == 2 - #_is_same_opt(ret[0], conf.cfgimpl_get_description().impl_get_opt_by_path('gc.gc2.prop')) - #_is_same_opt(ret[1], conf.unwrap_from_path('gc.prop', force_permissive=True)) - #ret = conf.find(byname='prop', force_permissive=True) - #assert len(ret) == 1 - #_is_same_opt(ret[0], conf.unwrap_from_path('gc.prop', force_permissive=True)) - #_is_same_opt(conf.find_first(byname='prop', force_permissive=True), conf.unwrap_from_path('gc.prop', force_permissive=True)) - ##assert conf.find_first(byname='prop') == conf.unwrap_from_path('gc.prop') - ## combinaison of filters + # + ret = api.option.find('prop') + assert len(ret) == 1 + _is_same_opt(ret[0].option.get(), api.option('gc.prop').option.get()) + # + api.property.read_write() + raises(AttributeError, "assert api.option.find('prop').option.get()") + ret = api.unrestraint.option.find(name='prop') + assert len(ret) == 2 + _is_same_opt(ret[0].option.get(), api.unrestraint.option('gc.gc2.prop').option.get()) + _is_same_opt(ret[1].option.get(), api.forcepermissive.option('gc.prop').option.get()) + # + ret = api.forcepermissive.option.find('prop') + assert len(ret) == 1 + _is_same_opt(ret[0].option.get(), api.forcepermissive.option('gc.prop').option.get()) + # + _is_same_opt(api.forcepermissive.option.find('prop', first=True).option.get(), api.forcepermissive.option('gc.prop').option.get()) + #FIXME cannot find an option without name + # combinaison of filters #ret = conf.find(bytype=BoolOption, byname='dummy') #assert len(ret) == 1 #_is_same_opt(ret[0], conf.unwrap_from_path('gc.dummy')) #_is_same_opt(conf.find_first(bytype=BoolOption, byname='dummy'), conf.unwrap_from_path('gc.dummy')) - #ret = conf.find(byvalue=False, byname='dummy') - #assert len(ret) == 1 - #_is_same_opt(ret[0], conf.unwrap_from_path('gc.dummy')) - #_is_same_opt(conf.find_first(byvalue=False, byname='dummy'), conf.unwrap_from_path('gc.dummy')) - ##subconfig - #ret = conf.gc.find(byname='dummy') - #assert len(ret) == 1 - #_is_same_opt(ret[0], conf.unwrap_from_path('gc.dummy')) - #ret = conf.gc.find(byname='float') - #assert len(ret) == 1 - #_is_same_opt(ret[0], conf.unwrap_from_path('gc.float')) - #ret = conf.gc.find(byname='bool') - #assert len(ret) == 1 - #_is_same_opt(ret[0], conf.unwrap_from_path('gc.gc2.bool')) - #_is_same_opt(conf.gc.find_first(byname='bool', byvalue=False), conf.unwrap_from_path('gc.gc2.bool')) - #raises(AttributeError, "assert conf.gc.find_first(byname='bool', byvalue=True)") - #raises(AttributeError, "conf.gc.find(byname='wantref').first()") - #ret = conf.gc.find(byname='prop', check_properties=False) - #assert len(ret) == 2 - #_is_same_opt(ret[0], conf.cfgimpl_get_description().impl_get_opt_by_path('gc.gc2.prop')) - #_is_same_opt(ret[1], conf.unwrap_from_path('gc.prop', force_permissive=True)) - #conf.read_only() - #ret = conf.gc.find(byname='prop') - #assert len(ret) == 1 - #_is_same_opt(ret[0], conf.unwrap_from_path('gc.prop')) - ## not OptionDescription - #raises(AttributeError, "conf.find_first(byname='gc')") - #raises(AttributeError, "conf.gc.find_first(byname='gc2')") - #raises(ValueError, "conf.find(byname='bool', type_='unknown')") + # + ret = api.option.find('dummy', value=False) + assert len(ret) == 1 + _is_same_opt(ret[0].option.get(), api.option('gc.dummy').option.get()) + # + _is_same_opt(api.option.find('dummy', value=False, first=True).option.get(), api.option('gc.dummy').option.get()) + #subconfig + ret = api.option('gc').find('dummy') + assert len(ret) == 1 + _is_same_opt(ret[0].option.get(), api.option('gc.dummy').option.get()) + # + ret = api.option('gc').find('float') + assert len(ret) == 1 + _is_same_opt(ret[0].option.get(), api.option('gc.float').option.get()) + # + ret = api.option('gc').find('bool') + assert len(ret) == 1 + _is_same_opt(ret[0].option.get(), api.option('gc.gc2.bool').option.get()) + _is_same_opt(api.option('gc').find('bool', value=False, first=True).option.get(), api.option('gc.gc2.bool').option.get()) + # + raises(AttributeError, "assert api.option('gc').find('bool', value=True, first=True).option.get()") + # + raises(AttributeError, "api.option('gc').find('wantref').option.get()") + # + ret = api.unrestraint.option('gc').find('prop') + assert len(ret) == 2 + _is_same_opt(ret[0].option.get(), api.unrestraint.option('gc.gc2.prop').option.get()) + _is_same_opt(ret[1].option.get(), api.forcepermissive.option('gc.prop').option.get()) + # + api.property.read_only() + ret = api.option('gc').find('prop') + assert len(ret) == 1 + _is_same_opt(ret[0].option.get(), api.option('gc.prop').option.get()) + # not OptionDescription + raises(AttributeError, "api.option.find('gc', first=True)") + raises(AttributeError, "api.option.find('gc2', first=True)") -#def test_find_multi(): -# b = BoolOption('bool', '', multi=True) -# o = OptionDescription('od', '', [b]) -# conf = Config(o) -# raises(AttributeError, "conf.find(byvalue=True)") -# raises(AttributeError, "conf.find_first(byvalue=True)") -# conf.bool.append(False) -# raises(AttributeError, "conf.find(byvalue=True)") -# raises(AttributeError, "conf.find_first(byvalue=True)") -# conf.bool.append(False) -# raises(AttributeError, "conf.find(byvalue=True)") -# raises(AttributeError, "conf.find_first(byvalue=True)") -# conf.bool.append(True) -# ret = conf.find(byvalue=True) -# assert len(ret) == 1 -# _is_same_opt(ret[0], b) -# _is_same_opt(conf.find_first(byvalue=True), b) +def test_find_multi(): + b = BoolOption('bool', '', multi=True) + o = OptionDescription('od', '', [b]) + conf = Config(o) + api = getapi(conf) + # + raises(AttributeError, "api.option.find('bool', value=True)") + raises(AttributeError, "api.option.find('bool', value=True, first=True)") + api.option('bool').value.set([False]) + raises(AttributeError, "api.option.find('bool', value=True)") + raises(AttributeError, "api.option.find('bool', value=True, first=True)") + api.option('bool').value.set([False, False]) + raises(AttributeError, "api.option.find('bool', value=True)") + raises(AttributeError, "api.option.find('bool', value=True, first=True)") + api.option('bool').value.set([False, False, True]) + ret = api.option.find('bool', value=True) + assert len(ret) == 1 + _is_same_opt(ret[0].option.get(), b) + _is_same_opt(api.option.find('bool', value=True, first=True).option.get(), b) def test_does_not_find_in_config(): diff --git a/test/test_dyn_optiondescription.py b/test/test_dyn_optiondescription.py index 6c7d7f3..ae7a581 100644 --- a/test/test_dyn_optiondescription.py +++ b/test/test_dyn_optiondescription.py @@ -36,7 +36,7 @@ def return_list(val=None, suffix=None): return ['val1', 'val2'] -def return_same_list(suffix): +def return_same_list(*args, **kwargs): return ['val1', 'val1'] @@ -48,6 +48,10 @@ def return_raise(suffix): raise Exception('error') +def return_str(*args, **kwargs): + return 'str' + + def test_build_dyndescription(): st1 = StrOption('st', '') dod = DynOptionDescription('dod', '', [st1], callback=return_list) @@ -66,6 +70,15 @@ def test_build_dyndescription_raise(): raises(ConfigError, "api.option.make_dict()") +def test_build_dyndescription_not_list(): + st1 = StrOption('st', '') + dod = DynOptionDescription('dod', '', [st1], callback=return_str) + od1 = OptionDescription('od', '', [dod]) + cfg = Config(od1) + api = getapi(cfg) + raises(ValueError, "api.option.make_dict()") + + def test_subpath_dyndescription(): st1 = StrOption('st', '') dod = DynOptionDescription('dod', '', [st1], callback=return_list) @@ -492,9 +505,7 @@ def test_requires_dyndescription(): assert api.option('od.dodval1.stval1').value.get() is None assert api.option('od.dodval2.stval2').value.get() is None # - print('-----------------') api.option('boolean').value.set(False) - print('-----------------') props = [] try: api.option('od.dodval1.stval1').value.get() @@ -608,8 +619,8 @@ def test_find_dyndescription_context(): od2 = OptionDescription('od', '', [od]) api = getapi(Config(od2)) api.option('od.dodval1.stval1').value.set('yes') - assert api.option.find('stval1', type='value', first=True) == "yes" - assert isinstance(api.option.find('stval1', type='option', first=True), DynSymLinkOption) + assert api.option.find('stval1', first=True).value.get() == "yes" + assert isinstance(api.option.find('stval1', first=True).option.get(), DynSymLinkOption) #assert api.option.find(bytype=StrOption, type='path') == ['od.dodval1.stval1', 'od.dodval2.stval2', 'od.val1'] #opts = api.option.find(byvalue='yes') #assert len(opts) == 1 @@ -1185,7 +1196,7 @@ def test_invalid_samevalue_dyndescription(): od1 = OptionDescription('od', '', [dod]) cfg = Config(od1) api = getapi(cfg) - raises(ConfigError, "api.option.make_dict()") + raises(ValueError, "api.option.make_dict()") def test_invalid_name_dyndescription(): diff --git a/test/test_masterslaves.py b/test/test_masterslaves.py index 9307273..f406454 100644 --- a/test/test_masterslaves.py +++ b/test/test_masterslaves.py @@ -52,7 +52,7 @@ def test_base_config(): api.property.read_write() assert api.option('creole.general.activer_proxy_client').value.get() is False assert api.option('creole.general.nom_machine').value.get() == "eoleng" - assert api.option.find('nom_machine', type='value', first=True) == "eoleng" + assert api.option.find('nom_machine', first=True).value.get() == "eoleng" result = {'general.numero_etab': None, 'general.nombre_interfaces': 1, 'general.serveur_ntp': [], 'interface1.ip_admin_eth0.ip_admin_eth0': None, 'general.mode_conteneur_actif': False, 'general.time_zone': 'Paris', diff --git a/test/test_metaconfig.py b/test/test_metaconfig.py index 2e2a359..8020552 100644 --- a/test/test_metaconfig.py +++ b/test/test_metaconfig.py @@ -126,8 +126,10 @@ def test_contexts(): def test_find(): api = make_metaconfig() - assert [1] == api.option.find('i2', type='value') - assert 1 == api.option.find('i2', type='value', first=True) + ret = api.option.find('i2') + assert len(ret) == 1 + assert 1 == ret[0].value.get() + assert 1 == api.option.find('i2', first=True).value.get() assert api.option.make_dict() == {'od1.i4': 2, 'od1.i1': None, 'od1.i3': None, 'od1.i2': 1, 'od1.i5': [2]} @@ -203,14 +205,14 @@ def test_meta_meta_set(): conf1 = meta.getconfig('conf1') conf2 = meta.getconfig('conf2') assert api.config('meta.conf1').option('od1.i1').value.get() == api.config('meta.conf2').option('od1.i1').value.get() == 7 - assert [conf1, conf2] == api.config.find('i1', byvalue=7, first=True).cfgimpl_get_children() + assert [conf1, conf2] == api.config.find('i1', value=7, first=True).cfgimpl_get_children() api.config('meta.conf1').option('od1.i1').value.set(8) assert [conf1, conf2] == api.config.find('i1', first=True).cfgimpl_get_children() - assert [conf2] == api.config.find('i1', byvalue=7, first=True).cfgimpl_get_children() - assert [conf1] == api.config.find('i1', byvalue=8, first=True).cfgimpl_get_children() - assert [conf1, conf2] == api.config.find('i5', byvalue=2, first=True).cfgimpl_get_children() - raises(AttributeError, "api.config.find('i1', byvalue=10, first=True)") - raises(AttributeError, "api.config.find('not', byvalue=10, first=True)") + assert [conf2] == api.config.find('i1', value=7, first=True).cfgimpl_get_children() + assert [conf1] == api.config.find('i1', value=8, first=True).cfgimpl_get_children() + assert [conf1, conf2] == api.config.find('i5', value=2, first=True).cfgimpl_get_children() + raises(AttributeError, "api.config.find('i1', value=10, first=True)") + raises(AttributeError, "api.config.find('not', value=10, first=True)") raises(AttributeError, "api.config.find('i6', first=True)") raises(ValueError, "api.value.set('od1.i6', 7, only_config=True, force_default=True)") raises(ValueError, "api.value.set('od1.i6', 7, only_config=True, force_default_if_same=True)") diff --git a/test/test_option_setting.py b/test/test_option_setting.py index e568a7a..0f5361a 100644 --- a/test/test_option_setting.py +++ b/test/test_option_setting.py @@ -384,8 +384,8 @@ def test_access_by_get(): descr = make_description() api = getapi(Config(descr)) raises(AttributeError, "api.option.find('idontexist')") - assert api.option.find('wantref', type='value', first=True) is False - assert api.option.find('dummy', type='value', first=True) is False + assert api.option.find('wantref', first=True).value.get() is False + assert api.option.find('dummy', first=True).value.get() is False def test_access_by_get_whith_hide(): @@ -398,7 +398,7 @@ def test_access_by_get_whith_hide(): BoolOption("d1", "")]) api = getapi(Config(descr)) api.property.read_write() - raises(AttributeError, "api.option.find('b1', type='value')") + raises(AttributeError, "api.option.find('b1').value.get()") def test_append_properties(): diff --git a/test/test_symlink.py b/test/test_symlink.py index 93ae320..2f83351 100644 --- a/test/test_symlink.py +++ b/test/test_symlink.py @@ -35,6 +35,24 @@ def test_symlink_option(): assert api.option('c').value.get() is False +def test_symlink_assign_option(): + boolopt = BoolOption("b", "", default=False) + linkopt = SymLinkOption("c", boolopt) + descr = OptionDescription("opt", "", + [linkopt, OptionDescription("s1", "", [boolopt])]) + api = getapi(Config(descr)) + raises(ConfigError, "api.option('c').value.set(True)") + + +def test_symlink_del_option(): + boolopt = BoolOption("b", "", default=False) + linkopt = SymLinkOption("c", boolopt) + descr = OptionDescription("opt", "", + [linkopt, OptionDescription("s1", "", [boolopt])]) + api = getapi(Config(descr)) + raises(TypeError, "api.option('c').value.reset()") + + def test_symlink_getproperties(): boolopt = BoolOption('b', '', default=True, properties=('test',)) linkopt = SymLinkOption("c", boolopt) diff --git a/tiramisu/api.py b/tiramisu/api.py index 25744e6..2940224 100644 --- a/tiramisu/api.py +++ b/tiramisu/api.py @@ -628,6 +628,8 @@ class TiramisuOption(CommonTiramisu): self.config_bag) elif subfunc == 'make_dict' and self._get_option().impl_is_optiondescription(): return self._make_dict + elif subfunc == 'find' and self._get_option().impl_is_optiondescription(): + return self._find elif subfunc == 'list' and self._get_option().impl_is_optiondescription(): return self._list elif subfunc == 'group_type' and self._get_option().impl_is_optiondescription(): @@ -650,6 +652,32 @@ class TiramisuOption(CommonTiramisu): withoption=withoption, withvalue=withvalue) + def _find(self, + name, + value=undefined, + first=False): + """find an option by name (only for optiondescription)""" + if not first: + ret = [] + for path in self.config_bag.config.find(byname=name, + byvalue=value, + bytype=None, + type_='path', + _subpath=self.path, + config_bag=self.config_bag): + config_bag = self.config_bag.copy('nooption') + subconfig, name = config_bag.config.cfgimpl_get_home_by_path(path, + config_bag) + t_option = TiramisuOption(name, + path, + None, # index for a slave ? + subconfig, + config_bag) + if first: + return t_option + ret.append(t_option) + return ret + @count def _group_type(self): """get type for an optiondescription (only for optiondescription)""" @@ -864,17 +892,29 @@ class TiramisuContextOption(TiramisuContext): @count def find(self, name, - type='option', + value=undefined, first=False): """find an option by name""" - if first: - return self.config_bag.config.find_first(byname=name, - type_=type, - config_bag=self.config_bag) - else: - return self.config_bag.config.find(byname=name, - type_=type, - config_bag=self.config_bag) + if not first: + ret = [] + for path in self.config_bag.config.find(byname=name, + byvalue=value, + bytype=None, + type_='path', + #_subpath=self.path, + config_bag=self.config_bag): + config_bag = self.config_bag.copy('nooption') + subconfig, name = config_bag.config.cfgimpl_get_home_by_path(path, + config_bag) + t_option = TiramisuOption(name, + path, + None, # index for a slave ? + subconfig, + config_bag) + if first: + return t_option + ret.append(t_option) + return ret #@count #def get(self, path): @@ -928,12 +968,12 @@ class TiramisuContextConfig(TiramisuContext): """configuration methods""" def find(self, name, - byvalue=undefined, + value=undefined, first=False): """find a path from option name and optionnaly a value to MetaConfig or GroupConfig""" if first: return self.config_bag.config.find_firsts(byname=name, - byvalue=byvalue, + byvalue=value, config_bag=self.config_bag) else: raise APIError('not implemented yet') diff --git a/tiramisu/config.py b/tiramisu/config.py index da8493f..d76d4b2 100644 --- a/tiramisu/config.py +++ b/tiramisu/config.py @@ -381,62 +381,15 @@ class SubConfig(object): return value def find(self, + bytype, + byname, + byvalue, config_bag, - bytype=None, - byname=None, - byvalue=undefined, - type_='option'): - """ - finds a list of options recursively in the config - - :param bytype: Option class (BoolOption, StrOption, ...) - :param byname: filter by Option.impl_getname() - :param byvalue: filter by the option's value - :returns: list of matching Option objects - """ - return self.cfgimpl_get_context()._find(bytype, - byname, - byvalue, - config_bag, - first=False, - type_=type_, - _subpath=self.cfgimpl_get_path(False)) - - def find_first(self, - config_bag, - bytype=None, - byname=None, - byvalue=undefined, - type_='option', - raise_if_not_found=True): - """ - finds an option recursively in the config - - :param bytype: Option class (BoolOption, StrOption, ...) - :param byname: filter by Option.impl_getname() - :param byvalue: filter by the option's value - :returns: list of matching Option objects - """ - return self.cfgimpl_get_context()._find(bytype, - byname, - byvalue, - config_bag, - first=True, - type_=type_, - _subpath=self.cfgimpl_get_path(False), - raise_if_not_found=raise_if_not_found) - - def _find(self, - bytype, - byname, - byvalue, - config_bag, - first, - type_='option', - _subpath=None, - raise_if_not_found=True, - only_path=undefined, - only_option=undefined): + type_='option', + _subpath=None, + raise_if_not_found=True, + only_path=undefined, + only_option=undefined): """ convenience method for finding an option that lives only in the subtree @@ -459,20 +412,14 @@ class SubConfig(object): if type_ not in ('option', 'path', 'value'): # pragma: optional cover raise ValueError(_('unknown type_ type {0}' - 'for _find').format(type_)) - find_results = [] - # if value and/or validate_properties are set, need all avalaible option - # If first one has no good value or not good property check second one - # and so on - only_first = first is True and byvalue is undefined and \ - config_bag.validate_properties is False + 'for find').format(type_)) + found = False if only_path is not undefined: options = [(only_path, only_option)] else: options = self.cfgimpl_get_description().impl_get_options_paths(bytype, byname, _subpath, - only_first, config_bag) for path, option in options: sconfig_bag = config_bag.copy('nooption') @@ -480,39 +427,34 @@ class SubConfig(object): if not _filter_by_value(sconfig_bag): continue #remove option with propertyerror, ... - if config_bag.validate_properties: + if sconfig_bag.validate_properties: try: self.unwrap_from_path(path, - config_bag) + sconfig_bag) self.cfgimpl_get_settings().validate_properties(path, None, - config_bag) + sconfig_bag) except PropertiesOptionError: continue if type_ == 'value': retval = self.getattr(path, None, - config_bag) + sconfig_bag) elif type_ == 'path': retval = path elif type_ == 'option': retval = option - if first: - return retval - else: - find_results.append(retval) - return self._find_return_results(find_results, + found = True + yield retval + return self._find_return_results(found, raise_if_not_found) def _find_return_results(self, - find_results, + found, raise_if_not_found): - if find_results == []: # pragma: optional cover - if raise_if_not_found: - raise AttributeError(_("no option found in config" - " with these criteria")) - else: - return find_results + if not found and raise_if_not_found: + raise AttributeError(_("no option found in config" + " with these criteria")) def make_dict(self, config_bag, @@ -565,13 +507,12 @@ class SubConfig(object): "option")) context = self.cfgimpl_get_context() if withoption is not None: - for path in context._find(bytype=None, - byname=withoption, - byvalue=withvalue, - first=False, - type_='path', - _subpath=self.cfgimpl_get_path(False), - config_bag=config_bag): + for path in context.find(bytype=None, + byname=withoption, + byvalue=withvalue, + type_='path', + _subpath=self.cfgimpl_get_path(False), + config_bag=config_bag): path = '.'.join(path.split('.')[:-1]) opt = context.unwrap_from_path(path, config_bag) @@ -946,23 +887,21 @@ class GroupConfig(_CommonConfig): _sub=False): """Find first not in current GroupConfig, but in each children """ - ret = [] - #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, - config_bag=config_bag, - type_='path', - raise_if_not_found=raise_if_not_found) + bypath = next(self.find(bytype=None, + byvalue=undefined, + byname=byname, + config_bag=config_bag, + type_='path', + raise_if_not_found=raise_if_not_found)) byname = None byoption = self.cfgimpl_get_description().impl_get_opt_by_path(bypath) + ret = [] for child in self._impl_children: nconfig_bag = config_bag.copy('nooption') nconfig_bag.option = child @@ -974,21 +913,25 @@ class GroupConfig(_CommonConfig): config_bag=config_bag, raise_if_not_found=False, _sub=True)) - elif child._find(None, - byname, - byvalue, - first=True, - type_='path', - config_bag=config_bag, - raise_if_not_found=False, - only_path=bypath, - only_option=byoption): - ret.append(child) + else: + try: + next(child.find(None, + byname, + byvalue, + type_='path', + config_bag=config_bag, + raise_if_not_found=False, + only_path=bypath, + only_option=byoption)) + ret.append(child) + except StopIteration: + pass if _sub: return ret else: - return GroupConfig(self._find_return_results(ret, - raise_if_not_found)) + self._find_return_results(ret != [], + raise_if_not_found) + return GroupConfig(ret) def impl_getname(self): return self._impl_name diff --git a/tiramisu/option/dynoptiondescription.py b/tiramisu/option/dynoptiondescription.py index 127c7d8..536c397 100644 --- a/tiramisu/option/dynoptiondescription.py +++ b/tiramisu/option/dynoptiondescription.py @@ -81,9 +81,8 @@ class DynOptionDescription(OptionDescription): None, config_bag) if not isinstance(values, list): - raise ValueError(_('invalid suffix "{}" for option "{}", must be a list' - '').format(values, - self.impl_get_display_name())) + raise ValueError(_('DynOptionDescription callback for option "{}", is not a list ({})' + '').format(self.impl_get_display_name(), values)) if len(values) > len(set(values)): raise ValueError(_('DynOptionDescription callback return not unique value')) for val in values: diff --git a/tiramisu/option/optiondescription.py b/tiramisu/option/optiondescription.py index 6f103e5..b7b40a1 100644 --- a/tiramisu/option/optiondescription.py +++ b/tiramisu/option/optiondescription.py @@ -19,6 +19,7 @@ # the whole pypy projet is under MIT licence # ____________________________________________________________ from copy import copy +from itertools import chain from ..i18n import _ @@ -254,74 +255,61 @@ class OptionDescriptionWalk(CacheOptionDescription): bytype, byname, _subpath, - only_first, config_bag): - find_results = [] + def _filter_by_type(path, + option): + if isinstance(option, + bytype): + if byname is None: + if option.issubdyn(): + for doption in self.build_dynoptions(option, config_bag): + dpath = doption.impl_getname(config_bag.config) + yield (dpath, doption) + else: + yield (path, option) def _filter_by_name(path, option): name = option.impl_getname() if option.issubdyn(): - found = False if byname.startswith(name): for doption in self.build_dynoptions(option, config_bag): if byname == doption.impl_getname(): dpath = doption.impl_getpath(config_bag.config) - find_results.append((dpath, doption)) - found = True + yield (dpath, doption) break - if not found: - return False else: - if not byname == name: - return False - find_results.append((path, option)) - return True - - def _filter_by_type(path, - option): - if isinstance(option, - bytype): - #if byname is not None, check option byname in _filter_by_name - #not here - if byname is None: - if option.issubdyn(): - for doption in self.build_dynoptions(option, config_bag): - dpath = doption.impl_getname(config_bag.config) - find_results.append((dpath, doption)) - else: - find_results.append((path, option)) - return True - return False + if byname == name: + yield (path, option) def _filter(path, option): + generators = [] if bytype is not None: - retval = _filter_by_type(path, option) - if byname is None: - return retval + generators.append(_filter_by_type(path, option)) if byname is not None: - return _filter_by_name(path, option) + generators.append(_filter_by_name(path, option)) + if len(generators) == 1: + return generators[0] + else: + return chain(*generators) opts, paths = self._cache_paths - for index, path in enumerate(paths): - option = opts[index] + for index, option in enumerate(opts): if option.impl_is_optiondescription(): continue + path = paths[index] if _subpath is not None and not path.startswith(_subpath + '.'): continue if bytype == byname is None: if option.issubdyn(): for doption in self.build_dynoptions(option, config_bag): dpath = doption.impl_getpath(config_bag.config) - find_results.append((dpath, doption)) + yield (dpath, doption) else: - find_results.append((dpath, option)) + yield (dpath, option) else: - if _filter(path, option) is False: - continue - if only_first: - return find_results - return find_results + for ret in _filter(path, option): + yield ret def impl_getchild(self, name, diff --git a/tiramisu/storage/dictionary/setting.py b/tiramisu/storage/dictionary/setting.py index bde7b00..9bd0cf0 100644 --- a/tiramisu/storage/dictionary/setting.py +++ b/tiramisu/storage/dictionary/setting.py @@ -34,23 +34,23 @@ class Properties(Cache): # properties def setproperties(self, path, properties): - if DEBUG: + if DEBUG: # pragma: no cover print('setproperties', path, properties) self._properties[path] = properties def getproperties(self, path, default_properties): ret = self._properties.get(path, frozenset(default_properties)) - if DEBUG: + if DEBUG: # pragma: no cover print('getproperties', path, ret) return ret def reset_all_properties(self): - if DEBUG: + if DEBUG: # pragma: no cover print('reset_all_properties') self._properties.clear() def delproperties(self, path): - if DEBUG: + if DEBUG: # pragma: no cover print('delproperties', path) if path in self._properties: del(self._properties[path]) @@ -74,7 +74,7 @@ class Permissives(Cache): super(Permissives, self).__init__(storage) def setpermissive(self, path, permissive): - if DEBUG: + if DEBUG: # pragma: no cover print('setpermissive', path, permissive) if not permissive: if path in self._permissives: @@ -84,7 +84,7 @@ class Permissives(Cache): def getpermissive(self, path=None): ret = self._permissives.get(path, frozenset()) - if DEBUG: + if DEBUG: # pragma: no cover print('getpermissive', path, ret) return ret diff --git a/tiramisu/storage/dictionary/value.py b/tiramisu/storage/dictionary/value.py index fb99482..38bc739 100644 --- a/tiramisu/storage/dictionary/value.py +++ b/tiramisu/storage/dictionary/value.py @@ -75,7 +75,7 @@ class Values(Cache): """set value for a path a specified value must be associated to an owner """ - if DEBUG: + if DEBUG: # pragma: no cover print('setvalue', path, value, owner, index, id(self)) values = [] vidx = None @@ -97,9 +97,7 @@ class Values(Cache): return: boolean """ has_path = path in self._values[0] - if path.startswith('subod.subodval'): - raise Exception('arf ...') - if DEBUG: + if DEBUG: # pragma: no cover print('hasvalue', path, index, has_path, id(self)) if index is None: return has_path @@ -113,7 +111,7 @@ class Values(Cache): """ _values == ((path1, path2), ((idx1_1, idx1_2), None), ((value1_1, value1_2), value2), ((owner1_1, owner1_2), owner2)) """ - if DEBUG: + if DEBUG: # pragma: no cover print('reduce_index', path, index, id(self)) path_idx = self._values[0].index(path) indexes = self._values[1][path_idx] @@ -128,7 +126,7 @@ class Values(Cache): self._values = tuple(values) def resetvalue_index(self, path, index): - if DEBUG: + if DEBUG: # pragma: no cover print('resetvalue_index', path, index, id(self)) def _resetvalue(nb): values_idx = list(values[nb]) @@ -161,7 +159,7 @@ class Values(Cache): def resetvalue(self, path, commit): """remove value means delete value in storage """ - if DEBUG: + if DEBUG: # pragma: no cover print('resetvalue', path, id(self)) def _resetvalue(nb): lst = list(self._values[nb]) @@ -211,7 +209,7 @@ class Values(Cache): with_value) if owner is undefined: owner = default - if DEBUG: + if DEBUG: # pragma: no cover print('getvalue', path, index, value, owner, id(self)) if with_value: return owner, value