From d4ef47759e6597d0e879c3aaad931baef6f4087a Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Sat, 20 Apr 2013 17:30:05 +0200 Subject: [PATCH] Manipulate properties is now more convenient: c.cfgimpl_get_settings().has_property('hidden') => 'hidden' in c.cfgimpl_get_settings() c.cfgimpl_get_settings().has_property('hidden', option1) => 'frozen' in c.cfgimpl_get_settings()[opt] c.cfgimpl_get_settings().get_properties(option1) => c.cfgimpl_get_settings()[option1] c.cfgimpl_get_settings().get_properties(option1) => c.cfgimpl_get_settings()[option1] c.cfgimpl_get_settings().add_property('hidden', option1) => c.cfgimpl_get_settings()[optiont1].append('hidden') c.cfgimpl_get_settings().del_property('hidden', option1) => c.cfgimpl_get_settings()[optiont1].remove('hidden') c.cfgimpl_get_settings().enable_property('hidden') => c.cfgimpl_get_settings().append('hidden') c.cfgimpl_get_settings().disable_property('hidden') => c.cfgimpl_get_settings().remove('hidden') --- test/test_cache.py | 179 +++++++++++++++++++++++ test/test_freeze.py | 22 +-- test/test_mandatory.py | 6 +- test/test_option_consistency.py | 15 +- test/test_option_default.py | 5 +- test/test_option_setting.py | 29 ++-- test/test_option_type.py | 29 ++-- test/test_option_with_special_name.py | 38 ++--- test/test_permissive.py | 83 +++++++++++ tiramisu/setting.py | 195 +++++++++++++------------- tiramisu/value.py | 14 +- 11 files changed, 443 insertions(+), 172 deletions(-) create mode 100644 test/test_cache.py create mode 100644 test/test_permissive.py diff --git a/test/test_cache.py b/test/test_cache.py new file mode 100644 index 0000000..2bc35fe --- /dev/null +++ b/test/test_cache.py @@ -0,0 +1,179 @@ +# coding: utf-8 +import autopath +from tiramisu import setting +setting.expires_time = 1 +from tiramisu.option import IntOption, OptionDescription +from tiramisu.config import Config +from time import sleep + + +def make_description(): + u1 = IntOption('u1', '', multi=True) + u2 = IntOption('u2', '') + u3 = IntOption('u3', '', multi=True) + return OptionDescription('od1', '', [u1, u2, u3]) + + +def test_cache(): + od1 = make_description() + c = Config(od1) + values = c.cfgimpl_get_values() + settings = c.cfgimpl_get_settings() + c.u1 + assert od1.u1 in values._cache + assert od1.u1 in settings._cache + c.u2 + assert od1.u1 in values._cache + assert od1.u1 in settings._cache + assert od1.u2 in values._cache + assert od1.u2 in settings._cache + + +def test_cache_reset(): + od1 = make_description() + c = Config(od1) + values = c.cfgimpl_get_values() + settings = c.cfgimpl_get_settings() + #when change a value + c.u1 + assert od1.u1 in values._cache + assert od1.u1 in settings._cache + c.u2 = 1 + assert od1.u1 not in values._cache + assert od1.u1 not in settings._cache + #when remove a value + c.u1 + assert od1.u1 in values._cache + assert od1.u1 in settings._cache + del(c.u2) + assert od1.u1 not in values._cache + assert od1.u1 not in settings._cache + #when add/del property + c.u1 + assert od1.u1 in values._cache + assert od1.u1 in settings._cache + c.cfgimpl_get_settings()[od1.u2].append('test') + assert od1.u1 not in values._cache + assert od1.u1 not in settings._cache + c.u1 + assert od1.u1 in values._cache + assert od1.u1 in settings._cache + c.cfgimpl_get_settings()[od1.u2].remove('test') + assert od1.u1 not in values._cache + assert od1.u1 not in settings._cache + #when enable/disabled property + c.u1 + assert od1.u1 in values._cache + assert od1.u1 in settings._cache + c.cfgimpl_get_settings().append('test') + assert od1.u1 not in values._cache + assert od1.u1 not in settings._cache + c.u1 + assert od1.u1 in values._cache + assert od1.u1 in settings._cache + c.cfgimpl_get_settings().remove('test') + assert od1.u1 not in values._cache + assert od1.u1 not in settings._cache + + +def test_cache_reset_multi(): + od1 = make_description() + c = Config(od1) + values = c.cfgimpl_get_values() + settings = c.cfgimpl_get_settings() + #when change a value + c.u1 + assert od1.u1 in values._cache + assert od1.u1 in settings._cache + c.u3 = [1] + assert od1.u1 not in values._cache + assert od1.u1 not in settings._cache + #when append value + c.u1 + assert od1.u1 in values._cache + assert od1.u1 in settings._cache + c.u3.append(1) + assert od1.u1 not in values._cache + assert od1.u1 not in settings._cache + #when pop value + c.u1 + assert od1.u1 in values._cache + assert od1.u1 in settings._cache + c.u3.pop(1) + assert od1.u1 not in values._cache + assert od1.u1 not in settings._cache + #when remove a value + c.u1 + assert od1.u1 in values._cache + assert od1.u1 in settings._cache + del(c.u3) + assert od1.u1 not in values._cache + assert od1.u1 not in settings._cache + + +def test_reset_cache(): + od1 = make_description() + c = Config(od1) + values = c.cfgimpl_get_values() + settings = c.cfgimpl_get_settings() + c.u1 + assert od1.u1 in values._cache + assert od1.u1 in settings._cache + c.cfgimpl_reset_cache() + assert od1.u1 not in values._cache + assert od1.u1 not in settings._cache + c.u1 + sleep(1) + c.u2 + assert od1.u1 in values._cache + assert od1.u1 in settings._cache + assert od1.u2 in values._cache + assert od1.u2 in settings._cache + c.cfgimpl_reset_cache() + assert od1.u1 not in values._cache + assert od1.u1 not in settings._cache + assert od1.u2 not in values._cache + assert od1.u2 not in settings._cache + + +def test_reset_cache_only_expired(): + od1 = make_description() + c = Config(od1) + values = c.cfgimpl_get_values() + settings = c.cfgimpl_get_settings() + c.u1 + assert od1.u1 in values._cache + assert od1.u1 in settings._cache + c.cfgimpl_reset_cache(True) + assert od1.u1 in values._cache + assert od1.u1 in settings._cache + sleep(1) + c.u2 + assert od1.u1 in values._cache + assert od1.u1 in settings._cache + assert od1.u2 in values._cache + assert od1.u2 in settings._cache + c.cfgimpl_reset_cache(True) + assert od1.u1 not in values._cache + assert od1.u1 not in settings._cache + assert od1.u2 in values._cache + assert od1.u2 in settings._cache + + +def test_reset_cache_only(): + od1 = make_description() + c = Config(od1) + values = c.cfgimpl_get_values() + settings = c.cfgimpl_get_settings() + c.u1 + assert od1.u1 in values._cache + assert od1.u1 in settings._cache + c.cfgimpl_reset_cache(only=('values',)) + assert od1.u1 not in values._cache + assert od1.u1 in settings._cache + c.u1 + assert od1.u1 in values._cache + assert od1.u1 in settings._cache + c.cfgimpl_reset_cache(only=('settings',)) + assert od1.u1 in values._cache + assert od1.u1 not in settings._cache diff --git a/test/test_freeze.py b/test/test_freeze.py index 81127e4..d1d3217 100644 --- a/test/test_freeze.py +++ b/test/test_freeze.py @@ -39,7 +39,7 @@ def test_freeze_whole_config(): conf = Config(descr) setting = conf.cfgimpl_get_settings() setting.read_write() - setting.enable_property('everything_frozen') + setting.append('everything_frozen') assert conf.gc.dummy is False prop = [] try: @@ -47,7 +47,7 @@ def test_freeze_whole_config(): except PropertiesOptionError, err: prop = err.proptype assert 'frozen' in prop - setting.disable_property('everything_frozen') + setting.remove('everything_frozen') conf.gc.dummy = True assert conf.gc.dummy is True @@ -60,7 +60,7 @@ def test_freeze_one_option(): setting.read_write() #freeze only one option dummy = conf.unwrap_from_path('gc.dummy') - setting.add_property('frozen', dummy) + setting[dummy].append('frozen') assert conf.gc.dummy is False prop = [] try: @@ -77,8 +77,8 @@ def test_frozen_value(): config = Config(descr) setting = config.cfgimpl_get_settings() setting.read_write() - setting.enable_property('frozen') - setting.add_property('frozen', s) + setting.append('frozen') + setting[s].append('frozen') prop = [] try: config.string = "egg" @@ -93,9 +93,9 @@ def test_freeze(): conf = Config(descr) setting = conf.cfgimpl_get_settings() setting.read_write() - setting.enable_property('frozen') + setting.append('frozen') name = conf.unwrap_from_path("gc.name") - setting.add_property('frozen', name) + setting[name].append('frozen') prop = [] try: conf.gc.name = 'framework' @@ -109,9 +109,9 @@ def test_freeze_multi(): conf = Config(descr) setting = conf.cfgimpl_get_settings() setting.read_write() - setting.enable_property('frozen') + setting.append('frozen') obj = conf.unwrap_from_path('boolop') - setting.add_property('frozen', obj) + setting[obj].append('frozen') prop = [] try: conf.boolop = [True] @@ -125,11 +125,11 @@ def test_freeze_get_multi(): conf = Config(descr) setting = conf.cfgimpl_get_settings() setting.read_write() - setting.enable_property('frozen') + setting.append('frozen') valmulti = conf.boolop valmulti.append(False) obj = conf.unwrap_from_path('boolop') - setting.add_property('frozen', obj) + setting[obj].append('frozen') prop = [] try: valmulti.append(False) diff --git a/test/test_mandatory.py b/test/test_mandatory.py index 52456eb..c2911cf 100644 --- a/test/test_mandatory.py +++ b/test/test_mandatory.py @@ -171,7 +171,7 @@ def test_mandatory_disabled(): except PropertiesOptionError, err: prop = err.proptype assert prop == ['mandatory'] - setting.add_property('disabled', descr.str1) + setting[descr.str1].append('disabled') prop = [] try: config.str1 @@ -242,7 +242,7 @@ def test_mandatory_warnings_disabled(): setting.read_write() config.str assert list(mandatory_warnings(config)) == ['str', 'str1', 'unicode2', 'str3'] - setting.add_property('disabled', descr.str) + setting[descr.str].append('disabled') assert list(mandatory_warnings(config)) == ['str1', 'unicode2', 'str3'] @@ -254,6 +254,6 @@ def test_mandatory_warnings_frozen(): setting.read_write() config.str assert list(mandatory_warnings(config)) == ['str', 'str1', 'unicode2', 'str3'] - setting.add_property('frozen', descr.str) + setting[descr.str].append('frozen') setting.read_only() assert list(mandatory_warnings(config)) == ['str', 'str1', 'unicode2', 'str3'] diff --git a/test/test_option_consistency.py b/test/test_option_consistency.py index 88f3626..5a9c3e6 100644 --- a/test/test_option_consistency.py +++ b/test/test_option_consistency.py @@ -159,11 +159,11 @@ def test_hidden_if_in(): setting.read_write() intoption = cfg.unwrap_from_path('int') stroption = cfg.unwrap_from_path('str') - assert not setting.has_property('hidden', stroption) + assert not 'hidden' in setting[stroption] cfg.int = 1 raises(PropertiesOptionError, "cfg.str") raises(PropertiesOptionError, 'cfg.str="uvw"') - assert setting.has_property('hidden', stroption) + assert 'hidden' in setting[stroption] def test_hidden_if_in_with_group(): gcoption = ChoiceOption('name', 'GC name', ('ref', 'framework'), 'ref') @@ -183,7 +183,7 @@ def test_hidden_if_in_with_group(): cfg = Config(descr) setting = cfg.cfgimpl_get_settings() setting.read_write() - assert not setting.has_property('hidden', stroption) + assert not 'hidden' in setting[stroption] cfg.int = 1 raises(PropertiesOptionError, "cfg.gc.name") @@ -241,8 +241,8 @@ def test_has_callback(): config.bool = False # because dummy has a callback dummy = config.unwrap_from_path('gc.dummy') - setting.enable_property('freeze') - setting.add_property('frozen', dummy) + setting.append('freeze') + setting[dummy].append('frozen') raises(PropertiesOptionError, "config.gc.dummy = True") def test_freeze_and_has_callback(): @@ -251,8 +251,9 @@ def test_freeze_and_has_callback(): setting = config.cfgimpl_get_settings() setting.read_write() config.bool = False - config.cfgimpl_get_settings().enable_property('freeze') + setting = config.cfgimpl_get_settings() + setting.append('freeze') dummy = config.unwrap_from_path('gc.dummy') - config.cfgimpl_get_settings().add_property('frozen', dummy) + setting[dummy].append('frozen') raises(PropertiesOptionError, "config.gc.dummy = True") #____________________________________________________________ diff --git a/test/test_option_default.py b/test/test_option_default.py index dfe4733..833f4f1 100644 --- a/test/test_option_default.py +++ b/test/test_option_default.py @@ -58,8 +58,9 @@ def test_force_default_on_freeze(): config = Config(group) config.dummy1 = True config.dummy2 = False - config.cfgimpl_get_settings().add_property('frozen', dummy1) - config.cfgimpl_get_settings().add_property('frozen', dummy2) + setting = config.cfgimpl_get_settings() + setting[dummy1].append('frozen') + setting[dummy2].append('frozen') assert config.dummy1 == False assert config.dummy2 == False diff --git a/test/test_option_setting.py b/test/test_option_setting.py index 8bae976..f3b9863 100644 --- a/test/test_option_setting.py +++ b/test/test_option_setting.py @@ -145,10 +145,10 @@ def test_multi_with_requires(): config = Config(descr) setting = config.cfgimpl_get_settings() setting.read_write() - assert not config.cfgimpl_get_settings().has_property('hidden', stroption) + assert not 'hidden' in setting[stroption] config.int = 1 raises(PropertiesOptionError, "config.str = ['a', 'b']") - assert config.cfgimpl_get_settings().has_property('hidden', stroption) + assert 'hidden' in setting[stroption] def test__requires_with_inverted(): @@ -158,9 +158,10 @@ def test__requires_with_inverted(): requires=[('int', 1, 'hide', 'inverted')], multi=True) descr = OptionDescription("options", "", [s, intoption, stroption]) config = Config(descr) - assert not config.cfgimpl_get_settings().has_property('hidden', stroption) + setting = config.cfgimpl_get_settings() + assert not 'hidden' in setting[stroption] config.int = 1 - assert not config.cfgimpl_get_settings().has_property('hidden', stroption) + assert not 'hidden' in setting[stroption] def test_multi_with_requires_in_another_group(): @@ -174,10 +175,10 @@ def test_multi_with_requires_in_another_group(): config = Config(descr2) setting = config.cfgimpl_get_settings() setting.read_write() - assert not config.cfgimpl_get_settings().has_property('hidden', stroption) + assert not 'hidden' in setting[stroption] config.int = 1 raises(PropertiesOptionError, "config.opt.str = ['a', 'b']") - assert config.cfgimpl_get_settings().has_property('hidden', stroption) + assert 'hidden' in setting[stroption] def test_apply_requires_from_config(): @@ -191,10 +192,10 @@ def test_apply_requires_from_config(): config = Config(descr2) setting = config.cfgimpl_get_settings() setting.read_write() - assert not config.cfgimpl_get_settings().has_property('hidden', stroption) + assert not 'hidden' in setting[stroption] config.int = 1 raises(PropertiesOptionError, 'config.opt.str') - assert config.cfgimpl_get_settings().has_property('hidden', stroption) + assert 'hidden' in setting[stroption] def test_apply_requires_with_disabled(): @@ -208,10 +209,10 @@ def test_apply_requires_with_disabled(): config = Config(descr2) setting = config.cfgimpl_get_settings() setting.read_write() - assert not config.cfgimpl_get_settings().has_property('disabled', stroption) + assert not 'disabled' in setting[stroption] config.int = 1 raises(PropertiesOptionError, 'config.opt.str') - assert config.cfgimpl_get_settings().has_property('disabled', stroption) + assert 'disabled' in setting[stroption] def test_multi_with_requires_with_disabled_in_another_group(): @@ -225,10 +226,10 @@ def test_multi_with_requires_with_disabled_in_another_group(): config = Config(descr2) setting = config.cfgimpl_get_settings() setting.read_write() - assert not config.cfgimpl_get_settings().has_property('disabled', stroption) + assert not 'disabled' in setting[stroption] config.int = 1 raises(PropertiesOptionError, "config.opt.str = ['a', 'b']") - assert config.cfgimpl_get_settings().has_property('disabled', stroption) + assert 'disabled' in setting[stroption] def test_multi_with_requires_that_is_multi(): @@ -240,10 +241,10 @@ def test_multi_with_requires_that_is_multi(): config = Config(descr) setting = config.cfgimpl_get_settings() setting.read_write() - assert not config.cfgimpl_get_settings().has_property('hidden', stroption) + assert not 'hidden' in setting[stroption] config.int = [1, 1] raises(PropertiesOptionError, "config.str = ['a', 'b']") - assert config.cfgimpl_get_settings().has_property('hidden', stroption) + assert 'hidden' in setting[stroption] def test_multi_with_bool(): diff --git a/test/test_option_type.py b/test/test_option_type.py index 6ecd73e..d8a5b6b 100644 --- a/test/test_option_type.py +++ b/test/test_option_type.py @@ -45,7 +45,7 @@ def test_is_hidden(): setting = config.cfgimpl_get_settings() setting.read_write() dummy = config.unwrap_from_path('gc.dummy') - assert not config.cfgimpl_get_settings().has_property('frozen', dummy) + assert not 'frozen' in setting[dummy] # setattr raises(PropertiesOptionError, "config.gc.dummy == False") # getattr @@ -59,13 +59,13 @@ def test_group_is_hidden(): setting.read_write() gc = config.unwrap_from_path('gc') config.unwrap_from_path('gc.dummy') - config.cfgimpl_get_settings().add_property('hidden', gc) + setting[gc].append('hidden') raises(PropertiesOptionError, "config.gc.dummy") - assert config.cfgimpl_get_settings().has_property('hidden', gc) + assert 'hidden' in setting[gc] raises(PropertiesOptionError, "config.gc.float") # manually set the subconfigs to "show" - config.cfgimpl_get_settings().del_property('hidden', gc) - assert not config.cfgimpl_get_settings().has_property('hidden', gc) + setting[gc].remove('hidden') + assert not 'hidden' in setting[gc] assert config.gc.float == 2.3 #dummy est en hide prop = [] @@ -83,17 +83,17 @@ def test_group_is_hidden_multi(): setting.read_write() obj = config.unwrap_from_path('objspace') objspace = config.objspace - config.cfgimpl_get_settings().add_property('hidden', obj) + setting[obj].append('hidden') raises(PropertiesOptionError, "config.objspace") - assert config.cfgimpl_get_settings().has_property('hidden', obj) + assert 'hidden' in setting[obj] prop = [] try: objspace.append('std') except PropertiesOptionError, err: prop = err.proptype assert 'hidden' in prop - config.cfgimpl_get_settings().del_property('hidden', obj) - assert not config.cfgimpl_get_settings().has_property('hidden', obj) + setting[obj].remove('hidden') + assert not 'hidden' in setting[obj] config.objspace.append('std') @@ -103,8 +103,8 @@ def test_global_show(): setting = config.cfgimpl_get_settings() setting.read_write() dummy = config.unwrap_from_path('gc.dummy') - config.cfgimpl_get_settings().add_property('hidden', dummy) - assert config.cfgimpl_get_settings().has_property('hidden', dummy) + setting[dummy].append('hidden') + assert 'hidden' in setting[dummy] raises(PropertiesOptionError, "config.gc.dummy == False") @@ -112,11 +112,12 @@ def test_with_many_subgroups(): descr = make_description() config = Config(descr) booltwo = config.unwrap_from_path('gc.subgroup.booltwo') - assert not config.cfgimpl_get_settings().has_property('hidden', booltwo) + setting = config.cfgimpl_get_settings() + assert not 'hidden' in setting[booltwo] assert config.gc.subgroup.booltwo is False - config.cfgimpl_get_settings().add_property('hidden', booltwo) + setting[booltwo].append('hidden') path = 'gc.subgroup.booltwo' homeconfig, name = config.cfgimpl_get_home_by_path(path) assert name == "booltwo" getattr(homeconfig._cfgimpl_descr, name) - assert config.cfgimpl_get_settings().has_property('hidden', booltwo) + assert 'hidden' in setting[booltwo] diff --git a/test/test_option_with_special_name.py b/test/test_option_with_special_name.py index c6a17d0..4e21a40 100644 --- a/test/test_option_with_special_name.py +++ b/test/test_option_with_special_name.py @@ -2,15 +2,17 @@ import autopath from py.test import raises -from tiramisu.config import * -from tiramisu.option import * +from tiramisu.config import Config +from tiramisu.option import BoolOption, OptionDescription, ChoiceOption,\ + IntOption, FloatOption, StrOption + def make_description(): gcoption = ChoiceOption('name', 'GC name', ['ref', 'framework'], 'ref') gcdummy = BoolOption('dummy', 'dummy', default=False) gcdummy2 = BoolOption('hide', 'dummy', default=True) objspaceoption = ChoiceOption('objspace', 'Object space', - ['std', 'thunk'], 'std') + ['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) @@ -22,16 +24,11 @@ def make_description(): gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, floatoption, gcdummy2]) descr = OptionDescription('tiram', '', [gcgroup, booloption, objspaceoption, - wantref_option, stroption, - wantframework_option, - intoption, boolop]) + wantref_option, stroption, + wantframework_option, + intoption, boolop]) return descr -#def test_base_config_and_groups(): -# descr = make_description() -# # overrides the booloption default value -# config = Config(descr, bool=False) -# assert config.gc.hide == True def test_root_config_answers_ok(): "if you hide the root config, the options in this namespace behave normally" @@ -40,16 +37,19 @@ def test_root_config_answers_ok(): descr = OptionDescription('tiramisu', '', [gcdummy, boolop]) cfg = Config(descr) settings = cfg.cfgimpl_get_settings() - settings.enable_property('hiddend') #cfgimpl_hide() - assert cfg.dummy == False - assert cfg.boolop == True + settings.append('hidden') + assert cfg.dummy is False + assert cfg.boolop is True + def test_optname_shall_not_start_with_numbers(): raises(ValueError, "gcdummy = BoolOption('123dummy', 'dummy', default=False)") raises(ValueError, "descr = OptionDescription('123tiramisu', '', [])") -#def test_option_has_an_api_name(): -# gcdummy = BoolOption('cfgimpl_get_settings', 'dummy', default=False) -# boolop = BoolOption('boolop', 'Test boolean option op', default=True) -# descr = OptionDescription('tiramisu', '', [gcdummy, boolop]) -# raises(ValueError, "cfg = Config(descr)") + +def test_option_has_an_api_name(): + print "FIXME" + #gcdummy = BoolOption('cfgimpl_get_settings', 'dummy', default=False) + #boolop = BoolOption('boolop', 'Test boolean option op', default=True) + #descr = OptionDescription('tiramisu', '', [gcdummy, boolop]) + #raises(ValueError, "cfg = Config(descr)") diff --git a/test/test_permissive.py b/test/test_permissive.py new file mode 100644 index 0000000..c2d1f5f --- /dev/null +++ b/test/test_permissive.py @@ -0,0 +1,83 @@ +# coding: utf-8 +import autopath +from tiramisu.option import IntOption, OptionDescription +from tiramisu.config import Config +from tiramisu.error import PropertiesOptionError + + +def make_description(): + u1 = IntOption('u1', '', properties=('frozen', 'mandatory', 'disabled', )) + return OptionDescription('od1', '', [u1]) + + +def test_permissive(): + descr = make_description() + config = Config(descr) + setting = config.cfgimpl_get_settings() + setting.read_write() + props = [] + try: + config.u1 + except PropertiesOptionError, err: + props = err.proptype + assert props == ['disabled'] + setting.set_permissive(('disabled',)) + props = [] + try: + config.u1 + except PropertiesOptionError, err: + props = err.proptype + assert props == ['disabled'] + setting.append('permissive') + config.u1 + setting.remove('permissive') + props = [] + try: + config.u1 + except PropertiesOptionError, err: + props = err.proptype + assert props == ['disabled'] + + +def test_permissive_mandatory(): + descr = make_description() + config = Config(descr) + setting = config.cfgimpl_get_settings() + setting.read_only() + props = [] + try: + config.u1 + except PropertiesOptionError, err: + props = err.proptype + assert props == ['disabled', 'mandatory'] + setting.set_permissive(('mandatory', 'disabled',)) + setting.append('permissive') + config.u1 + setting.remove('permissive') + try: + config.u1 + except PropertiesOptionError, err: + props = err.proptype + assert props == ['disabled', 'mandatory'] + + +def test_permissive_frozen(): + descr = make_description() + config = Config(descr) + setting = config.cfgimpl_get_settings() + setting.read_write() + setting.set_permissive(('frozen', 'disabled',)) + try: + config.u1 = 1 + except PropertiesOptionError, err: + props = err.proptype + assert props == ['disabled', 'frozen'] + setting.append('permissive') + config.u1 = 1 + assert config.u1 == 1 + setting.remove('permissive') + try: + config.u1 = 1 + except PropertiesOptionError, err: + props = err.proptype + assert props == ['disabled', 'frozen'] diff --git a/tiramisu/setting.py b/tiramisu/setting.py index 97098b4..c3372ce 100644 --- a/tiramisu/setting.py +++ b/tiramisu/setting.py @@ -139,29 +139,58 @@ def populate_multitypes(): populate_multitypes() +class Property(object): + __slots__ = ('_setting', '_properties', '_opt') + + def __init__(self, setting, prop, opt=None): + self._opt = opt + self._setting = setting + self._properties = prop + + def append(self, propname): + if not propname in self._properties: + self._properties.append(propname) + self._setting._set_properties(self._properties, self._opt) + self._setting.context.cfgimpl_reset_cache() + + def remove(self, propname): + if propname in self._properties: + self._properties.remove(propname) + self._setting._set_properties(self._properties, self._opt) + self._setting.context.cfgimpl_reset_cache() + + def __contains__(self, propname): + return propname in self._properties + + #____________________________________________________________ class Setting(object): "``Config()``'s configuration options" - __slots__ = ('properties', 'permissives', 'owner', 'context', '_cache') + __slots__ = ('context', '_properties', '_permissives', '_owner', '_cache') def __init__(self, context): # properties attribute: the name of a property enables this property # key is None for global properties - self.properties = {None: ['expire']} + self._properties = {None: ['expire']} # permissive properties - self.permissives = {} + self._permissives = {} # generic owner - self.owner = owners.user + self._owner = owners.user self.context = context self._cache = {} #____________________________________________________________ # properties methods - def has_properties(self, opt=None): - "has properties means the Config's properties attribute is not empty" - return bool(len(self.get_properties(opt))) + def __contains__(self, propname): + return propname in self._get_properties() - def get_properties(self, opt=None, is_apply_req=True): + def __getitem__(self, opt): + return Property(self, self._get_properties(opt), opt) + + def __setitem__(self, opt, value): + raise ValueError('you must only append/remove properties') + + def _get_properties(self, opt=None, is_apply_req=True): if opt is not None and opt in self._cache: exp = time() props, created = self._cache[opt] @@ -173,84 +202,65 @@ class Setting(object): if is_apply_req: apply_requires(opt, self.context) default = list(opt._properties) - props = self.properties.get(opt, default) + props = self._properties.get(opt, default) if opt is not None: self._set_cache(opt, props) return props - def has_property(self, propname, opt=None): - """has property propname in the Config's properties attribute - :param property: string wich is the name of the property""" - return propname in self.get_properties(opt) - - def enable_property(self, propname): + def append(self, propname): "puts property propname in the Config's properties attribute" - props = self.get_properties() - if propname not in props: - props.append(propname) - self.set_properties(props) - self.context.cfgimpl_reset_cache() + Property(self, self._get_properties()).append(propname) - def disable_property(self, propname): + def remove(self, propname): "deletes property propname in the Config's properties attribute" - props = self.get_properties() - if propname in props: - props.remove(propname) - self.set_properties(props) - self.context.cfgimpl_reset_cache() + Property(self, self._get_properties()).remove(propname) - def set_properties(self, properties, opt=None): + def _set_properties(self, properties, opt=None): """save properties for specified opt (never save properties if same has option properties) """ if opt is None: - self.properties[opt] = properties + self._properties[opt] = properties else: if opt._properties == properties: - if opt in self.properties: - del(self.properties[opt]) + if opt in self._properties: + del(self._properties[opt]) else: - self.properties[opt] = properties + self._properties[opt] = properties - def add_property(self, propname, opt, is_apply_req=True): - if opt is None: - raise ValueError("option must not be None in add_property") - properties = self.get_properties(opt, is_apply_req) - if not propname in properties: - properties.append(propname) - self.set_properties(properties, opt) - self.context.cfgimpl_reset_cache() + def _validate_frozen(self, opt, value, is_write): + if not is_write: + return False + if 'permissive' in self and 'frozen' in self._get_permissive(): + return False + if 'everything_frozen' in self or ( + 'frozen' in self and 'frozen' in self[opt]): + return True + return False - def del_property(self, propname, opt, is_apply_req=True): - if opt is None: - raise ValueError("option must not be None in del_property") - properties = self.get_properties(opt, is_apply_req) - if propname in properties: - properties.remove(propname) - self.set_properties(properties, opt) - self.context.cfgimpl_reset_cache() - - def _validate_mandatory(self, opt, value, force_properties=None): - set_mandatory = self.has_property('mandatory') + def _validate_mandatory(self, opt, value, force_properties): + if 'permissive' in self and 'mandatory' in self._get_permissive(): + return False + check_mandatory = 'mandatory' in self if force_properties is not None: - set_mandatory = ('mandatory' in force_properties or - set_mandatory) - if set_mandatory and self.has_property('mandatory', opt) and \ + check_mandatory = ('mandatory' in force_properties or + check_mandatory) + if check_mandatory and 'mandatory' in self[opt] and \ self.context.cfgimpl_get_values()._is_empty(opt, value): return True return False def _calc_properties(self, opt_or_descr, force_permissive, force_properties): - properties = set(self.get_properties(opt_or_descr)) + properties = set(self._get_properties(opt_or_descr)) #remove this properties, those properties are validate in after properties = properties - set(['mandatory', 'frozen']) - set_properties = set(self.get_properties()) + set_properties = set(self._get_properties()) if force_properties is not None: set_properties.update(set(force_properties)) properties = properties & set_properties - if force_permissive is True or self.has_property('permissive'): - properties = properties - set(self.get_permissive()) - properties = properties - set(self.get_permissive(opt_or_descr)) + if force_permissive is True or 'permissive' in self: + properties = properties - set(self._get_permissive()) + properties = properties - set(self._get_permissive(opt_or_descr)) return list(properties) #____________________________________________________________ @@ -263,13 +273,9 @@ class Setting(object): " to an option named: {0} with properties" " {1}") if not is_descr: - if self._validate_mandatory(opt_or_descr, value, - force_properties=force_properties): + if self._validate_mandatory(opt_or_descr, value, force_properties): properties.append('mandatory') - #frozen - if is_write and (self.has_property('everything_frozen') or ( - self.has_property('frozen') and - self.has_property('frozen', opt_or_descr))): + if self._validate_frozen(opt_or_descr, value, is_write): properties.append('frozen') raise_text = _('cannot change the value to {0} for ' 'option {1} this option is frozen') @@ -278,47 +284,47 @@ class Setting(object): str(properties)), properties) - def get_permissive(self, opt=None): - return self.permissives.get(opt, []) + def _get_permissive(self, opt=None): + return self._permissives.get(opt, []) def set_permissive(self, permissive, opt=None): - if not isinstance(permissive, list): - raise TypeError(_('permissive must be a list')) - self.permissives[opt] = permissive + if not isinstance(permissive, tuple): + raise TypeError(_('permissive must be a tuple')) + self._permissives[opt] = permissive #____________________________________________________________ def setowner(self, owner): ":param owner: sets the default value for owner at the Config level" if not isinstance(owner, owners.Owner): raise TypeError(_("invalid generic owner {0}").format(str(owner))) - self.owner = owner + self._owner = owner def getowner(self): - return self.owner + return self._owner #____________________________________________________________ def read_only(self): "convenience method to freeze, hidde and disable" - self.enable_property('everything_frozen') - self.enable_property('frozen') # can be usefull... - self.disable_property('hidden') - self.enable_property('disabled') - self.enable_property('mandatory') - self.enable_property('validator') - self.disable_property('permissive') + self.append('everything_frozen') + self.append('frozen') # can be usefull... + self.remove('hidden') + self.append('disabled') + self.append('mandatory') + self.append('validator') + self.remove('permissive') def read_write(self): "convenience method to freeze, hidde and disable" - self.disable_property('everything_frozen') - self.enable_property('frozen') # can be usefull... - self.enable_property('hidden') - self.enable_property('disabled') - self.disable_property('mandatory') - self.enable_property('validator') - self.disable_property('permissive') + self.remove('everything_frozen') + self.append('frozen') # can be usefull... + self.append('hidden') + self.append('disabled') + self.remove('mandatory') + self.append('validator') + self.remove('permissive') def _set_cache(self, opt, props): - if self.has_property('expire'): + if 'expire' in self: self._cache[opt] = (props, time() + expires_time) pass @@ -346,7 +352,8 @@ def apply_requires(opt, config): #for symlink if hasattr(opt, '_requires') and opt._requires is not None: # filters the callbacks - setting = config.cfgimpl_get_settings() + settings = config.cfgimpl_get_settings() + setting = Property(settings, settings._get_properties(opt, False), opt) trigger_actions = build_actions(opt._requires) optpath = config.cfgimpl_get_context().cfgimpl_get_description().get_path_by_opt(opt) for requires in trigger_actions.values(): @@ -365,22 +372,20 @@ def apply_requires(opt, config): value = config.cfgimpl_get_context()._getattr(path, force_permissive=True) except PropertiesOptionError, err: properties = err.proptype - #FIXME: AttributeError or PropertiesOptionError ? - raise AttributeError(_("option '{0}' has requirement's property error: " - "{1} {2}").format(opt._name, path, properties)) + raise PropertiesOptionError(_("option '{0}' has requirement's property error: " + "{1} {2}").format(opt._name, path, properties)) except AttributeError: raise AttributeError(_("required option not found: " "{0}").format(path)) if value == expected: if inverse: - setting.del_property(action, opt, False) + setting.remove(action) else: - setting.add_property(action, opt, False) + setting.append(action) matches = True - #FIXME optimisation : fait un double break non ? voire un return # no requirement has been triggered, then just reverse the action if not matches: if inverse: - setting.add_property(action, opt, False) + setting.append(action) else: - setting.del_property(action, opt, False) + setting.remove(action) diff --git a/tiramisu/value.py b/tiramisu/value.py index bfa79ac..3bf42e6 100644 --- a/tiramisu/value.py +++ b/tiramisu/value.py @@ -96,14 +96,14 @@ class Values(object): # options with callbacks setting = self.context.cfgimpl_get_settings() value = self._get_value(opt) - is_frozen = setting.has_property('frozen', opt) + is_frozen = 'frozen' in setting[opt] if opt.has_callback(): #if value is set and : # - not frozen # - frozen and not force_default_on_freeze if not self.is_default_owner(opt) and ( not is_frozen or (is_frozen and - not setting.has_property('force_default_on_freeze', opt))): + not 'force_default_on_freeze' in setting[opt])): pass else: value = self._getcallback_value(opt) @@ -112,15 +112,15 @@ class Values(object): #suppress value if already set self._reset(opt) # frozen and force default - elif is_frozen and setting.has_property('force_default_on_freeze', opt): + elif is_frozen and 'force_default_on_freeze' in setting[opt]: value = opt.getdefault() if opt.is_multi(): value = Multi(value, self.context, opt) - if validate and not opt.validate(value, self.context, setting.has_property('validator')): + if validate and not opt.validate(value, self.context, 'validator' in setting): raise ValueError(_('invalid calculated value returned' ' for option {0}: {1}').format(opt._name, value)) if self.is_default_owner(opt) and \ - setting.has_property('force_store_value', opt): + 'force_store_value' in setting[opt]: self.setitem(opt, value) setting.validate_properties(opt, False, False, value=value, force_permissive=force_permissive, @@ -136,7 +136,7 @@ class Values(object): def _setitem(self, opt, value, force_permissive=False, force_properties=None): #valid opt if not opt.validate(value, self.context, - self.context.cfgimpl_get_settings().has_property('validator')): + 'validator' in self.context.cfgimpl_get_settings()): raise ValueError(_('invalid value {}' ' for option {}').format(value, opt._name)) if opt.is_multi() and not isinstance(value, Multi): @@ -172,7 +172,7 @@ class Values(object): return self.getowner(opt) == owners.default def _set_cache(self, opt, val): - if self.context.cfgimpl_get_settings().has_property('expire'): + if 'expire' in self.context.cfgimpl_get_settings(): self._cache[opt] = (val, time() + expires_time) def reset_cache(self, only_expired):