Manipulate properties is now more convenient:
authorEmmanuel Garette <egarette@cadoles.com>
Sat, 20 Apr 2013 15:30:05 +0000 (17:30 +0200)
committerEmmanuel Garette <egarette@cadoles.com>
Sat, 20 Apr 2013 15:30:05 +0000 (17:30 +0200)
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 [new file with mode: 0644]
test/test_freeze.py
test/test_mandatory.py
test/test_option_consistency.py
test/test_option_default.py
test/test_option_setting.py
test/test_option_type.py
test/test_option_with_special_name.py
test/test_permissive.py [new file with mode: 0644]
tiramisu/setting.py
tiramisu/value.py

diff --git a/test/test_cache.py b/test/test_cache.py
new file mode 100644 (file)
index 0000000..2bc35fe
--- /dev/null
@@ -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
index 81127e4..d1d3217 100644 (file)
@@ -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)
index 52456eb..c2911cf 100644 (file)
@@ -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']
index 88f3626..5a9c3e6 100644 (file)
@@ -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")
 #____________________________________________________________
index dfe4733..833f4f1 100644 (file)
@@ -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
 
index 8bae976..f3b9863 100644 (file)
@@ -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():
index 6ecd73e..d8a5b6b 100644 (file)
@@ -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]
index c6a17d0..4e21a40 100644 (file)
@@ -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 (file)
index 0000000..c2d1f5f
--- /dev/null
@@ -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']
index 97098b4..c3372ce 100644 (file)
@@ -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 __getitem__(self, opt):
+        return Property(self, self._get_properties(opt), opt)
 
-    def get_properties(self, opt=None, is_apply_req=True):
+    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 _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 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 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)
index bfa79ac..3bf42e6 100644 (file)
@@ -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):