diff --git a/test/test_config.py b/test/test_config.py index 6db3fcf..8de8a57 100644 --- a/test/test_config.py +++ b/test/test_config.py @@ -6,10 +6,11 @@ import autopath from py.test import raises -from tiramisu.config import Config +from tiramisu.config import Config, SubConfig from tiramisu.option import IntOption, FloatOption, StrOption, ChoiceOption, \ BoolOption, UnicodeOption, OptionDescription from tiramisu.error import ConflictError, ConfigError +import weakref def make_description(): @@ -294,3 +295,26 @@ def test_delete_config_with_subconfig(): raises(ConfigError, 'val[multi]') raises(ConfigError, 'setting[test]') raises(ConfigError, 'sub.make_dict()') + + +def test_config_weakref(): + o = OptionDescription('val', '', []) + o2 = OptionDescription('val', '', [o]) + c = Config(o2) + SubConfig(o, weakref.ref(c)) + raises(ValueError, "SubConfig(o, c)") + s = SubConfig(o, weakref.ref(c)) + assert s._cfgimpl_get_context() == c + del(c) + raises(ConfigError, "s._cfgimpl_get_context()") + + +def test_config_str(): + gcdummy = BoolOption('dummy', 'dummy', default=False) + gcdummy1 = BoolOption('dummy1', 'dummy', default=False, properties=('disabled',)) + o = OptionDescription('o', '', [gcdummy, gcdummy1]) + descr = OptionDescription('tiramisu', '', [o]) + cfg = Config(descr) + cfg.read_only() + str(cfg) + str(cfg.o) diff --git a/test/test_config_api.py b/test/test_config_api.py index f0681ea..4be9e80 100644 --- a/test/test_config_api.py +++ b/test/test_config_api.py @@ -4,26 +4,34 @@ from py.test import raises from tiramisu.config import Config from tiramisu.option import IntOption, FloatOption, StrOption, ChoiceOption, \ - BoolOption, FilenameOption, OptionDescription + BoolOption, FilenameOption, UnicodeOption, SymLinkOption, IPOption, \ + PortOption, NetworkOption, NetmaskOption, BroadcastOption, \ + DomainnameOption, OptionDescription +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',)) objspaceoption = ChoiceOption('objspace', 'Object space', ('std', 'thunk'), 'std') booloption = BoolOption('bool', 'Test boolean option', default=True) + booloption2 = BoolOption('bool', 'Test boolean option', default=False) intoption = IntOption('int', 'Test int option', default=0) + floatoption2 = FloatOption('float', 'Test float option', default=2.3) floatoption = FloatOption('float', 'Test float option', default=2.3) stroption = StrOption('str', 'Test string option', default="abc") boolop = BoolOption('boolop', 'Test boolean option op', default=True) wantref_option = BoolOption('wantref', 'Tests', default=False) wantframework_option = BoolOption('wantframework', 'Test', default=False) - gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, floatoption]) + gcgroup2 = OptionDescription('gc2', '', [booloption2, prop]) + gcgroup = OptionDescription('gc', '', [gcgroup2, gcoption, gcdummy, floatoption, prop2]) descr = OptionDescription('tiramisu', '', [gcgroup, booloption, objspaceoption, wantref_option, stroption, wantframework_option, - intoption, boolop]) + intoption, boolop, floatoption2]) return descr @@ -62,6 +70,17 @@ def test_iter_config(): [('string', 'string'), ('string2', 'string2')] +def test_iter_config_property(): + "iteration on config object" + s = StrOption("string", "", default="string", properties=('disabled',)) + s2 = StrOption("string2", "", default="string2") + descr = OptionDescription("options", "", [s, s2]) + config = Config(descr) + config.read_only() + assert [(name, value) for name, value in config] == \ + [('string2', 'string2')] + + def test_iter_subconfig(): "iteration on config sub object" descr = make_description() @@ -100,20 +119,41 @@ def test_find_in_config(): "finds option in config" descr = make_description() conf = Config(descr) + conf.read_only() assert conf.find(byname='dummy') == [conf.unwrap_from_path('gc.dummy')] + assert conf.find(byname='float') == [conf.unwrap_from_path('gc.float'), conf.unwrap_from_path('float')] + assert conf.find_first(byname='bool') == conf.unwrap_from_path('gc.gc2.bool') + assert conf.find_first(byname='bool', byvalue=True) == conf.unwrap_from_path('bool') assert conf.find_first(byname='dummy') == conf.unwrap_from_path('gc.dummy') + assert conf.find_first(byname='float') == conf.unwrap_from_path('gc.float') assert conf.find(bytype=ChoiceOption) == [conf.unwrap_from_path('gc.name'), conf.unwrap_from_path('objspace')] assert conf.find_first(bytype=ChoiceOption) == conf.unwrap_from_path('gc.name') assert conf.find(byvalue='ref') == [conf.unwrap_from_path('gc.name')] assert conf.find_first(byvalue='ref') == conf.unwrap_from_path('gc.name') + assert conf.find(byname='prop') == [conf.unwrap_from_path('gc.prop')] + conf.read_write() + raises(AttributeError, "assert conf.find(byname='prop')") + assert conf.find(byname='prop', check_properties=False) == [conf.unwrap_from_path('gc.gc2.prop'), conf.unwrap_from_path('gc.prop')] + #assert conf.find_first(byname='prop') == conf.unwrap_from_path('gc.prop') # combinaison of filters assert conf.find(bytype=BoolOption, byname='dummy') == [conf.unwrap_from_path('gc.dummy')] assert conf.find_first(bytype=BoolOption, byname='dummy') == conf.unwrap_from_path('gc.dummy') assert conf.find(byvalue=False, byname='dummy') == [conf.unwrap_from_path('gc.dummy')] assert conf.find_first(byvalue=False, byname='dummy') == conf.unwrap_from_path('gc.dummy') - ## byattrs - #assert conf.find_first(byattrs= dict(default=2.3)) == conf.unwrap_from_path('gc.float') - #assert conf.find_first(byvalue=False, byname='dummy', byattrs=dict(default=False)) == conf.unwrap_from_path('gc.dummy') + #subconfig + assert conf.gc.find(byname='dummy') == [conf.unwrap_from_path('gc.dummy')] + assert conf.gc.find(byname='float') == [conf.unwrap_from_path('gc.float')] + assert conf.gc.find(byname='bool') == [conf.unwrap_from_path('gc.gc2.bool')] + assert 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()") + assert conf.gc.find(byname='prop', check_properties=False) == [conf.unwrap_from_path('gc.gc2.prop'), conf.unwrap_from_path('gc.prop')] + conf.read_only() + assert conf.gc.find(byname='prop') == [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')") def test_find_multi(): @@ -152,3 +192,66 @@ def test_filename(): c.a = u'tmp/text.txt' raises(ValueError, "c.a = u'/tmp/with space.txt'") raises(ValueError, "c.a = u'/tmp/with$.txt'") + + +def test_iter_all(): + s = StrOption("string", "", default="string") + s2 = StrOption("string2", "", default="string2") + descr = OptionDescription("options", "", [s, s2]) + config = Config(descr) + assert list(config.iter_all()) == [('string', 'string'), ('string2', 'string2')] + for i in config.iter_all(): + #test StopIteration + break + + +def test_iter_all_prop(): + s = StrOption("string", "", default="string", properties=('disabled',)) + s2 = StrOption("string2", "", default="string2") + descr = OptionDescription("options", "", [s, s2]) + config = Config(descr) + config.read_only() + assert list(config.iter_all()) == [('string2', 'string2')] + + +def test_impl_getpaths(): + s = StrOption("string", "", default="string", properties=('disabled',)) + s2 = StrOption("string2", "", default="string2") + s3 = StrOption("string3", "", default="string3") + s4 = StrOption("string4", "", default="string4", properties=('hidden',)) + od = OptionDescription('od', '', [s3, s4]) + descr = OptionDescription("options", "", [s, s2, od]) + config = Config(descr) + assert ['string', 'string2', 'od.string3', 'od.string4'] == config.cfgimpl_get_description().impl_getpaths() + assert ['string', 'string2', 'od', 'od.string3', 'od.string4'] == config.cfgimpl_get_description().impl_getpaths(include_groups=True) + config.read_write() + raises(PropertiesOptionError, "config.od.string4") + assert ['string', 'string2', 'od.string3', 'od.string4'] == config.cfgimpl_get_description().impl_getpaths() + assert ['string', 'string2', 'od', 'od.string3', 'od.string4'] == config.cfgimpl_get_description().impl_getpaths(include_groups=True) + + +def test_invalid_option(): + raises(TypeError, "ChoiceOption('a', '', [1, 2])") + raises(TypeError, "ChoiceOption('a', '', 1)") + raises(TypeError, "ChoiceOption('a', '', (1,), open_values='string')") + raises(ValueError, "ChoiceOption('a', '', (1,), 3)") + raises(ValueError, "FloatOption('a', '', 'string')") + raises(ValueError, "UnicodeOption('a', '', 1)") + raises(ValueError, "SymLinkOption('a', 'string')") + raises(ValueError, "IPOption('a', '', 1)") + raises(ValueError, "IPOption('a', '', 'string')") + raises(ValueError, "PortOption('a', '', 'string')") + raises(ValueError, "PortOption('a', '', '11:12:13', allow_range=True)") + raises(ValueError, "PortOption('a', '', 11111111111111111111)") + raises(ValueError, "PortOption('a', '', allow_zero=True, allow_wellknown=False, allow_registred=True, allow_private=False)") + raises(ValueError, "PortOption('a', '', allow_zero=True, allow_wellknown=True, allow_registred=False, allow_private=True)") + raises(ValueError, "PortOption('a', '', allow_zero=True, allow_wellknown=False, allow_registred=False, allow_private=True)") + raises(ValueError, "PortOption('a', '', allow_zero=True, allow_wellknown=False, allow_registred=True, allow_private=True)") + raises(ValueError, "PortOption('a', '', allow_zero=False, allow_wellknown=False, allow_registred=False, allow_private=False)") + raises(ValueError, "NetworkOption('a', '', 'string')") + raises(ValueError, "NetmaskOption('a', '', 'string')") + raises(ValueError, "BroadcastOption('a', '', 'string')") + raises(ValueError, "DomainnameOption('a', '', 'string')") + raises(ValueError, "DomainnameOption('a', '', type_='string')") + raises(ValueError, "DomainnameOption('a', '', allow_ip='string')") + raises(ValueError, "DomainnameOption('a', '', allow_without_dot='string')") diff --git a/test/test_config_domain.py b/test/test_config_domain.py index 9fd9ed3..bcae92a 100644 --- a/test/test_config_domain.py +++ b/test/test_config_domain.py @@ -7,9 +7,9 @@ from tiramisu.option import DomainnameOption, EmailOption, URLOption, OptionDesc def test_domainname(): d = DomainnameOption('d', '') - e = DomainnameOption('e', '', "toto.com") f = DomainnameOption('f', '', allow_without_dot=True) - od = OptionDescription('a', '', [d, f]) + g = DomainnameOption('g', '', allow_ip=True) + od = OptionDescription('a', '', [d, f, g]) c = Config(od) c.read_write() c.d = 'toto.com' @@ -24,6 +24,12 @@ def test_domainname(): # c.f = 'toto.com' c.f = 'toto' + raises(ValueError, "c.f = 'domainnametoolongthathavemorethanmaximumsizeforatruedomainnameanditsnoteasytogeneratesolongdomainnamewithoutrepeatdomainnametoolongthathavemorethanmaximumsizeforatruedomainnameanditsnoteasytogeneratesolongdomainnamewithoutrepeatbutimnotabletodoitnowiendityeah'") + raises(ValueError, "c.f = 'd'") + # + c.g = 'toto.com' + c.g = '192.168.1.0' + c.g = '192.168.1.29' def test_special_domain_name(): """domain name option that starts with a number or not @@ -69,6 +75,7 @@ def test_email(): c.e = 'root@foo.com' raises(ValueError, "c.e = 'root'") raises(ValueError, "c.e = 'root@domain'") + raises(ValueError, "c.e = 'root[]@domain'") def test_url(): @@ -89,3 +96,4 @@ def test_url(): c.u = 'https://foo.com:8443' c.u = 'https://foo.com:8443/' c.u = 'https://foo.com:8443/index.html' + raises(ValueError, "c.u = 'https://foo.com:84438989'") diff --git a/test/test_dereference.py b/test/test_dereference.py index be8dfde..358c1b9 100644 --- a/test/test_dereference.py +++ b/test/test_dereference.py @@ -2,8 +2,8 @@ import autopath #from py.test import raises -from tiramisu.config import Config -from tiramisu.option import BoolOption, OptionDescription +from tiramisu.config import Config, GroupConfig, MetaConfig +from tiramisu.option import BoolOption, IntOption, OptionDescription import weakref @@ -109,3 +109,31 @@ def test_deref_optiondescription_config(): assert w() is not None del(c) assert w() is None + + +def test_deref_groupconfig(): + i1 = IntOption('i1', '') + od1 = OptionDescription('od1', '', [i1]) + od2 = OptionDescription('od2', '', [od1]) + conf1 = Config(od2) + conf2 = Config(od2) + meta = GroupConfig([conf1, conf2]) + w = weakref.ref(conf1) + del(conf1) + assert w() is not None + del(meta) + assert w() is None + + +def test_deref_metaconfig(): + i1 = IntOption('i1', '') + od1 = OptionDescription('od1', '', [i1]) + od2 = OptionDescription('od2', '', [od1]) + conf1 = Config(od2) + conf2 = Config(od2) + meta = MetaConfig([conf1, conf2]) + w = weakref.ref(conf1) + del(conf1) + assert w() is not None + del(meta) + assert w() is None diff --git a/test/test_metaconfig.py b/test/test_metaconfig.py index 35d65d5..a8fc395 100644 --- a/test/test_metaconfig.py +++ b/test/test_metaconfig.py @@ -1,172 +1,203 @@ -#import autopath +import autopath -#from py.test import raises +from py.test import raises -#from tiramisu.setting import owners -#from tiramisu.config import Config, MetaConfig -#from tiramisu.option import IntOption, OptionDescription -#from tiramisu.error import ConfigError +from tiramisu.setting import owners +from tiramisu.config import Config, GroupConfig, MetaConfig +from tiramisu.option import IntOption, OptionDescription +from tiramisu.error import ConfigError, PropertiesOptionError -#owners.addowner('meta') +owners.addowner('meta') -#def make_description(): -# i1 = IntOption('i1', '') -# i2 = IntOption('i2', '', default=1) -# i3 = IntOption('i3', '') -# i4 = IntOption('i4', '', default=2) -# od1 = OptionDescription('od1', '', [i1, i2, i3, i4]) -# od2 = OptionDescription('od2', '', [od1]) -# conf1 = Config(od2) -# conf2 = Config(od2) -# meta = MetaConfig([conf1, conf2]) -# meta.cfgimpl_get_settings().setowner(owners.meta) -# return meta +def make_description(): + i1 = IntOption('i1', '') + i2 = IntOption('i2', '', default=1) + i3 = IntOption('i3', '') + i4 = IntOption('i4', '', default=2) + i5 = IntOption('i5', '', default=[2], multi=True) + i6 = IntOption('i6', '', properties=('disabled',)) + od1 = OptionDescription('od1', '', [i1, i2, i3, i4, i5, i6]) + od2 = OptionDescription('od2', '', [od1]) + conf1 = Config(od2) + conf2 = Config(od2) + conf1.read_write() + conf2.read_write() + meta = MetaConfig([conf1, conf2]) + meta.cfgimpl_get_settings().setowner(owners.meta) + return meta -##FIXME ne pas mettre 2 meta dans une config -##FIXME ne pas mettre 2 OD differents dans un meta -#def test_none(): -# meta = make_description() -# conf1, conf2 = meta._impl_children -# assert conf1.od1.i3 is conf2.od1.i3 is None -# assert conf1.getowner(conf1.unwrap_from_path('od1.i3')) is conf2.getowner(conf2.unwrap_from_path('od1.i3')) is owners.default -# meta.od1.i3 = 3 -# assert conf1.od1.i3 == conf2.od1.i3 == 3 -# assert conf1.getowner(conf1.unwrap_from_path('od1.i3')) is conf2.getowner(conf2.unwrap_from_path('od1.i3')) is owners.meta -# meta.od1.i3 = 3 -# conf1.od1.i3 = 2 -# assert conf1.od1.i3 == 2 -# assert conf2.od1.i3 == 3 -# assert conf1.getowner(conf1.unwrap_from_path('od1.i3')) is owners.user -# assert conf2.getowner(conf2.unwrap_from_path('od1.i3')) is owners.meta -# meta.od1.i3 = 4 -# assert conf1.od1.i3 == 2 -# assert conf2.od1.i3 == 4 -# assert conf1.getowner(conf1.unwrap_from_path('od1.i3')) is owners.user -# assert conf2.getowner(conf2.unwrap_from_path('od1.i3')) is owners.meta -# del(meta.od1.i3) -# assert conf1.od1.i3 == 2 -# assert conf2.od1.i3 is None -# assert conf1.getowner(conf1.unwrap_from_path('od1.i3')) is owners.user -# assert conf2.getowner(conf2.unwrap_from_path('od1.i3')) is owners.default -# del(conf1.od1.i3) -# assert conf1.od1.i3 is conf2.od1.i3 is None -# assert conf1.getowner(conf1.unwrap_from_path('od1.i3')) is conf2.getowner(conf2.unwrap_from_path('od1.i3')) is owners.default +#FIXME ne pas mettre 2 meta dans une config +#FIXME ne pas mettre 2 OD differents dans un meta +#FIXME serialization +def test_none(): + meta = make_description() + conf1, conf2 = meta.cfgimpl_get_children() + assert conf1.od1.i3 is conf2.od1.i3 is None + assert conf1.getowner(conf1.unwrap_from_path('od1.i3')) is conf2.getowner(conf2.unwrap_from_path('od1.i3')) is owners.default + meta.od1.i3 = 3 + assert conf1.od1.i3 == conf2.od1.i3 == 3 + assert conf1.getowner(conf1.unwrap_from_path('od1.i3')) is conf2.getowner(conf2.unwrap_from_path('od1.i3')) is owners.meta + meta.od1.i3 = 3 + conf1.od1.i3 = 2 + assert conf1.od1.i3 == 2 + assert conf2.od1.i3 == 3 + assert conf1.getowner(conf1.unwrap_from_path('od1.i3')) is owners.user + assert conf2.getowner(conf2.unwrap_from_path('od1.i3')) is owners.meta + meta.od1.i3 = 4 + assert conf1.od1.i3 == 2 + assert conf2.od1.i3 == 4 + assert conf1.getowner(conf1.unwrap_from_path('od1.i3')) is owners.user + assert conf2.getowner(conf2.unwrap_from_path('od1.i3')) is owners.meta + del(meta.od1.i3) + assert conf1.od1.i3 == 2 + assert conf2.od1.i3 is None + assert conf1.getowner(conf1.unwrap_from_path('od1.i3')) is owners.user + assert conf2.getowner(conf2.unwrap_from_path('od1.i3')) is owners.default + del(conf1.od1.i3) + assert conf1.od1.i3 is conf2.od1.i3 is None + assert conf1.getowner(conf1.unwrap_from_path('od1.i3')) is conf2.getowner(conf2.unwrap_from_path('od1.i3')) is owners.default -#def test_default(): -# meta = make_description() -# conf1, conf2 = meta._impl_children -# assert conf1.od1.i2 == conf2.od1.i2 == 1 -# assert conf1.getowner(conf1.unwrap_from_path('od1.i2')) is conf2.getowner(conf2.unwrap_from_path('od1.i2')) is owners.default -# meta.od1.i2 = 3 -# assert conf1.od1.i2 == conf2.od1.i2 == 3 -# assert conf1.getowner(conf1.unwrap_from_path('od1.i2')) is conf2.getowner(conf2.unwrap_from_path('od1.i2')) is owners.meta -# meta.od1.i2 = 3 -# conf1.od1.i2 = 2 -# assert conf1.od1.i2 == 2 -# assert conf2.od1.i2 == 3 -# assert conf1.getowner(conf1.unwrap_from_path('od1.i2')) is owners.user -# assert conf2.getowner(conf2.unwrap_from_path('od1.i2')) is owners.meta -# meta.od1.i2 = 4 -# assert conf1.od1.i2 == 2 -# assert conf2.od1.i2 == 4 -# assert conf1.getowner(conf1.unwrap_from_path('od1.i2')) is owners.user -# assert conf2.getowner(conf2.unwrap_from_path('od1.i2')) is owners.meta -# del(meta.od1.i2) -# assert conf1.od1.i2 == 2 -# assert conf2.od1.i2 == 1 -# assert conf1.getowner(conf1.unwrap_from_path('od1.i2')) is owners.user -# assert conf2.getowner(conf2.unwrap_from_path('od1.i2')) is owners.default -# del(conf1.od1.i2) -# assert conf1.od1.i2 == conf2.od1.i2 == 1 -# assert conf1.getowner(conf1.unwrap_from_path('od1.i2')) is conf2.getowner(conf2.unwrap_from_path('od1.i2')) is owners.default +def test_default(): + meta = make_description() + conf1, conf2 = meta.cfgimpl_get_children() + assert conf1.od1.i2 == conf2.od1.i2 == 1 + assert conf1.getowner(conf1.unwrap_from_path('od1.i2')) is conf2.getowner(conf2.unwrap_from_path('od1.i2')) is owners.default + meta.od1.i2 = 3 + assert conf1.od1.i2 == conf2.od1.i2 == 3 + assert conf1.getowner(conf1.unwrap_from_path('od1.i2')) is conf2.getowner(conf2.unwrap_from_path('od1.i2')) is owners.meta + meta.od1.i2 = 3 + conf1.od1.i2 = 2 + assert conf1.od1.i2 == 2 + assert conf2.od1.i2 == 3 + assert conf1.getowner(conf1.unwrap_from_path('od1.i2')) is owners.user + assert conf2.getowner(conf2.unwrap_from_path('od1.i2')) is owners.meta + meta.od1.i2 = 4 + assert conf1.od1.i2 == 2 + assert conf2.od1.i2 == 4 + assert conf1.getowner(conf1.unwrap_from_path('od1.i2')) is owners.user + assert conf2.getowner(conf2.unwrap_from_path('od1.i2')) is owners.meta + del(meta.od1.i2) + assert conf1.od1.i2 == 2 + assert conf2.od1.i2 == 1 + assert conf1.getowner(conf1.unwrap_from_path('od1.i2')) is owners.user + assert conf2.getowner(conf2.unwrap_from_path('od1.i2')) is owners.default + del(conf1.od1.i2) + assert conf1.od1.i2 == conf2.od1.i2 == 1 + assert conf1.getowner(conf1.unwrap_from_path('od1.i2')) is conf2.getowner(conf2.unwrap_from_path('od1.i2')) is owners.default -#def test_contexts(): -# meta = make_description() -# conf1, conf2 = meta._impl_children -# assert conf1.od1.i2 == conf2.od1.i2 == 1 -# assert conf1.getowner(conf1.unwrap_from_path('od1.i2')) is conf2.getowner(conf2.unwrap_from_path('od1.i2')) is owners.default -# meta.set_contexts('od1.i2', 6) -# assert meta.od1.i2 == 1 -# assert conf1.od1.i2 == conf2.od1.i2 == 6 -# assert conf1.getowner(conf1.unwrap_from_path('od1.i2')) is conf2.getowner(conf2.unwrap_from_path('od1.i2')) is owners.user +def test_contexts(): + meta = make_description() + conf1, conf2 = meta.cfgimpl_get_children() + assert conf1.od1.i2 == conf2.od1.i2 == 1 + assert conf1.getowner(conf1.unwrap_from_path('od1.i2')) is conf2.getowner(conf2.unwrap_from_path('od1.i2')) is owners.default + meta.setattrs('od1.i2', 6) + assert meta.od1.i2 == 1 + assert conf1.od1.i2 == conf2.od1.i2 == 6 + assert conf1.getowner(conf1.unwrap_from_path('od1.i2')) is conf2.getowner(conf2.unwrap_from_path('od1.i2')) is owners.user -#def test_find(): -# meta = make_description() -# i2 = meta.unwrap_from_path('od1.i2') -# assert [i2] == meta.find(byname='i2') -# assert i2 == meta.find_first(byname='i2') -# assert meta.make_dict() == {'od1.i4': 2, 'od1.i1': None, 'od1.i3': None, 'od1.i2': 1} +def test_find(): + meta = make_description() + i2 = meta.unwrap_from_path('od1.i2') + assert [i2] == meta.find(byname='i2') + assert i2 == meta.find_first(byname='i2') + assert meta.make_dict() == {'od1.i4': 2, 'od1.i1': None, 'od1.i3': None, + 'od1.i2': 1, 'od1.i5': [2], 'od1.i6': None} -#def test_meta_meta(): -# meta1 = make_description() -# meta2 = MetaConfig([meta1]) -# meta2.cfgimpl_get_settings().setowner(owners.meta) -# conf1, conf2 = meta1._impl_children -# assert conf1.od1.i2 == conf2.od1.i2 == 1 -# assert conf1.getowner(conf1.unwrap_from_path('od1.i2')) is conf2.getowner(conf2.unwrap_from_path('od1.i2')) is owners.default -# meta2.od1.i2 = 3 -# assert conf1.od1.i2 == conf2.od1.i2 == 3 -# assert conf1.getowner(conf1.unwrap_from_path('od1.i2')) is conf2.getowner(conf2.unwrap_from_path('od1.i2')) is owners.meta -# meta2.od1.i2 = 3 -# conf1.od1.i2 = 2 -# assert conf1.od1.i2 == 2 -# assert conf2.od1.i2 == 3 -# assert conf1.getowner(conf1.unwrap_from_path('od1.i2')) is owners.user -# assert conf2.getowner(conf2.unwrap_from_path('od1.i2')) is owners.meta -# meta2.od1.i2 = 4 -# assert conf1.od1.i2 == 2 -# assert conf2.od1.i2 == 4 -# assert conf1.getowner(conf1.unwrap_from_path('od1.i2')) is owners.user -# assert conf2.getowner(conf2.unwrap_from_path('od1.i2')) is owners.meta -# del(meta2.od1.i2) -# assert conf1.od1.i2 == 2 -# assert conf2.od1.i2 == 1 -# assert conf1.getowner(conf1.unwrap_from_path('od1.i2')) is owners.user -# assert conf2.getowner(conf2.unwrap_from_path('od1.i2')) is owners.default -# del(conf1.od1.i2) -# assert conf1.od1.i2 == conf2.od1.i2 == 1 -# assert conf1.getowner(conf1.unwrap_from_path('od1.i2')) is conf2.getowner(conf2.unwrap_from_path('od1.i2')) is owners.default -# meta1.od1.i2 = 6 -# assert conf1.od1.i2 == conf2.od1.i2 == 6 -# assert conf1.getowner(conf1.unwrap_from_path('od1.i2')) is conf2.getowner(conf2.unwrap_from_path('od1.i2')) is owners.meta +def test_meta_meta(): + meta1 = make_description() + meta2 = MetaConfig([meta1]) + meta2.cfgimpl_get_settings().setowner(owners.meta) + conf1, conf2 = meta1.cfgimpl_get_children() + assert conf1.od1.i2 == conf2.od1.i2 == 1 + assert conf1.getowner(conf1.unwrap_from_path('od1.i2')) is conf2.getowner(conf2.unwrap_from_path('od1.i2')) is owners.default + meta2.od1.i2 = 3 + assert conf1.od1.i2 == conf2.od1.i2 == 3 + assert conf1.getowner(conf1.unwrap_from_path('od1.i2')) is conf2.getowner(conf2.unwrap_from_path('od1.i2')) is owners.meta + meta2.od1.i2 = 3 + conf1.od1.i2 = 2 + assert conf1.od1.i2 == 2 + assert conf2.od1.i2 == 3 + assert conf1.getowner(conf1.unwrap_from_path('od1.i2')) is owners.user + assert conf2.getowner(conf2.unwrap_from_path('od1.i2')) is owners.meta + meta2.od1.i2 = 4 + assert conf1.od1.i2 == 2 + assert conf2.od1.i2 == 4 + assert conf1.getowner(conf1.unwrap_from_path('od1.i2')) is owners.user + assert conf2.getowner(conf2.unwrap_from_path('od1.i2')) is owners.meta + del(meta2.od1.i2) + assert conf1.od1.i2 == 2 + assert conf2.od1.i2 == 1 + assert conf1.getowner(conf1.unwrap_from_path('od1.i2')) is owners.user + assert conf2.getowner(conf2.unwrap_from_path('od1.i2')) is owners.default + del(conf1.od1.i2) + assert conf1.od1.i2 == conf2.od1.i2 == 1 + assert conf1.getowner(conf1.unwrap_from_path('od1.i2')) is conf2.getowner(conf2.unwrap_from_path('od1.i2')) is owners.default + meta1.od1.i2 = 6 + assert conf1.od1.i2 == conf2.od1.i2 == 6 + assert conf1.getowner(conf1.unwrap_from_path('od1.i2')) is conf2.getowner(conf2.unwrap_from_path('od1.i2')) is owners.meta -#def test_meta_meta_set(): -# meta1 = make_description() -# meta2 = MetaConfig([meta1]) -# meta2.cfgimpl_get_settings().setowner(owners.meta) -# conf1, conf2 = meta1._impl_children -# meta2.set_contexts('od1.i1', 7) -# assert conf1.od1.i1 == conf2.od1.i1 == 7 -# assert conf1.getowner(conf1.unwrap_from_path('od1.i1')) is conf2.getowner(conf2.unwrap_from_path('od1.i1')) is owners.user -# assert [conf1, conf2] == meta2.find_first_contexts(byname='i1', byvalue=7) -# conf1.od1.i1 = 8 -# assert [conf2] == meta2.find_first_contexts(byname='i1', byvalue=7) -# assert [conf1] == meta2.find_first_contexts(byname='i1', byvalue=8) -# raises(AttributeError, "meta2.find_first_contexts(byname='i1', byvalue=10)") +def test_meta_meta_set(): + meta1 = make_description() + meta2 = MetaConfig([meta1]) + meta2.cfgimpl_get_settings().setowner(owners.meta) + conf1, conf2 = meta1.cfgimpl_get_children() + meta2.setattrs('od1.i1', 7) + #PropertiesOptionError + meta2.setattrs('od1.i6', 7) + assert conf1.od1.i1 == conf2.od1.i1 == 7 + assert conf1.getowner(conf1.unwrap_from_path('od1.i1')) is conf2.getowner(conf2.unwrap_from_path('od1.i1')) is owners.user + assert [conf1, conf2] == meta2.find_firsts(byname='i1', byvalue=7) + conf1.od1.i1 = 8 + assert [conf1, conf2] == meta2.find_firsts(byname='i1') + assert [conf2] == meta2.find_firsts(byname='i1', byvalue=7) + assert [conf1] == meta2.find_firsts(byname='i1', byvalue=8) + assert [conf1, conf2] == meta2.find_firsts(byname='i5', byvalue=2) + raises(AttributeError, "meta2.find_firsts(byname='i1', byvalue=10)") + raises(AttributeError, "meta2.find_firsts(byname='not', byvalue=10)") + raises(AttributeError, "meta2.find_firsts(byname='i6')") -#def test_not_meta(): -# i1 = IntOption('i1', '') -# od1 = OptionDescription('od1', '', [i1]) -# od2 = OptionDescription('od2', '', [od1]) -# conf1 = Config(od2) -# conf2 = Config(od2) -# meta = MetaConfig([conf1, conf2], False) -# raises(ConfigError, 'meta.od1.i1') -# conf1, conf2 = meta._impl_children -# meta.set_contexts('od1.i1', 7) -# assert conf1.od1.i1 == conf2.od1.i1 == 7 -# assert conf1.getowner(conf1.unwrap_from_path('od1.i1')) is conf2.getowner(conf2.unwrap_from_path('od1.i1')) is owners.user +def test_not_meta(): + i1 = IntOption('i1', '') + od1 = OptionDescription('od1', '', [i1]) + od2 = OptionDescription('od2', '', [od1]) + conf1 = Config(od2) + conf2 = Config(od2) + raises(ValueError, "GroupConfig(conf1)") + meta = GroupConfig([conf1, conf2]) + raises(ConfigError, 'meta.od1.i1') + conf1, conf2 = meta.cfgimpl_get_children() + meta.setattrs('od1.i1', 7) + assert conf1.od1.i1 == conf2.od1.i1 == 7 + assert conf1.getowner(conf1.unwrap_from_path('od1.i1')) is conf2.getowner(conf2.unwrap_from_path('od1.i1')) is owners.user -#def test_meta_path(): -# meta = make_description() -# assert meta._impl_path is None -# assert meta.od1._impl_path == 'od1' +def test_meta_path(): + meta = make_description() + assert meta._impl_path is None + assert meta.od1._impl_path == 'od1' + + +def test_meta_unconsistent(): + i1 = IntOption('i1', '') + i2 = IntOption('i2', '', default=1) + i3 = IntOption('i3', '') + i4 = IntOption('i4', '', default=2) + od1 = OptionDescription('od1', '', [i1, i2, i3, i4]) + od2 = OptionDescription('od2', '', [od1]) + conf1 = Config(od2) + conf2 = Config(od2) + conf3 = Config(od2) + conf4 = Config(od1) + meta = MetaConfig([conf1, conf2]) + meta.cfgimpl_get_settings().setowner(owners.meta) + raises(TypeError, 'MetaConfig("string")') + raises(ValueError, "MetaConfig([conf1, conf3])") + raises(ValueError, "MetaConfig([conf3, conf4])") diff --git a/test/test_multi.py b/test/test_multi.py new file mode 100644 index 0000000..42fd8e1 --- /dev/null +++ b/test/test_multi.py @@ -0,0 +1,21 @@ +# coding: utf-8 +import autopath +from tiramisu.value import Multi +from tiramisu.option import IntOption, OptionDescription +from tiramisu.config import Config +from tiramisu.error import ConfigError + +import weakref +from py.test import raises + + +def test_multi(): + i = IntOption('int', '', multi=True) + o = OptionDescription('od', '', [i]) + c = Config(o) + multi = Multi([1,2,3], weakref.ref(c), i, 'int') + raises(ValueError, "Multi([1,2,3], c, i, 'int')") + raises(ValueError, "Multi(multi, weakref.ref(c), i, 'int')") + assert c is multi._getcontext() + del(c) + raises(ConfigError, "multi._getcontext()") diff --git a/test/test_option_calculation.py b/test/test_option_calculation.py index 91d61a4..89f9291 100644 --- a/test/test_option_calculation.py +++ b/test/test_option_calculation.py @@ -373,6 +373,9 @@ def test_callback_multi_value(): assert cfg.val2 == ['val'] assert cfg.val3 == ['yes'] assert cfg.val4 == ['val', 'yes'] + cfg.val2.append('new') + assert cfg.val1 == ['val'] + assert cfg.val2 == ['val', 'new'] def test_callback_multi_list(): @@ -466,6 +469,66 @@ def test_callback_master_and_slaves_slave(): assert cfg.val1.val2 == ['val2', 'val2', 'val'] +def test_callback_master_and_slaves_slave_cal(): + val3 = StrOption('val3', "", multi=True) + val1 = StrOption('val1', "", multi=True, callback=return_value, callback_params={'': ((val3, False),)}) + val2 = StrOption('val2', "", multi=True, callback=return_val) + interface1 = OptionDescription('val1', '', [val1, val2]) + interface1.impl_set_group_type(groups.master) + maconfig = OptionDescription('rootconfig', '', [interface1, val3]) + cfg = Config(maconfig) + cfg.read_write() + assert cfg.val3 == [] + assert cfg.val1.val1 == [] + assert cfg.val1.val2 == [] + cfg.val1.val1 = ['val1'] + cfg.val3 = ['val1'] + assert cfg.val1.val1 == ['val1'] + assert cfg.val1.val2 == ['val'] + assert cfg.val1.val1 == ['val1'] + assert cfg.val1.val2 == ['val'] + del(cfg.val1.val1) + cfg.val1.val2 = ['val'] + cfg.val3 = ['val1', 'val2'] + assert cfg.val1.val2 == ['val', 'val'] + assert cfg.val1.val1 == ['val1', 'val2'] + cfg.val1.val2 = ['val1', 'val2'] + cfg.val3.pop(1) + # cannot remove slave's value because master is calculated + # so raise + raises(SlaveError, "cfg.val1.val1") + raises(SlaveError, "cfg.val1.val2") + cfg.val3 = ['val1', 'val2', 'val3'] + assert cfg.val1.val2 == ['val1', 'val2', 'val'] + + +def test_callback_master_and_slaves_slave_cal2(): + val3 = StrOption('val3', "", ['val', 'val'], multi=True) + val1 = StrOption('val1', "", multi=True, callback=return_value, callback_params={'': ((val3, False),)}) + val2 = StrOption('val2', "", ['val2', 'val2'], multi=True) + interface1 = OptionDescription('val1', '', [val1, val2]) + interface1.impl_set_group_type(groups.master) + maconfig = OptionDescription('rootconfig', '', [interface1, val3]) + cfg = Config(maconfig) + cfg.read_write() + assert cfg.val3 == ['val', 'val'] + assert cfg.val1.val1 == ['val', 'val'] + assert cfg.val1.val2 == ['val2', 'val2'] + cfg.val3.pop(1) +# # cannot remove slave's value because master is calculated +# # so raise + raises(SlaveError, "cfg.val1.val1") + raises(SlaveError, "cfg.val1.val2") + cfg.val3 = ['val', 'val'] + assert cfg.val3 == ['val', 'val'] + assert cfg.val1.val1 == ['val', 'val'] + assert cfg.val1.val2 == ['val2', 'val2'] + raises(SlaveError, "cfg.val1.val1 = ['val']") + assert cfg.val3 == ['val', 'val'] + assert cfg.val1.val1 == ['val', 'val'] + assert cfg.val1.val2 == ['val2', 'val2'] + + def test_callback_master_and_slaves_slave_list(): val1 = StrOption('val1', "", multi=True) val2 = StrOption('val2', "", multi=True, callback=return_list) diff --git a/test/test_option_consistency.py b/test/test_option_consistency.py index a7ff41c..1beb4bb 100644 --- a/test/test_option_consistency.py +++ b/test/test_option_consistency.py @@ -169,6 +169,18 @@ def test_consistency_network_netmask(): raises(ValueError, "c.a = '192.168.1.1'") +def test_consistency_ip_netmask_network_error(): + a = IPOption('a', '') + b = NetworkOption('b', '') + c = NetmaskOption('c', '') + od = OptionDescription('od', '', [a, b, c]) + c.impl_add_consistency('ip_netmask', a, b) + c = Config(od) + c.a = '192.168.1.1' + c.b = '192.168.1.0' + raises(ConfigError, "c.c = '255.255.255.0'") + + def test_consistency_ip_netmask_error_multi(): a = IPOption('a', '', multi=True) b = NetmaskOption('b', '') @@ -217,6 +229,8 @@ def test_consistency_ip_netmask_multi_master(): c.b = ['255.255.255.255'] c.b = ['255.255.255.0'] raises(ValueError, "c.a = ['192.168.1.0']") + c.a = ['192.168.1.128'] + raises(ValueError, "c.b = ['255.255.255.128']") c.a = ['192.168.1.2', '192.168.1.3'] @@ -260,6 +274,20 @@ def test_consistency_broadcast(): c.c[1] = '192.168.2.255' +def test_consistency_broadcast_error(): + a = NetworkOption('a', '', multi=True) + b = NetmaskOption('b', '', multi=True) + c = BroadcastOption('c', '', multi=True) + od = OptionDescription('a', '', [a, b, c]) + od.impl_set_group_type(groups.master) + b.impl_add_consistency('network_netmask', a) + c.impl_add_consistency('broadcast', a) + c = Config(od) + c.a = ['192.168.1.0'] + c.b = ['255.255.255.0'] + raises(ConfigError, "c.c = ['192.168.1.255']") + + def test_consistency_broadcast_default(): a = NetworkOption('a', '', '192.168.1.0') b = NetmaskOption('b', '', '255.255.255.128') diff --git a/test/test_option_owner.py b/test/test_option_owner.py index b758e91..d4c3f6b 100644 --- a/test/test_option_owner.py +++ b/test/test_option_owner.py @@ -36,6 +36,7 @@ def test_default_owner(): cfg = Config(descr) assert cfg.dummy is False assert cfg.getowner(gcdummy) == 'default' + raises(TypeError, "cfg.getowner('gcdummy')") cfg.dummy = True assert cfg.getowner(gcdummy) == owners.user diff --git a/test/test_parsing_group.py b/test/test_parsing_group.py index 7ecd860..c3b6ffc 100644 --- a/test/test_parsing_group.py +++ b/test/test_parsing_group.py @@ -94,6 +94,19 @@ def test_iter_on_groups(): result = list(config.creole.iter_groups(group_type=groups.family)) group_names = [res[0] for res in result] assert group_names == ['general', 'interface1'] + for i in config.creole.iter_groups(group_type=groups.family): + #test StopIteration + break + + +def test_iter_on_groups_props(): + descr = make_description() + config = Config(descr) + config.read_write() + config.cfgimpl_get_settings()[descr.creole.interface1].append('disabled') + result = list(config.creole.iter_groups(group_type=groups.family)) + group_names = [res[0] for res in result] + assert group_names == ['general'] def test_iter_on_empty_group(): diff --git a/test/test_state.py b/test/test_state.py index ef46ce2..03be06e 100644 --- a/test/test_state.py +++ b/test/test_state.py @@ -1,10 +1,13 @@ +import autopath + from tiramisu.option import BoolOption, UnicodeOption, SymLinkOption, \ - OptionDescription -from tiramisu.config import Config + IntOption, OptionDescription +from tiramisu.config import Config, GroupConfig, MetaConfig from tiramisu.setting import owners from tiramisu.storage import delete_session from tiramisu.error import ConfigError from pickle import dumps, loads +from py.test import raises def return_value(value=None): @@ -90,10 +93,48 @@ def _diff_opt(opt1, opt2): assert val1 == val2 +def _diff_conf(cfg1, cfg2): + attr1 = set(_get_slots(cfg1)) + attr2 = set(_get_slots(cfg2)) + diff1 = attr1 - attr2 + diff2 = attr2 - attr1 + if diff1 != set(): + raise Exception('more attribute in cfg1 {0}'.format(list(diff1))) + if diff2 != set(): + raise Exception('more attribute in cfg2 {0}'.format(list(diff2))) + for attr in attr1: + if attr in ('_impl_context', '__weakref__'): + continue + err1 = False + err2 = False + val1 = None + val2 = None + try: + val1 = getattr(cfg1, attr) + except: + err1 = True + + try: + val2 = getattr(cfg2, attr) + except: + err2 = True + assert err1 == err2 + if val1 is None: + assert val1 == val2 + elif attr == '_impl_values': + assert cfg1.cfgimpl_get_values().get_modified_values() == cfg2.cfgimpl_get_values().get_modified_values() + elif attr == '_impl_settings': + assert cfg1.cfgimpl_get_settings().get_modified_properties() == cfg2.cfgimpl_get_settings().get_modified_properties() + assert cfg1.cfgimpl_get_settings().get_modified_permissives() == cfg2.cfgimpl_get_settings().get_modified_permissives() + elif attr == '_impl_descr': + _diff_opt(cfg1.cfgimpl_get_description(), cfg2.cfgimpl_get_description()) + else: + assert val1 == val2 + + def test_diff_opt(): b = BoolOption('b', '') u = UnicodeOption('u', '', requires=[{'option': b, 'expected': True, 'action': 'disabled', 'inverse': True}]) - #u.impl_add_consistency('not_equal', b) s = SymLinkOption('s', u) o = OptionDescription('o', '', [b, u, s]) o1 = OptionDescription('o1', '', [o]) @@ -107,6 +148,11 @@ def test_diff_opt(): _diff_opt(o1.o.s, q.o.s) +def test_only_optiondescription(): + b = BoolOption('b', '') + raises(SystemError, "a = dumps(b)") + + def test_diff_opt_cache(): b = BoolOption('b', '') u = UnicodeOption('u', '', requires=[{'option': b, 'expected': True, 'action': 'disabled', 'inverse': True}]) @@ -169,10 +215,7 @@ def test_state_config(): cfg._impl_test = True a = dumps(cfg) q = loads(a) - _diff_opt(maconfig, q.cfgimpl_get_description()) - assert cfg.cfgimpl_get_values().get_modified_values() == q.cfgimpl_get_values().get_modified_values() - assert cfg.cfgimpl_get_settings().get_modified_properties() == q.cfgimpl_get_settings().get_modified_properties() - assert cfg.cfgimpl_get_settings().get_modified_permissives() == q.cfgimpl_get_settings().get_modified_permissives() + _diff_conf(cfg, q) try: delete_session('29090931') except ConfigError: @@ -191,12 +234,9 @@ def test_state_properties(): cfg.cfgimpl_get_settings()[val1].append('test') a = dumps(cfg) q = loads(a) - _diff_opt(maconfig, q.cfgimpl_get_description()) - assert cfg.cfgimpl_get_values().get_modified_values() == q.cfgimpl_get_values().get_modified_values() - assert cfg.cfgimpl_get_settings().get_modified_properties() == q.cfgimpl_get_settings().get_modified_properties() - assert cfg.cfgimpl_get_settings().get_modified_permissives() == q.cfgimpl_get_settings().get_modified_permissives() + _diff_conf(cfg, q) try: - delete_session('29090931') + delete_session('29090932') except ConfigError: pass @@ -212,15 +252,12 @@ def test_state_values(): cfg.val1 = True a = dumps(cfg) q = loads(a) - _diff_opt(maconfig, q.cfgimpl_get_description()) - assert cfg.cfgimpl_get_values().get_modified_values() == q.cfgimpl_get_values().get_modified_values() - assert cfg.cfgimpl_get_settings().get_modified_properties() == q.cfgimpl_get_settings().get_modified_properties() - assert cfg.cfgimpl_get_settings().get_modified_permissives() == q.cfgimpl_get_settings().get_modified_permissives() + _diff_conf(cfg, q) q.val1 = False #assert cfg.val1 is True assert q.val1 is False try: - delete_session('29090931') + delete_session('29090933') except ConfigError: pass @@ -238,14 +275,94 @@ def test_state_values_owner(): cfg.val1 = True a = dumps(cfg) q = loads(a) - _diff_opt(maconfig, q.cfgimpl_get_description()) - assert cfg.cfgimpl_get_values().get_modified_values() == q.cfgimpl_get_values().get_modified_values() - assert cfg.cfgimpl_get_settings().get_modified_properties() == q.cfgimpl_get_settings().get_modified_properties() - assert cfg.cfgimpl_get_settings().get_modified_permissives() == q.cfgimpl_get_settings().get_modified_permissives() + _diff_conf(cfg, q) q.val1 = False nval1 = q.cfgimpl_get_description().val1 assert q.getowner(nval1) == owners.newowner try: - delete_session('29090931') + delete_session('29090934') except ConfigError: pass + + +def test_state_metaconfig(): + i1 = IntOption('i1', '') + od1 = OptionDescription('od1', '', [i1]) + od2 = OptionDescription('od2', '', [od1]) + conf1 = Config(od2, session_id='29090935') + conf1._impl_test = True + conf2 = Config(od2, session_id='29090936') + conf2._impl_test = True + meta = MetaConfig([conf1, conf2], session_id='29090937') + meta._impl_test = True + raises(ConfigError, "dumps(meta)") + try: + delete_session('29090935') + delete_session('29090936') + delete_session('29090937') + except ConfigError: + pass + + +def test_state_groupconfig(): + i1 = IntOption('i1', '') + od1 = OptionDescription('od1', '', [i1]) + od2 = OptionDescription('od2', '', [od1]) + conf1 = Config(od2, session_id='29090935') + conf1._impl_test = True + conf2 = Config(od2, session_id='29090936') + conf2._impl_test = True + meta = GroupConfig([conf1, conf2], session_id='29090937') + meta._impl_test = True + a = dumps(meta) + q = loads(a) + _diff_conf(meta, q) + try: + delete_session('29090935') + delete_session('29090936') + delete_session('29090937') + except ConfigError: + pass + + +def test_state_unkown_setting_owner(): + """load an unknow _owner, should create it""" + assert not 'supernewuser' in owners.__dict__ + loads("""ccopy_reg +_reconstructor +p0 +(ctiramisu.setting +Settings +p1 +c__builtin__ +object +p2 +Ntp3 +Rp4 +(dp5 +S'_owner' +p6 +S'supernewuser' +p7 +sS'_p_' +p8 +g0 +(ctiramisu.storage.dictionary.setting +Settings +p9 +g2 +Ntp10 +Rp11 +(dp12 +S'_cache' +p13 +(dp14 +sS'_permissives' +p15 +(dp16 +sS'_properties' +p17 +(dp18 +sbsb. +.""") + assert 'supernewuser' in owners.__dict__ diff --git a/tiramisu/autolib.py b/tiramisu/autolib.py index ffdbb0a..cb3552a 100644 --- a/tiramisu/autolib.py +++ b/tiramisu/autolib.py @@ -152,7 +152,10 @@ def carry_out_calculation(option, config, callback, callback_params, opt) # get value try: - value = config._getattr(path, force_permissive=True) + value = config._getattr(path, force_permissive=True, validate=False) + # convert to list, not modifie this multi + if value.__class__.__name__ == 'Multi': + value = list(value) except PropertiesOptionError as err: if force_permissive: continue diff --git a/tiramisu/config.py b/tiramisu/config.py index 4bc0e15..c9fb992 100644 --- a/tiramisu/config.py +++ b/tiramisu/config.py @@ -48,7 +48,7 @@ class SubConfig(object): :type subpath: `str` with the path name """ # main option description - if not isinstance(descr, OptionDescription): + if descr is not None and not isinstance(descr, OptionDescription): raise TypeError(_('descr must be an optiondescription, not {0}' ).format(type(descr))) self._impl_descr = descr @@ -149,8 +149,6 @@ class SubConfig(object): except UnicodeEncodeError: lines.append("{0} = {1}".format(name, value.encode(default_encoding))) - except PropertiesOptionError: - pass return '\n'.join(lines) __repr__ = __str__ @@ -169,7 +167,7 @@ class SubConfig(object): def cfgimpl_get_description(self): if self._impl_descr is None: raise ConfigError(_('no option description found for this config' - ' (may be metaconfig without meta)')) + ' (may be GroupConfig)')) else: return self._impl_descr @@ -298,12 +296,9 @@ class SubConfig(object): :return: find list or an exception if nothing has been found """ def _filter_by_name(): - try: - if byname is None or path == byname or \ - path.endswith('.' + byname): - return True - except IndexError: - pass + if byname is None or path == byname or \ + path.endswith('.' + byname): + return True return False def _filter_by_value(): @@ -454,22 +449,16 @@ class SubConfig(object): def _make_sub_dict(self, opt, path, pathsvalues, _currpath, flatten): if isinstance(opt, OptionDescription): - try: - pathsvalues += getattr(self, path).make_dict(flatten, - _currpath + - path.split('.')) - except PropertiesOptionError: - pass # this just a hidden or disabled option + pathsvalues += getattr(self, path).make_dict(flatten, + _currpath + + path.split('.')) else: - try: - value = self._getattr(opt._name) - if flatten: - name = opt._name - else: - name = '.'.join(_currpath + [opt._name]) - pathsvalues.append((name, value)) - except PropertiesOptionError: - pass # this just a hidden or disabled option + value = self._getattr(opt._name) + if flatten: + name = opt._name + else: + name = '.'.join(_currpath + [opt._name]) + pathsvalues.append((name, value)) def cfgimpl_get_path(self): descr = self.cfgimpl_get_description() @@ -477,9 +466,9 @@ class SubConfig(object): return context_descr.impl_get_path_by_opt(descr) -class CommonConfig(SubConfig): - "abstract base class for the Config and the MetaConfig" - __slots__ = ('_impl_values', '_impl_settings', '_impl_meta') +class _CommonConfig(SubConfig): + "abstract base class for the Config, GroupConfig and the MetaConfig" + __slots__ = ('_impl_values', '_impl_settings', '_impl_meta', '_impl_test') def _impl_build_all_paths(self): self.cfgimpl_get_description().impl_build_cache() @@ -518,7 +507,8 @@ class CommonConfig(SubConfig): return None def cfgimpl_get_meta(self): - return self._impl_meta + if self._impl_meta is not None: + return self._impl_meta() # information def impl_set_information(self, key, value): @@ -536,11 +526,48 @@ class CommonConfig(SubConfig): """ return self._impl_values.get_information(key, default) + # ----- state + def __getstate__(self): + if self._impl_meta is not None: + raise ConfigError(_('cannot serialize Config with MetaConfig')) + slots = set() + for subclass in self.__class__.__mro__: + if subclass is not object: + slots.update(subclass.__slots__) + slots -= frozenset(['_impl_context', '_impl_meta', '__weakref__']) + state = {} + for slot in slots: + try: + state[slot] = getattr(self, slot) + except AttributeError: + pass + storage = self._impl_values._p_._storage + if not storage.serializable: + raise ConfigError(_('this storage is not serialisable, could be a ' + 'none persistent storage')) + state['_storage'] = {'session_id': storage.session_id, + 'persistent': storage.persistent} + state['_impl_setting'] = _impl_getstate_setting() + return state + + def __setstate__(self, state): + for key, value in state.items(): + if key not in ['_storage', '_impl_setting']: + setattr(self, key, value) + set_storage(**state['_impl_setting']) + self._impl_context = weakref.ref(self) + self._impl_settings.context = weakref.ref(self) + self._impl_values.context = weakref.ref(self) + storage = get_storage(test=self._impl_test, **state['_storage']) + self._impl_values._impl_setstate(storage) + self._impl_settings._impl_setstate(storage) + self._impl_meta = None + # ____________________________________________________________ -class Config(CommonConfig): +class Config(_CommonConfig): "main configuration management entry" - __slots__ = ('__weakref__', '_impl_test') + __slots__ = ('__weakref__',) def __init__(self, descr, session_id=None, persistent=False): """ Configuration option management master class @@ -564,41 +591,6 @@ class Config(CommonConfig): #undocumented option used only in test script self._impl_test = False - def __getstate__(self): - if self._impl_meta is not None: - raise ConfigError('cannot serialize Config with meta') - slots = set() - for subclass in self.__class__.__mro__: - if subclass is not object: - slots.update(subclass.__slots__) - slots -= frozenset(['_impl_context', '__weakref__']) - state = {} - for slot in slots: - try: - state[slot] = getattr(self, slot) - except AttributeError: - pass - storage = self._impl_values._p_._storage - if not storage.serializable: - raise ConfigError('this storage is not serialisable, could be a ' - 'none persistent storage') - state['_storage'] = {'session_id': storage.session_id, - 'persistent': storage.persistent} - state['_impl_setting'] = _impl_getstate_setting() - return state - - def __setstate__(self, state): - for key, value in state.items(): - if key not in ['_storage', '_impl_setting']: - setattr(self, key, value) - set_storage(**state['_impl_setting']) - self._impl_context = weakref.ref(self) - self._impl_settings.context = weakref.ref(self) - self._impl_values.context = weakref.ref(self) - storage = get_storage(test=self._impl_test, **state['_storage']) - self._impl_values._impl_setstate(storage) - self._impl_settings._impl_setstate(storage) - def cfgimpl_reset_cache(self, only_expired=False, only=('values', 'settings')): @@ -608,99 +600,119 @@ class Config(CommonConfig): self.cfgimpl_get_settings().reset_cache(only_expired=only_expired) -#class MetaConfig(CommonConfig): -# __slots__ = ('_impl_children',) +class GroupConfig(_CommonConfig): + __slots__ = ('_impl_children', '__weakref__') -# def __init__(self, children, meta=True, session_id=None, persistent=False): -# if not isinstance(children, list): -# raise ValueError(_("metaconfig's children must be a list")) -# self._impl_descr = None -# self._impl_path = None -# if meta: -# for child in children: -# if not isinstance(child, CommonConfig): -# raise TypeError(_("metaconfig's children " -# "must be config, not {0}" -# ).format(type(child))) -# if self._impl_descr is None: -# self._impl_descr = child.cfgimpl_get_description() -# elif not self._impl_descr is child.cfgimpl_get_description(): -# raise ValueError(_('all config in metaconfig must ' -# 'have the same optiondescription')) -# if child.cfgimpl_get_meta() is not None: -# raise ValueError(_("child has already a metaconfig's")) -# child._impl_meta = self + def __init__(self, children, session_id=None, persistent=False, + _descr=None): + if not isinstance(children, list): + raise ValueError(_("metaconfig's children must be a list")) + self._impl_children = children + settings, values = get_storages(self, session_id, persistent) + self._impl_settings = Settings(self, settings) + self._impl_values = Values(self, values) + super(GroupConfig, self).__init__(_descr, weakref.ref(self)) + self._impl_meta = None + #undocumented option used only in test script + self._impl_test = False -# self._impl_children = children -# settings, values = get_storages(self, session_id, persistent) -# self._impl_settings = Settings(self, settings) -# self._impl_values = Values(self, values) -# self._impl_meta = None + def cfgimpl_get_children(self): + return self._impl_children -# def cfgimpl_get_children(self): -# return self._impl_children + #def cfgimpl_get_context(self): + # "a meta config is a config which has a setting, that is itself" + # return self + # + def cfgimpl_reset_cache(self, + only_expired=False, + only=('values', 'settings')): + if 'values' in only: + self.cfgimpl_get_values().reset_cache(only_expired=only_expired) + if 'settings' in only: + self.cfgimpl_get_settings().reset_cache(only_expired=only_expired) + for child in self._impl_children: + child.cfgimpl_reset_cache(only_expired=only_expired, only=only) -# def cfgimpl_get_context(self): -# "a meta config is a config wich has a setting, that is itself" -# return self + def setattrs(self, path, value): + """Setattr not in current GroupConfig, but in each children + """ + for child in self._impl_children: + try: + if not isinstance(child, GroupConfig): + setattr(child, path, value) + else: + child.setattrs(path, value) + except PropertiesOptionError: + pass -# def cfgimpl_reset_cache(self, -# only_expired=False, -# only=('values', 'settings')): -# if 'values' in only: -# self.cfgimpl_get_values().reset_cache(only_expired=only_expired) -# if 'settings' in only: -# self.cfgimpl_get_settings().reset_cache(only_expired=only_expired) -# for child in self._impl_children: -# child.cfgimpl_reset_cache(only_expired=only_expired, only=only) + def find_firsts(self, byname=None, bypath=None, byvalue=None, + type_='path', display_error=True): + """Find first not in current GroupConfig, but in each children + """ + ret = [] + #if MetaConfig, all children have same OptionDescription as context + #so search only one time for all children + try: + if bypath is None and byname is not None and \ + isinstance(self, MetaConfig): + bypath = self._find(bytype=None, byvalue=None, byname=byname, + first=True, type_='path', + check_properties=False, + display_error=display_error) + byname = None + except AttributeError: + pass + for child in self._impl_children: + try: + if not isinstance(child, MetaConfig): + if bypath is not None: + #if byvalue is None, try if not raise + value = getattr(child, bypath) + if byvalue is not None: + if isinstance(value, Multi): + if byvalue in value: + ret.append(child) + else: + if value == byvalue: + ret.append(child) + else: + ret.append(child) + else: + ret.append(child.find_first(byname=byname, + byvalue=byvalue, + type_=type_, + display_error=False)) + else: + ret.extend(child.find_firsts(byname=byname, + bypath=bypath, + byvalue=byvalue, + type_=type_, + display_error=False)) + except AttributeError: + pass + return self._find_return_results(ret, display_error) -# def set_contexts(self, path, value): -# for child in self._impl_children: -# try: -# if not isinstance(child, MetaConfig): -# setattr(child, path, value) -# else: -# child.set_contexts(path, value) -# except PropertiesOptionError: -# pass -# def find_first_contexts(self, byname=None, bypath=None, byvalue=None, -# type_='path', display_error=True): -# ret = [] -# try: -# if bypath is None and byname is not None and \ -# self.cfgimpl_get_description() is not None: -# bypath = self._find(bytype=None, byvalue=None, byname=byname, -# first=True, type_='path', -# check_properties=False, -# display_error=display_error) -# except ConfigError: -# pass -# for child in self._impl_children: -# try: -# if not isinstance(child, MetaConfig): -# if bypath is not None: -# if byvalue is not None: -# if getattr(child, bypath) == byvalue: -# ret.append(child) -# else: -# #not raise -# getattr(child, bypath) -# ret.append(child) -# else: -# ret.append(child.find_first(byname=byname, -# byvalue=byvalue, -# type_=type_, -# display_error=False)) -# else: -# ret.extend(child.find_first_contexts(byname=byname, -# bypath=bypath, -# byvalue=byvalue, -# type_=type_, -# display_error=False)) -# except AttributeError: -# pass -# return self._find_return_results(ret, display_error) +class MetaConfig(GroupConfig): + __slots__ = tuple() + + def __init__(self, children, session_id=None, persistent=False): + descr = None + for child in children: + if not isinstance(child, _CommonConfig): + raise TypeError(_("metaconfig's children " + "should be config, not {0}" + ).format(type(child))) + if child.cfgimpl_get_meta() is not None: + raise ValueError(_("child has already a metaconfig's")) + if descr is None: + descr = child.cfgimpl_get_description() + elif not descr is child.cfgimpl_get_description(): + raise ValueError(_('all config in metaconfig must ' + 'have the same optiondescription')) + child._impl_meta = weakref.ref(self) + + super(MetaConfig, self).__init__(children, session_id, persistent, descr) def mandatory_warnings(config): @@ -719,6 +731,4 @@ def mandatory_warnings(config): except PropertiesOptionError as err: if err.proptype == ['mandatory']: yield path - except ConfigError: - pass config.cfgimpl_reset_cache(only=('values',)) diff --git a/tiramisu/option.py b/tiramisu/option.py index 8b5eb68..b9960b6 100644 --- a/tiramisu/option.py +++ b/tiramisu/option.py @@ -354,9 +354,6 @@ class Option(BaseOption): """ if context is not None: descr = context.cfgimpl_get_description() - #option is also in all_cons_opts - if option not in all_cons_opts: - raise ConfigError(_('option not in all_cons_opts')) all_cons_vals = [] for opt in all_cons_opts: @@ -587,31 +584,15 @@ class Option(BaseOption): consistencies = self._state_consistencies else: consistencies = self._consistencies - if isinstance(consistencies, list): - new_value = [] - for consistency in consistencies: - values = [] - for obj in consistency[1]: - if load: - values.append(descr.impl_get_opt_by_path(obj)) - else: - values.append(descr.impl_get_path_by_opt(obj)) - new_value.append((consistency[0], tuple(values))) - - else: - new_value = {} - for key, _consistencies in consistencies.items(): - new_value[key] = [] - for key_cons, _cons in _consistencies: - _list_cons = [] - for _con in _cons: - if load: - _list_cons.append( - descr.impl_get_opt_by_path(_con)) - else: - _list_cons.append( - descr.impl_get_path_by_opt(_con)) - new_value[key].append((key_cons, tuple(_list_cons))) + new_value = [] + for consistency in consistencies: + values = [] + for obj in consistency[1]: + if load: + values.append(descr.impl_get_opt_by_path(obj)) + else: + values.append(descr.impl_get_path_by_opt(obj)) + new_value.append((consistency[0], tuple(values))) if load: del(self._state_consistencies) self._consistencies = new_value @@ -663,7 +644,7 @@ class ChoiceOption(Option): return self._open_values def _validate(self, value): - if not self._open_values and not value in self._values: + if not self.impl_is_openvalues() and not value in self.impl_get_values(): raise ValueError(_('value {0} is not permitted, ' 'only {1} is allowed' '').format(value, self._values)) @@ -783,9 +764,13 @@ class IPOption(Option): def _validate(self, value): # sometimes an ip term starts with a zero # but this does not fit in some case, for example bind does not like it - for val in value.split('.'): - if val.startswith("0") and len(val) > 1: - raise ValueError(_('invalid IP')) + try: + for val in value.split('.'): + if val.startswith("0") and len(val) > 1: + raise ValueError(_('invalid IP')) + except AttributeError: + #if integer for example + raise ValueError(_('invalid IP')) # 'standard' validation try: IP('{0}/32'.format(value)) @@ -857,18 +842,23 @@ class PortOption(Option): if self._allow_range and ":" in str(value): value = str(value).split(':') if len(value) != 2: - raise ValueError('invalid part, range must have two values ' - 'only') + raise ValueError(_('invalid part, range must have two values ' + 'only')) if not value[0] < value[1]: - raise ValueError('invalid port, first port in range must be' - ' smaller than the second one') + raise ValueError(_('invalid port, first port in range must be' + ' smaller than the second one')) else: value = [value] for val in value: + try: + int(val) + except ValueError: + raise ValueError(_('invalid port')) if not self._min_value <= int(val) <= self._max_value: - raise ValueError('invalid port, must be an between {0} and {1}' - ''.format(self._min_value, self._max_value)) + raise ValueError(_('invalid port, must be an between {0} ' + 'and {1}').format(self._min_value, + self._max_value)) class NetworkOption(Option): @@ -924,19 +914,14 @@ class NetmaskOption(Option): IP('{0}/{1}'.format(val_ipnetwork, val_netmask), make_net=not make_net) except ValueError: - if not make_net: - msg = _("invalid network {0} ({1}) " - "with netmask {2}," - " this network is an IP") + pass else: if make_net: msg = _("invalid IP {0} ({1}) with netmask {2}," " this IP is a network") except ValueError: - if make_net: - msg = _('invalid IP {0} ({1}) with netmask {2}') - else: + if not make_net: msg = _('invalid network {0} ({1}) with netmask {2}') if msg is not None: raise ValueError(msg.format(val_ipnetwork, opts[1]._name, @@ -1032,8 +1017,8 @@ class DomainnameOption(Option): if self._type == 'domainname' and not self._allow_without_dot and \ '.' not in value: raise ValueError(_("invalid domainname, must have dot")) - if len(value) > 255: - raise ValueError(_("invalid domainname's length (max 255)")) + if len(value) > 255: + raise ValueError(_("invalid domainname's length (max 255)")) if len(value) < 2: raise ValueError(_("invalid domainname's length (min 2)")) if not self._domain_re.search(value): @@ -1310,13 +1295,10 @@ class OptionDescription(BaseOption): if consistencies is not None: for func, all_cons_opts in consistencies: #all_cons_opts[0] is the option where func is set - ret = all_cons_opts[0]._launch_consistency(func, option, - value, - context, index, - all_cons_opts) - if ret is False: - return False - return True + all_cons_opts[0]._launch_consistency(func, option, + value, + context, index, + all_cons_opts) def _impl_getstate(self, descr=None): """enables us to export into a dict diff --git a/tiramisu/value.py b/tiramisu/value.py index a02196a..ed70f90 100644 --- a/tiramisu/value.py +++ b/tiramisu/value.py @@ -66,6 +66,8 @@ class Values(object): meta = self._getcontext().cfgimpl_get_meta() if meta is not None: value = meta.cfgimpl_get_values()[opt] + if isinstance(value, Multi): + value = list(value) else: value = opt.impl_getdefault() if opt.impl_is_multi(): @@ -73,7 +75,7 @@ class Values(object): else: return value - def _getvalue(self, opt, path, validate=True): + def _getvalue(self, opt, path): """actually retrieves the value :param opt: the `option.Option()` object @@ -82,14 +84,9 @@ class Values(object): if not self._p_.hasvalue(path): # if there is no value value = self._getdefault(opt) - if opt.impl_is_multi(): - value = Multi(value, self.context, opt, path, validate) else: # if there is a value value = self._p_.getvalue(path) - if opt.impl_is_multi() and not isinstance(value, Multi): - # load value so don't need to validate if is not a Multi - value = Multi(value, self.context, opt, path, validate=False) return value def get_modified_values(self): @@ -198,7 +195,7 @@ class Values(object): # ConfigError if properties did not raise. config_error = None force_permissives = None - # if value is callback and is not set + # if value has callback and is not set # or frozen with force_default_on_freeze if opt.impl_has_callback() and ( self._is_default_owner(path) or @@ -208,7 +205,7 @@ class Values(object): if (opt.impl_is_multi() and opt.impl_get_multitype() == multitypes.slave): masterp = self._get_opt_path(opt.impl_get_master_slaves()) - mastervalue = getattr(context, masterp) + mastervalue = context._getattr(masterp, validate=validate) lenmaster = len(mastervalue) if lenmaster == 0: value = [] @@ -240,7 +237,10 @@ class Values(object): if opt.impl_is_multi(): value = Multi(value, self.context, opt, path, validate) else: - value = self._getvalue(opt, path, validate) + value = self._getvalue(opt, path) + if opt.impl_is_multi(): + # load value so don't need to validate if is not a Multi + value = Multi(value, self.context, opt, path, validate=validate) if config_error is None and validate: opt.impl_validate(value, context, 'validator' in setting) if config_error is None and self._is_default_owner(path) and \ @@ -266,10 +266,27 @@ class Values(object): context = self._getcontext() opt.impl_validate(value, context, 'validator' in context.cfgimpl_get_settings()) - if opt.impl_is_multi() and not isinstance(value, Multi): + if opt.impl_is_multi(): value = Multi(value, self.context, opt, path, setitem=True) + # Save old value + if opt.impl_get_multitype() == multitypes.master and \ + self._p_.hasvalue(path): + old_value = self._p_.getvalue(path) + old_owner = self._p_.getowner(path, None) + else: + old_value = undefined + old_owner = undefined self._setvalue(opt, path, value, force_permissive=force_permissive, is_write=is_write) + if opt.impl_is_multi() and opt.impl_get_multitype() == multitypes.master: + try: + value._valid_master() + except Exception, err: + if old_value is not undefined: + self._p_.setvalue(path, old_value, old_owner) + else: + self._p_.resetvalue(path) + raise err def _setvalue(self, opt, path, value, force_permissive=False, force_properties=None, @@ -283,6 +300,8 @@ class Values(object): force_permissive=force_permissive, force_properties=force_properties) owner = context.cfgimpl_get_settings().getowner() + if isinstance(value, Multi): + value = list(value) self._p_.setvalue(path, value, owner) def getowner(self, opt): @@ -403,6 +422,8 @@ class Multi(list): :param opt: the option object that have this Multi value :param setitem: only if set a value """ + if isinstance(value, Multi): + raise ValueError(_('{0} is already a Multi ').format(opt._name)) self.opt = opt self.path = path if not isinstance(context, weakref.ReferenceType): @@ -412,8 +433,9 @@ class Multi(list): value = [value] if validate and self.opt.impl_get_multitype() == multitypes.slave: value = self._valid_slave(value, setitem) - elif validate and self.opt.impl_get_multitype() == multitypes.master: - self._valid_master(value) + elif not setitem and validate and \ + self.opt.impl_get_multitype() == multitypes.master: + self._valid_master() super(Multi, self).__init__(value) def _getcontext(self): @@ -433,12 +455,10 @@ class Multi(list): values = context.cfgimpl_get_values() masterp = context.cfgimpl_get_description().impl_get_path_by_opt( self.opt.impl_get_master_slaves()) - mastervalue = getattr(context, masterp) + mastervalue = context._getattr(masterp, validate=False) masterlen = len(mastervalue) valuelen = len(value) - is_default_owner = not values._is_default_owner(self.path) or setitem - if valuelen > masterlen or (valuelen < masterlen and - is_default_owner): + if valuelen > masterlen or (valuelen < masterlen and setitem): raise SlaveError(_("invalid len for the slave: {0}" " which has {1} as master").format( self.opt._name, masterp)) @@ -455,30 +475,12 @@ class Multi(list): #else: same len so do nothing return value - def _valid_master(self, value): - masterlen = len(value) + def _valid_master(self): + #masterlen = len(value) values = self._getcontext().cfgimpl_get_values() for slave in self.opt._master_slaves: path = values._get_opt_path(slave) - if not values._is_default_owner(path): - value_slave = values._getvalue(slave, path) - if len(value_slave) > masterlen: - raise SlaveError(_("invalid len for the master: {0}" - " which has {1} as slave with" - " greater len").format( - self.opt._name, slave._name)) - elif len(value_slave) < masterlen: - for num in range(0, masterlen - len(value_slave)): - if slave.impl_has_callback(): - # if callback add a value, but this value will not - # change anymore automaticly (because this value - # has owner) - index = value_slave.__len__() - value_slave.append( - values._getcallback_value(slave, index=index), - force=True) - else: - value_slave.append(undefined, force=True) + Multi(values._getvalue(slave, path), self.context, slave, path) def __setitem__(self, index, value): self._validate(value, index) @@ -518,16 +520,15 @@ class Multi(list): dvalue = values._getcallback_value(slave, index=index) else: dvalue = slave.impl_getdefault_multi() - old_value = values.getitem(slave, path, + old_value = values.getitem(slave, path, validate=False, validate_properties=False) - if len(old_value) < self.__len__(): - values.getitem(slave, path, - validate_properties=False).append( - dvalue, force=True) - else: - values.getitem(slave, path, - validate_properties=False)[ - index] = dvalue + if len(old_value) + 1 != self.__len__(): + raise SlaveError(_("invalid len for the slave: {0}" + " which has {1} as master").format( + self.opt._name, self.__len__())) + values.getitem(slave, path, validate=False, + validate_properties=False).append( + dvalue, force=True) def sort(self, cmp=None, key=None, reverse=False): if self.opt.impl_get_multitype() in [multitypes.slave, @@ -592,12 +593,12 @@ class Multi(list): if self.opt.impl_get_multitype() == multitypes.slave: raise SlaveError(_("cannot pop a value on a multi option {0}" " which is a slave").format(self.opt._name)) - elif self.opt.impl_get_multitype() == multitypes.master: + if self.opt.impl_get_multitype() == multitypes.master: for slave in self.opt.impl_get_master_slaves(): values = context.cfgimpl_get_values() if not values.is_default_owner(slave): #get multi without valid properties - values.getitem(slave, + values.getitem(slave, validate=False, validate_properties=False ).pop(index, force=True) #set value without valid properties diff --git a/translations/fr/tiramisu.po b/translations/fr/tiramisu.po index d9bbc3e..83a9289 100644 --- a/translations/fr/tiramisu.po +++ b/translations/fr/tiramisu.po @@ -79,7 +79,7 @@ msgstr "l'attribut {2} de l'objet '{0}' ({1}) est en lecture seule" #: tiramisu/option.py:141 tiramisu/value.py:376 msgid "information's item not found: {0}" -msgstr "aucune config spécifié alors que c'est nécessaire" +msgstr "aucune config spécifiée alors que c'est nécessaire" #: tiramisu/option.py:203 msgid "cannot serialize Option, only in OptionDescription"