From d26626a1f9cd5f0050ce5bdb4fe3a42cb538274a Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Sat, 23 Dec 2017 20:21:07 +0100 Subject: [PATCH] settings --- test/new_api/test_freeze.py | 28 +- test/new_api/test_option_setting.py | 553 ++++++++++++++++++++++++++++ tiramisu/api.py | 31 +- tiramisu/error.py | 16 +- tiramisu/setting.py | 70 ++-- 5 files changed, 637 insertions(+), 61 deletions(-) create mode 100644 test/new_api/test_option_setting.py diff --git a/test/new_api/test_freeze.py b/test/new_api/test_freeze.py index 7b67674..f56b452 100644 --- a/test/new_api/test_freeze.py +++ b/test/new_api/test_freeze.py @@ -146,17 +146,17 @@ def test_force_store_value(): descr = make_description_freeze() conf = Config(descr) api = getapi(conf) - assert api.value.get() == {'wantref': ('forced', False), - 'wantref2': ('forced', False), - 'wantref3': ('forced', (False,))} + assert api.value.get_modified() == {'wantref': ('forced', False), + 'wantref2': ('forced', False), + 'wantref3': ('forced', (False,))} api.option('wantref').value.set(True) - assert api.value.get() == {'wantref': ('user', True), - 'wantref2': ('forced', False), - 'wantref3': ('forced', (False,))} + assert api.value.get_modified() == {'wantref': ('user', True), + 'wantref2': ('forced', False), + 'wantref3': ('forced', (False,))} api.option('wantref').value.reset() - assert api.value.get() == {'wantref': ('forced', False), - 'wantref2': ('forced', False), - 'wantref3': ('forced', (False,))} + assert api.value.get_modified() == {'wantref': ('forced', False), + 'wantref2': ('forced', False), + 'wantref3': ('forced', (False,))} def test_force_store_value_no_requirement(): @@ -189,28 +189,28 @@ def test_force_store_value_masterslaves_sub(): descr = MasterSlaves("int", "", [b, c]) odr = OptionDescription('odr', '', [descr]) api = getapi(Config(odr)) - assert api.value.get() == {'int.int': ('forced', ())} + assert api.value.get_modified() == {'int.int': ('forced', ())} def test_force_store_value_callback(): b = IntOption('int', 'Test int option', properties=('force_store_value',), callback=return_val) descr = OptionDescription("int", "", [b]) api = getapi(Config(descr)) - assert api.value.get() == {'int': ('forced', 1)} + assert api.value.get_modified() == {'int': ('forced', 1)} def test_force_store_value_callback_params(): b = IntOption('int', 'Test int option', properties=('force_store_value',), callback=return_val2, callback_params={'value': (2,)}) descr = OptionDescription("int", "", [b]) api = getapi(Config(descr)) - assert api.value.get() == {'int': ('forced', 2)} + assert api.value.get_modified() == {'int': ('forced', 2)} def test_force_store_value_callback_params_2(): b = IntOption('int', 'Test int option', properties=('force_store_value',), callback=return_val3, callback_params={'': ((None,),), 'value': (2,)}) descr = OptionDescription("int", "", [b]) api = getapi(Config(descr)) - assert api.value.get() == {'int': ('forced', 2)} + assert api.value.get_modified() == {'int': ('forced', 2)} def test_force_store_value_callback_params_with_opt(): @@ -218,4 +218,4 @@ def test_force_store_value_callback_params_with_opt(): b = IntOption('int', 'Test int option', properties=('force_store_value',), callback=return_val2, callback_params={'value': ((a, False),)}) descr = OptionDescription("int", "", [a, b]) api = getapi(Config(descr)) - assert api.value.get() == {'int': ('forced', 2)} + assert api.value.get_modified() == {'int': ('forced', 2)} diff --git a/test/new_api/test_option_setting.py b/test/new_api/test_option_setting.py new file mode 100644 index 0000000..07be0be --- /dev/null +++ b/test/new_api/test_option_setting.py @@ -0,0 +1,553 @@ +"config.set() or config.setoption() or option.setoption()" +from .autopath import do_autopath +do_autopath() + +from py.test import raises + +from tiramisu.i18n import _ +from tiramisu.error import display_list, ConfigError +from tiramisu.setting import owners, groups +from tiramisu import ChoiceOption, BoolOption, IntOption, FloatOption, \ + StrOption, OptionDescription, MasterSlaves, Config, getapi, undefined +from tiramisu.error import PropertiesOptionError + + +def make_description(): + gcoption = ChoiceOption('name', 'GC name', ('ref', 'framework'), 'ref') + gcdummy = BoolOption('dummy', 'dummy', default=False) + objspaceoption = ChoiceOption('objspace', 'Object space', + ('std', 'thunk'), 'std') + booloption = BoolOption('bool', 'Test boolean option', default=True) + intoption = IntOption('int', 'Test int option', default=0) + 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', 'Test requires', default=False) + wantframework_option = BoolOption('wantframework', 'Test requires', + default=False) + gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, floatoption]) + descr = OptionDescription('tiramisu', '', [gcgroup, booloption, objspaceoption, + wantref_option, stroption, + wantframework_option, + intoption, boolop]) + return descr + + +#____________________________________________________________ +# change with __setattr__ +def test_attribute_access(): + "Once set, option values can't be changed again by attribute access" + s = StrOption("string", "", default="string") + descr = OptionDescription("options", "", [s]) + api = getapi(Config(descr)) + # let's try to change it again + api.option('string').value.set('foo') + assert api.option('string').value.get() == 'foo' + + +def test_setitem(): + s = StrOption("string", "", default=["string", "sdfsdf"], default_multi="prout", multi=True) + descr = OptionDescription("options", "", [s]) + api = getapi(Config(descr)) + api.option('string').value.set([undefined, 'foo']) + assert api.option('string').value.get() == ['string', 'foo'] + + +def test_reset(): + "if value is None, resets to default owner" + s = StrOption("string", "", default="string") + descr = OptionDescription("options", "", [s]) + api = getapi(Config(descr)) + api.option('string').value.set('foo') + assert api.option('string').value.get() == "foo" + assert api.option('string').owner.get() ==owners.user + api.option('string').value.reset() + assert api.option('string').value.get() == 'string' + assert api.option('string').owner.get() ==owners.default + + +def test_reset_with_multi(): + s = StrOption("string", "", default=["string"], default_multi="string", multi=True) + descr = OptionDescription("options", "", [s]) + api = getapi(Config(descr)) +# api.option('string').value.set([]) + api.option('string').value.reset() + assert api.option('string').value.get() == ["string"] + assert api.option('string').owner.get() =='default' + api.option('string').value.set(["eggs", "spam", "foo"]) + assert api.option('string').owner.get() =='user' + api.option('string').value.set([]) + api.option('string').value.reset() +# assert api.option('string').value.get() == ["string"] + assert api.option('string').owner.get() =='default' + raises(ValueError, "api.option('string').value.set(None)") + + +def test_default_with_multi(): + "default with multi is a list" + s = StrOption("string", "", default=[], default_multi="string", multi=True) + descr = OptionDescription("options", "", [s]) + api = getapi(Config(descr)) + assert api.option('string').value.get() == [] + s = StrOption("string", "", default=None, default_multi="string", multi=True) + descr = OptionDescription("options", "", [s]) + api = getapi(Config(descr)) + assert api.option('string').value.get() == [] + + +def test_idontexist(): + descr = make_description() + api = getapi(Config(descr)) + api.option.make_dict() + raises(AttributeError, "api.option('idontexist').value.get()") + + +# ____________________________________________________________ +def test_attribute_access_with_multi(): + s = StrOption("string", "", default=["string"], default_multi="string", multi=True) + descr = OptionDescription("options", "", [s]) + api = getapi(Config(descr)) + api.option('string').value.set(["foo", "bar"]) + assert api.option('string').value.get() == ["foo", "bar"] + + +def test_item_access_with_multi(): + s = StrOption("string", "", default=["string"], multi=True) + descr = OptionDescription("options", "", [s]) + api = getapi(Config(descr)) + api.option('string').value.set(["foo", "bar"]) + assert api.option('string').value.get() == ["foo", "bar"] + api.option('string').value.set(["changetest", "bar"]) + assert api.option('string').value.get() == ["changetest", "bar"] + + +def test_access_with_multi_default(): + s = StrOption("string", "", default=["string"], multi=True) + descr = OptionDescription("options", "", [s]) + api = getapi(Config(descr)) + assert api.option('string').owner.get() =='default' + api.option('string').value.set(["foo", "bar"]) + assert api.option('string').value.get() == ["foo", "bar"] + assert api.option('string').owner.get() =='user' + + +def test_multi_with_requires(): + s = StrOption("string", "", default=["string"], default_multi="string", multi=True) + intoption = IntOption('int', 'Test int option', default=0) + stroption = StrOption('str', 'Test string option', default=["abc"], default_multi="abc", + requires=[{'option': intoption, 'expected': 1, 'action': 'hidden'}], multi=True) + descr = OptionDescription("options", "", [s, intoption, stroption]) + api = getapi(Config(descr)) + api.property.read_write() + assert not 'hidden' in api.option('str').property.get() + api.option('int').value.set(1) + raises(PropertiesOptionError, "api.option('str').value.set(['a', 'b'])") + assert 'hidden' in api.option('str').property.get() + + +def test__requires_with_inverted(): + s = StrOption("string", "", default=["string"], multi=True) + intoption = IntOption('int', 'Test int option', default=0) + stroption = StrOption('str', 'Test string option', default=["abc"], default_multi="abc", + requires=[{'option': intoption, 'expected': 1, 'action': 'hide', 'inverse': True}], multi=True) + descr = OptionDescription("options", "", [s, intoption, stroption]) + api = getapi(Config(descr)) + assert not 'hidden' in api.option('str').property.get() + api.option('int').value.set(1) + assert not 'hidden' in api.option('str').property.get() + + +def test_multi_with_requires_in_another_group(): + s = StrOption("string", "", default=["string"], multi=True) + intoption = IntOption('int', 'Test int option', default=0) + stroption = StrOption('str', 'Test string option', default=["abc"], + requires=[{'option': intoption, 'expected': 1, 'action': 'hidden'}], multi=True) + descr = OptionDescription("opt", "", [stroption]) + descr2 = OptionDescription("opt2", "", [intoption, s, descr]) + api = getapi(Config(descr2)) + api.property.read_write() + assert not 'hidden' in api.option('opt.str').property.get() + api.option('int').value.set(1) + raises(PropertiesOptionError, "api.option('opt.str').value.set(['a', 'b'])") + assert 'hidden' in api.option('opt.str').property.get() + + +def test_multi_with_requires_in_another_group_inverse(): + s = StrOption("string", "", default=["string"], multi=True) + intoption = IntOption('int', 'Test int option', default=0) + stroption = StrOption('str', 'Test string option', default=["abc"], + requires=[{'option': intoption, 'expected': 0, 'action': 'hidden', 'inverse': True}], multi=True) + descr = OptionDescription("opt", "", [stroption]) + descr2 = OptionDescription("opt2", "", [intoption, s, descr]) + api = getapi(Config(descr2)) + api.property.read_write() + assert not 'hidden' in api.option('opt.str').property.get() + api.option('int').value.set(1) + raises(PropertiesOptionError, "api.option('opt.str').value.set(['a', 'b'])") + assert 'hidden' in api.option('opt.str').property.get() + + +def test_apply_requires_from_config(): + s = StrOption("string", "", default=["string"], multi=True) + intoption = IntOption('int', 'Test int option', default=0) + stroption = StrOption('str', 'Test string option', default=["abc"], + requires=[{'option': intoption, 'expected': 1, 'action': 'hidden'}], multi=True) + descr = OptionDescription("opt", "", [stroption]) + descr2 = OptionDescription("opt2", "", [intoption, s, descr]) + api = getapi(Config(descr2)) + api.property.read_write() + assert not 'hidden' in api.option('opt.str').property.get() + api.option('int').value.set(1) + raises(PropertiesOptionError, "api.option('opt.str').value.get()") + assert 'hidden' in api.option('opt.str').property.get() + + +def test_apply_requires_with_disabled(): + s = StrOption("string", "", default=["string"], multi=True) + intoption = IntOption('int', 'Test int option', default=0) + stroption = StrOption('str', 'Test string option', default=["abc"], + requires=[{'option': intoption, 'expected': 1, 'action': 'disabled'}], multi=True) + descr = OptionDescription("opt", "", [stroption]) + descr2 = OptionDescription("opt2", "", [intoption, s, descr]) + api = getapi(Config(descr2)) + api.property.read_write() + assert not 'disabled' in api.option('opt.str').property.get() + api.option('int').value.set(1) + raises(PropertiesOptionError, "api.option('opt.str').value.get()") + assert 'disabled' in api.option('opt.str').property.get() + + +def test_multi_with_requires_with_disabled_in_another_group(): + s = StrOption("string", "", default=["string"], multi=True) + intoption = IntOption('int', 'Test int option', default=0) + stroption = StrOption('str', 'Test string option', default=["abc"], + requires=[{'option': intoption, 'expected': 1, 'action': 'disabled'}], multi=True) + descr = OptionDescription("opt", "", [stroption]) + descr2 = OptionDescription("opt2", "", [intoption, s, descr]) + api = getapi(Config(descr2)) + api.property.read_write() + assert not 'disabled' in api.option('opt.str').property.get() + api.option('int').value.set(1) + raises(PropertiesOptionError, "api.option('opt.str').value.set(['a', 'b'])") + assert 'disabled' in api.option('opt.str').property.get() + + +def test_multi_with_requires_that_is_multi(): + b = IntOption('int', 'Test int option', default=[0], multi=True) + c = StrOption('str', 'Test string option', default=['abc'], requires=[{'option': b, 'expected': 1, 'action': 'hidden'}], multi=True) + descr = OptionDescription("opt", "", [b, c]) + descr + raises(ValueError, "Config(descr)") + + +def test_multi_with_requires_that_is_multi_inverse(): + b = IntOption('int', 'Test int option', default=[0], multi=True) + c = StrOption('str', 'Test string option', default=['abc'], requires=[{'option': b, 'expected': 0, 'action': 'hidden', 'inverse': True}], multi=True) + descr = OptionDescription("opt", "", [b, c]) + descr + raises(ValueError, "Config(descr)") + + +def test_multi_with_requires_that_is_masterslave(): + b = IntOption('int', 'Test int option', default=[0], multi=True) + c = StrOption('str', 'Test string option', requires=[{'option': b, 'expected': 1, 'action': 'hidden'}], multi=True) + descr = MasterSlaves("int", "", [b, c]) + #descr.impl_set_group_type(groups.master) + Config(descr) + + +def test_multi_with_requires_that_is_masterslave_master(): + b = IntOption('int', 'Test int option', multi=True) + c = StrOption('str', 'Test string option', requires=[{'option': b, 'expected': 1, 'action': 'hidden'}], multi=True) + descr = MasterSlaves("str", "", [c, b]) + descr2 = OptionDescription('descr', '', [descr]) + raises(ValueError, "Config(descr2)") + + +def test_multi_with_requires_that_is_masterslave_slave(): + b = IntOption('int', 'Test int option', default=[0], multi=True) + c = StrOption('str', 'Test string option', multi=True) + d = StrOption('str1', 'Test string option', requires=[{'option': c, 'expected': '1', 'action': 'hidden'}], multi=True) + descr = MasterSlaves("int", "", [b, c, d]) + descr2 = OptionDescription('od', '', [descr]) + api = getapi(Config(descr2)) + api.property.read_write() + assert api.option('int.int').value.get() == [0] + assert api.option('int.str', 0).value.get() == None + assert api.option('int.str1', 0).value.get() == None + api.option('int.int').value.set([0, 1]) + assert api.option('int.int').value.get() == [0, 1] + assert api.option('int.str', 0).value.get() == None + assert api.option('int.str', 1).value.get() == None + assert api.option('int.str1', 0).value.get() == None + assert api.option('int.str1', 1).value.get() == None + api.option('int.str', 1).value.set('1') + api.property.read_only() + assert api.option('int.str1', 0).value.get() == None + assert api.option('int.str1', 1).value.get() == None + api.property.read_write() + assert api.option('int.str1', 0).value.get() == None + raises(PropertiesOptionError, "api.option('int.str1', 1).value.get()") + + +def test_multi_with_requires_that_is_masterslave_slave_inverse(): + b = IntOption('int', 'Test int option', default=[0], multi=True) + c = StrOption('str', 'Test string option', multi=True) + d = StrOption('str1', 'Test string option', requires=[{'option': c, 'expected': None, 'action': 'hidden', 'inverse': True}], multi=True) + descr = MasterSlaves("int", "", [b, c, d]) + descr2 = OptionDescription('od', '', [descr]) + api = getapi(Config(descr2)) + api.property.read_write() + assert api.option('int.int').value.get() == [0] + assert api.option('int.str', 0).value.get() is None + assert api.option('int.str1', 0).value.get() is None + api.option('int.int').value.set([0, 1]) + assert api.option('int.int').value.get() == [0, 1] + assert api.option('int.str', 0).value.get() is None + assert api.option('int.str', 1).value.get() is None + assert api.option('int.str1', 0).value.get() is None + assert api.option('int.str1', 1).value.get() is None + api.option('int.str', 1).value.set('1') + api.property.read_only() + assert api.option('int.str1', 0).value.get() is None + assert api.option('int.str1', 1).value.get() is None + api.property.read_write() + assert api.option('int.str1', 0).value.get() is None + raises(PropertiesOptionError, "api.option('int.str1', 1).value.get()") + + +def test_multi_with_requires_that_is_not_same_masterslave(): + b = IntOption('int', 'Test int option', default=[0], multi=True) + c = StrOption('str', 'Test string option', requires=[{'option': b, 'expected': 1, 'action': 'hidden'}], multi=True) + descr1 = MasterSlaves("int", "", [b, c]) + #descr1.impl_set_group_type(groups.master) + d = IntOption('int1', 'Test int option', default=[0], multi=True) + e = StrOption('str', 'Test string option', requires=[{'option': b, 'expected': 1, 'action': 'hidden'}], multi=True) + descr2 = MasterSlaves("int1", "", [d, e]) + #descr2.impl_set_group_type(groups.master) + descr3 = OptionDescription('val', '', [descr1, descr2]) + descr3 + raises(ValueError, "Config(descr3)") + + +def test_multi_with_bool(): + s = BoolOption("bool", "", default=[False], multi=True) + descr = OptionDescription("options", "", [s]) + api = getapi(Config(descr)) + api.option('bool').value.set([True, False]) + assert api.option('bool').value.get() == [True, False] + + +def test_choice_access_with_multi(): + ch = ChoiceOption("t1", "", ("a", "b"), default=["a"], multi=True) + descr = OptionDescription("options", "", [ch]) + api = getapi(Config(descr)) + api.option('t1').value.set(["a", "b", "a", "b"]) + assert api.option('t1').value.get() == ["a", "b", "a", "b"] + + +#____________________________________________________________ +def test_accepts_multiple_changes_from_option(): + s = StrOption("string", "", default="string") + descr = OptionDescription("options", "", [s]) + api = getapi(Config(descr)) + api.option('string').value.set("egg") + assert api.option('string').option.default() == "string" + assert api.option('string').value.get() == "egg" + api.option('string').value.set('blah') + assert api.option('string').option.default() == "string" + assert api.option('string').value.get() == "blah" + api.option('string').value.set('bol') + assert api.option('string').value.get() == 'bol' + + +def test_allow_multiple_changes_from_config(): + """ + a `setoption` from the config object is much like the attribute access, + except the fact that value owner can bet set + """ + s = StrOption("string", "", default="string") + s2 = StrOption("string2", "", default="string") + suboption = OptionDescription("bip", "", [s2]) + descr = OptionDescription("options", "", [s, suboption]) + api = getapi(Config(descr)) + api.option('string').value.set("oh") + assert api.option('string').value.get() == "oh" + api.option('string').value.set("blah") + assert api.option('string').value.get() == "blah" + + +# ____________________________________________________________ +# accessing a value by the get method +def test_access_by_get(): + descr = make_description() + api = getapi(Config(descr)) + raises(AttributeError, "api.option.find('idontexist')") + assert api.option.find_first('wantref', type='value') is False + assert api.option.find_first('dummy', type='value') is False + + +def test_access_by_get_whith_hide(): + b1 = BoolOption("b1", "", properties=(('hidden'),)) + descr = OptionDescription("opt", "", + [OptionDescription("sub", "", + [b1, ChoiceOption("c1", "", ('a', 'b', 'c'), 'a'), + BoolOption("d1", "")]), + BoolOption("b2", ""), + BoolOption("d1", "")]) + api = getapi(Config(descr)) + api.property.read_write() + raises(AttributeError, "api.option.find('b1', type='value')") + + +def test_append_properties(): + descr = make_description() + api = getapi(Config(descr)) + assert api.option('gc.dummy').property.get() == set() + api.option('gc.dummy').property.add('test') + assert api.option('gc.dummy').property.get() == {'test'} + raises(ConfigError, "api.option('gc.dummy').property.add('force_store_value')") + assert api.option('gc.dummy').property.get() == {'test'} + + +def test_reset_properties(): + descr = make_description() + api = getapi(Config(descr)) + assert api.option('gc.dummy').property.get() == set() + api.option('gc.dummy').property.add('frozen') + assert api.option('gc.dummy').property.get() == {'frozen'} + api.option('gc.dummy').property.reset() + assert api.option('gc.dummy').property.get() == set() + + +def test_properties_cached(): + b1 = BoolOption("b1", "", properties=('test',)) + descr = OptionDescription("opt", "", [OptionDescription("sub", "", [b1])]) + api = getapi(Config(descr)) + api.property.read_write() + assert api.option('sub.b1').property.get() == {'test'} + + +def test_append_properties_force_store_value(): + gcdummy = BoolOption('dummy', 'dummy', default=False, properties=('force_store_value',)) + gcgroup = OptionDescription('gc', '', [gcdummy]) + descr = OptionDescription('tiramisu', '', [gcgroup]) + api = getapi(Config(descr)) + assert api.option('gc.dummy').property.get() == {'force_store_value'} + api.option('gc.dummy').property.add('test') + assert api.option('gc.dummy').property.get() == {'force_store_value', 'test'} + + +def test_reset_properties_force_store_value(): + gcdummy = BoolOption('dummy', 'dummy', default=False, properties=('force_store_value',)) + gcgroup = OptionDescription('gc', '', [gcdummy]) + descr = OptionDescription('tiramisu', '', [gcgroup]) + api = getapi(Config(descr)) + assert api.property.get_modified() == {} + api.property.add('frozen') + assert api.property.get_modified() == \ + {None: set(('frozen', 'expire', 'cache', 'validator', 'warnings'))} + api.property.reset() + assert api.property.get_modified() == {} + api.option('gc.dummy').property.add('test') + assert api.property.get_modified() == {'gc.dummy': set(('test', 'force_store_value'))} + api.property.reset() + assert api.property.get_modified() == {'gc.dummy': set(('test', 'force_store_value'))} + api.property.add('frozen') + assert api.property.get_modified() == \ + {None: set(('frozen', 'expire', 'validator', 'cache', 'warnings')), + 'gc.dummy': set(('test', 'force_store_value'))} + api.property.add('frozen') + assert api.property.get_modified() == \ + {None: set(('frozen', 'expire', 'validator', 'cache', 'warnings')), + 'gc.dummy': set(('test', 'force_store_value'))} + api.option('gc.dummy').property.add('test') + assert api.property.get_modified() == \ + {None: set(('frozen', 'expire', 'validator', 'cache', 'warnings')), + 'gc.dummy': set(('test', 'force_store_value'))} + + +def test_set_modified_value(): + gcdummy = BoolOption('dummy', 'dummy', default=False, properties=('force_store_value',)) + gcgroup = OptionDescription('gc', '', [gcdummy]) + descr = OptionDescription('tiramisu', '', [gcgroup]) + api = getapi(Config(descr)) + assert api.property.get_modified() == {} + api.property.set_modified({None: set(('frozen', 'expire', 'cache', 'validator', 'warnings'))}) + assert api.property.get_modified() == \ + {None: set(('frozen', 'expire', 'cache', 'validator', 'warnings'))} + + +def test_pprint(): + msg_error = _("cannot access to {0} \"{1}\" because has {2} {3}") + msg_is = _('the value of "{0}" is "{1}"') + msg_is_not = _('the value of "{0}" is not {1}') + properties = _('properties') + prop = _('property') + + s = StrOption("string", "", default=["string"], default_multi="string", multi=True, properties=('hidden', 'disabled')) + s2 = StrOption("string2", "", default="string") + s3 = StrOption("string3", "", default=["string"], default_multi="string", multi=True, properties=('hidden',)) + intoption = IntOption('int', 'Test int option', default=0) + stroption = StrOption('str', 'Test string option', default="abc", + requires=[{'option': intoption, 'expected': 2, 'action': 'hidden', 'inverse': True}, + {'option': intoption, 'expected': 3, 'action': 'hidden', 'inverse': True}, + {'option': intoption, 'expected': 4, 'action': 'hidden', 'inverse': True}, + {'option': intoption, 'expected': 1, 'action': 'disabled'}, + {'option': s2, 'expected': 'string', 'action': 'disabled'}]) + + val2 = StrOption('val2', "") + descr2 = OptionDescription("options", "", [val2], requires=[{'option': intoption, 'expected': 1, 'action': 'hidden'}]) + + val3 = StrOption('val3', "", requires=[{'option': stroption, 'expected': '2', 'action': 'hidden', 'inverse': True}]) + + descr = OptionDescription("options", "", [s, s2, s3, intoption, stroption, descr2, val3]) + api = getapi(Config(descr)) + api.property.read_write() + api.option('int').value.set(1) + err = None + try: + api.option('str').value.get() + except PropertiesOptionError as error: + err = error + + list_disabled = '"disabled" (' + display_list([msg_is.format('Test int option', '1'), msg_is.format('string2', 'string')]) + ')' + list_hidden = '"hidden" (' + msg_is_not.format('Test int option', display_list([2, 3, 4], 'or', add_quote=True)) + ')' + assert str(err) == _(msg_error.format('option', 'Test string option', properties, display_list([list_disabled, list_hidden]))) + + err = None + try: + api.option('options.val2').value.get() + except PropertiesOptionError as error: + err = error + + assert str(err) == msg_error.format('optiondescription', 'options', prop, '"hidden" (' + msg_is.format('Test int option', 1) + ')') + + err = None + try: + api.option('val3').value.get() + except PropertiesOptionError as error: + err = error + + msg_1 = msg_is.format('string2', 'string') + msg_2 = msg_is.format('Test int option', 1) + msg_3 = msg_is_not.format('Test int option', display_list([2, 3, 4], 'or', add_quote=True)) + + list_hidden = '"hidden" (' + display_list([msg_2, msg_3, msg_1]) + ')' + assert str(err) == msg_error.format('option', 'val3', prop, list_hidden) + + err = None + try: + api.option('string').value.get() + except Exception as error: + err = error + + assert str(err) == msg_error.format('option', 'string', properties, display_list(['disabled', 'hidden'])) + + err = None + try: + api.option('string3').value.get() + except Exception as error: + err = error + + assert str(err) == msg_error.format('option', 'string3', prop, 'hidden') diff --git a/tiramisu/api.py b/tiramisu/api.py index 6cbe713..2862a2e 100644 --- a/tiramisu/api.py +++ b/tiramisu/api.py @@ -171,12 +171,12 @@ class TiramisuOptionOption(CommonTiramisuOption): return self._opt.impl_get_display_name() @count - def getdefault(self): - return self._opt.impl_getdefault() + def default(self): + return self.config_bag.option.impl_getdefault() @count - def getdefaultmulti(self): - return self._opt.impl_getdefault_multi() + def defaultmulti(self): + return self.config_bag.option.impl_getdefault_multi() @count def has_dependency(self, self_is_dep=True): @@ -263,9 +263,9 @@ class TiramisuOptionProperty(CommonTiramisuOption): @count def add(self, prop): - props = self.get() - props.add(prop) - self.set(props) + self.settings.addproperty(self.path, + prop, + self.config_bag) @count def pop(self, prop): @@ -277,8 +277,8 @@ class TiramisuOptionProperty(CommonTiramisuOption): def reset(self): """reset all personalised properties """ - self.settings.reset(opt=self._opt, - path=self._path) + self.settings.reset(opt=self.config_bag.option, + path=self.path) class TiramisuOptionPermissive(CommonTiramisuOption): @@ -485,7 +485,7 @@ class TiramisuContextValue(TiramisuContext): return self.config_bag.config.cfgimpl_get_values().mandatory_warnings(self.config_bag) @count - def get(self): + def get_modified(self): return self.config_bag.config.cfgimpl_get_values().get_modified_values() @@ -538,11 +538,22 @@ class TiramisuContextProperty(TiramisuContext): def get(self): return set(self.config_bag.setting_properties) + @count + def get_modified(self): + return self.config_bag.config.cfgimpl_get_settings().get_modified_properties() + + @count + def set_modified(self, props): + return self.config_bag.config.cfgimpl_get_settings().set_modified_properties(props) + @count def set(self, props): self.config_bag.config.cfgimpl_get_settings().set_context_properties(frozenset(props)) self.config_bag.setting_properties = self.config_bag.config.cfgimpl_get_settings().get_context_properties() + def reset(self): + self.config_bag.config.cfgimpl_get_settings().reset() + class TiramisuContextPermissive(TiramisuContext): diff --git a/tiramisu/error.py b/tiramisu/error.py index 406e686..db784c4 100644 --- a/tiramisu/error.py +++ b/tiramisu/error.py @@ -18,7 +18,7 @@ from .i18n import _ -def display_list(lst, separator='and'): +def display_list(lst, separator='and', add_quote=False): if separator == 'and': separator = _('and') elif separator == 'or': @@ -29,7 +29,9 @@ def display_list(lst, separator='and'): ret = lst[0] if not isinstance(ret, str): ret = str(ret) - return '"{}"'.format(ret) + if add_quote: + ret = '"{}"'.format(ret) + return ret else: if isinstance(lst, tuple): lst = list(lst) @@ -38,11 +40,15 @@ def display_list(lst, separator='and'): for l in lst[:-1]: if not isinstance(l, str): l = str(l) - lst_.append('"{}"'.join(_(l))) + if add_quote: + l = '"{}"'.format(l) + lst_.append(_(l)) last = lst[-1] if not isinstance(last, str): last = str(_(last)) - return ', '.join(lst_) + _(' {} ').format(separator) + '"{}"'.format(last) + if add_quote: + last = '"{}"'.format(last) + return ', '.join(lst_) + _(' {} ').format(separator) + '{}'.format(last) # Exceptions for an Option @@ -75,7 +81,7 @@ class PropertiesOptionError(AttributeError): only_one = len(req) == 1 msg = [] for action, msg_ in req.items(): - msg.append('{0} ({1})'.format(action, display_list(msg_))) + msg.append('"{0}" ({1})'.format(action, display_list(msg_))) else: only_one = len(self.proptype) == 1 msg = list(self.proptype) diff --git a/tiramisu/setting.py b/tiramisu/setting.py index 0cd8c88..4795fe9 100644 --- a/tiramisu/setting.py +++ b/tiramisu/setting.py @@ -106,7 +106,7 @@ rw_append = set(['frozen', 'disabled', 'validator', 'hidden']) rw_remove = set(['permissive', 'everything_frozen', 'mandatory', 'empty']) -forbidden_set_properties = frozenset(['force_store_value']) +FORBIDDEN_SET_PROPERTIES = frozenset(['force_store_value']) forbidden_set_permissives = frozenset(['frozen', 'force_default_on_freeze']) @@ -368,14 +368,13 @@ class Settings(object): path, index, config_bag) - requires = self.apply_requires(path, - index, - False, - config_bag) - #FIXME devrait etre un frozenset! - if requires != set([]): - props = copy(props) - props |= requires + props |= self.apply_requires(path, + index, + False, + config_bag) + #if requires != set([]): + # props = copy(props) + # props |= requires props -= self.getpermissive(opt, path) @@ -525,16 +524,16 @@ class Settings(object): if operator != 'and': if debug: if isinstance(orig_value, PropertiesOptionError): - for msg in orig_value.cfgimpl_get_settings().apply_requires(**orig_value._datas).values(): + for msg in orig_value._settings.apply_requires(**orig_value._datas).values(): calc_properties.setdefault(action, []).extend(msg) else: if not inverse: - msg = _('the value of "{0}" is "{1}"') + msg = _('the value of "{0}" is {1}') else: - msg = _('the value of "{0}" is not "{1}"') + msg = _('the value of "{0}" is not {1}') calc_properties.setdefault(action, []).append( msg.format(option.impl_get_display_name(), - display_list(expected, 'or'))) + display_list(expected, 'or', add_quote=True))) else: calc_properties.add(action) breaked = True @@ -560,7 +559,8 @@ class Settings(object): def setproperties(self, path, properties, - config_bag): + config_bag, + force=False): """save properties for specified path (never save properties if same has option properties) """ @@ -573,10 +573,11 @@ class Settings(object): if opt and opt.impl_is_symlinkoption(): raise TypeError(_("can't assign properties to the SymLinkOption \"{}\"" "").format(opt.impl_get_display_name())) - forbidden_properties = forbidden_set_properties & properties - if forbidden_properties: - raise ConfigError(_('cannot add those properties: {0}').format( - ' '.join(forbidden_properties))) + if not force: + forbidden_properties = FORBIDDEN_SET_PROPERTIES & properties + if forbidden_properties: + raise ConfigError(_('cannot add those properties: {0}').format( + ' '.join(forbidden_properties))) if not isinstance(properties, frozenset): raise TypeError(_('properties must be a frozenset')) self._p_.setproperties(path, @@ -585,6 +586,22 @@ class Settings(object): self._getcontext().cfgimpl_reset_cache(opt=opt, path=path) + def addproperty(self, + path, + property_, + config_bag): + if property_ in FORBIDDEN_SET_PROPERTIES: + raise ConfigError(_('cannot add this property: "{0}"').format( + ' '.join(property_))) + + props = self.getproperties(path, + None, + config_bag) + self.setproperties(path, + props | {property_}, + config_bag, + force=True) + def set_context_permissive(self, permissive): self.setpermissive(None, None, permissive) @@ -665,20 +682,6 @@ class Settings(object): config_bag.properties = self_properties properties = self_properties & config_bag.setting_properties - {'frozen', 'mandatory', 'empty'} if not opt.impl_is_optiondescription(): - ##mandatory - #if 'mandatory' in properties or 'empty' in properties: - # value = self._getcontext().cfgimpl_get_values().get_cached_value(path, - # index, - # config_bag) - # sconfig_bag = config_bag.copy() - # sconfig_bag.properties = properties - # if not self.validate_mandatory(index, - # value, - # sconfig_bag): - # properties -= set(['mandatory']) - # else: - # properties |= set(['mandatory']) - # properties -= set(['empty']) opt_type = 'option' else: opt_type = 'optiondescription' @@ -764,6 +767,9 @@ class Settings(object): def get_modified_properties(self): return self._p_.get_modified_properties() + def set_modified_properties(self, props): + return self._p_.set_modified_properties(props) + def get_modified_permissives(self): return self._pp_.get_modified_permissives()