better cache
authorEmmanuel Garette <egarette@cadoles.com>
Sat, 8 Jul 2017 13:59:56 +0000 (15:59 +0200)
committerEmmanuel Garette <egarette@cadoles.com>
Sat, 8 Jul 2017 13:59:56 +0000 (15:59 +0200)
21 files changed:
ChangeLog
test/test_cache.py
test/test_state.py
tiramisu/__init__.py
tiramisu/autolib.py
tiramisu/config.py
tiramisu/error.py
tiramisu/i18n.py
tiramisu/option/baseoption.py
tiramisu/option/masterslave.py
tiramisu/option/option.py
tiramisu/option/optiondescription.py
tiramisu/setting.py
tiramisu/storage/dictionary/__init__.py
tiramisu/storage/dictionary/option.py
tiramisu/storage/dictionary/setting.py
tiramisu/storage/dictionary/storage.py
tiramisu/storage/dictionary/value.py
tiramisu/storage/sqlite3/__init__.py
tiramisu/storage/util.py
tiramisu/value.py

index ade2d3c..ee61e37 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+Sat Jul  8 15:57:13 2017 +0200 Emmanuel Garette <egarette@cadoles.com>
+       * better cache, only remove value/property from cache for value
+       modified and for all value affected by this modification
+
 Sat May 20 16:27:09 2017 +0200 Emmanuel Garette <egarette@cadoles.com>
        * add 'operator' to requirement
 
index b3963b2..c4611ca 100644 (file)
@@ -5,7 +5,7 @@ do_autopath()
 from tiramisu import setting, value
 setting.expires_time = 1
 value.expires_time = 1
-from tiramisu.option import IntOption, StrOption, OptionDescription
+from tiramisu.option import BoolOption, IPOption, IntOption, StrOption, OptionDescription
 from tiramisu.config import Config
 from tiramisu.error import ConfigError
 from tiramisu.setting import groups
@@ -77,31 +77,42 @@ def test_cache_reset():
     settings = c.cfgimpl_get_settings()
     #when change a value
     c.u1
+    c.u2
     assert 'u1' in values._p_.get_cached(c)
     assert 'u1' in settings._p_.get_cached(c)
+    assert 'u2' in values._p_.get_cached(c)
+    assert 'u2' in settings._p_.get_cached(c)
     c.u2 = 1
-    assert 'u1' not in values._p_.get_cached(c)
-    assert 'u1' not in settings._p_.get_cached(c)
+    assert 'u1' in values._p_.get_cached(c)
+    assert 'u1' in settings._p_.get_cached(c)
+    assert 'u2' not in values._p_.get_cached(c)
+    assert 'u2' not in settings._p_.get_cached(c)
     #when remove a value
     c.u1
     assert 'u1' in values._p_.get_cached(c)
     assert 'u1' in settings._p_.get_cached(c)
     del(c.u2)
-    assert 'u1' not in values._p_.get_cached(c)
-    assert 'u1' not in settings._p_.get_cached(c)
+    assert 'u1' in values._p_.get_cached(c)
+    assert 'u1' in settings._p_.get_cached(c)
+    assert 'u2' not in values._p_.get_cached(c)
+    assert 'u2' not in settings._p_.get_cached(c)
     #when add/del property
     c.u1
     assert 'u1' in values._p_.get_cached(c)
     assert 'u1' in settings._p_.get_cached(c)
     c.cfgimpl_get_settings()[od1.u2].append('test')
-    assert 'u1' not in values._p_.get_cached(c)
-    assert 'u1' not in settings._p_.get_cached(c)
+    assert 'u1' in values._p_.get_cached(c)
+    assert 'u1' in settings._p_.get_cached(c)
+    assert 'u2' not in values._p_.get_cached(c)
+    assert 'u2' not in settings._p_.get_cached(c)
     c.u1
     assert 'u1' in values._p_.get_cached(c)
     assert 'u1' in settings._p_.get_cached(c)
     c.cfgimpl_get_settings()[od1.u2].remove('test')
-    assert 'u1' not in values._p_.get_cached(c)
-    assert 'u1' not in settings._p_.get_cached(c)
+    assert 'u1' in values._p_.get_cached(c)
+    assert 'u1' in settings._p_.get_cached(c)
+    assert 'u2' not in values._p_.get_cached(c)
+    assert 'u2' not in settings._p_.get_cached(c)
     #when enable/disabled property
     c.u1
     assert 'u1' in values._p_.get_cached(c)
@@ -122,34 +133,51 @@ def test_cache_reset_multi():
     c = Config(od1)
     values = c.cfgimpl_get_values()
     settings = c.cfgimpl_get_settings()
-    #when change a value
     c.u1
+    c.u3
     assert 'u1' in values._p_.get_cached(c)
     assert 'u1' in settings._p_.get_cached(c)
+    assert 'u3' in values._p_.get_cached(c)
+    assert 'u3' in settings._p_.get_cached(c)
+    #when change a value
     c.u3 = [1]
-    assert 'u1' not in values._p_.get_cached(c)
-    assert 'u1' not in settings._p_.get_cached(c)
+    assert 'u1' in values._p_.get_cached(c)
+    assert 'u1' in settings._p_.get_cached(c)
+    assert 'u3' not in values._p_.get_cached(c)
+    assert 'u3' not in settings._p_.get_cached(c)
     #when append value
     c.u1
+    c.u3
     assert 'u1' in values._p_.get_cached(c)
     assert 'u1' in settings._p_.get_cached(c)
+    assert 'u3' in values._p_.get_cached(c)
+    assert 'u3' in settings._p_.get_cached(c)
     c.u3.append(1)
-    assert 'u1' not in values._p_.get_cached(c)
-    assert 'u1' not in settings._p_.get_cached(c)
+    assert 'u1' in values._p_.get_cached(c)
+    assert 'u1' in settings._p_.get_cached(c)
+    assert 'u3' not in values._p_.get_cached(c)
+    assert 'u3' not in settings._p_.get_cached(c)
     #when pop value
     c.u1
+    c.u3
     assert 'u1' in values._p_.get_cached(c)
     assert 'u1' in settings._p_.get_cached(c)
+    assert 'u3' in values._p_.get_cached(c)
+    assert 'u3' in settings._p_.get_cached(c)
     c.u3.pop(1)
-    assert 'u1' not in values._p_.get_cached(c)
-    assert 'u1' not in settings._p_.get_cached(c)
+    assert 'u1' in values._p_.get_cached(c)
+    assert 'u1' in settings._p_.get_cached(c)
+    assert 'u3' not in values._p_.get_cached(c)
+    assert 'u3' not in settings._p_.get_cached(c)
     #when remove a value
     c.u1
     assert 'u1' in values._p_.get_cached(c)
     assert 'u1' in settings._p_.get_cached(c)
     del(c.u3)
-    assert 'u1' not in values._p_.get_cached(c)
-    assert 'u1' not in settings._p_.get_cached(c)
+    assert 'u1' in values._p_.get_cached(c)
+    assert 'u1' in settings._p_.get_cached(c)
+    assert 'u3' not in values._p_.get_cached(c)
+    assert 'u3' not in settings._p_.get_cached(c)
 
 
 def test_reset_cache():
@@ -348,3 +376,210 @@ def test_cache_master_slave():
     assert set(cache['ip_admin_eth0.ip_admin_eth0'].keys()) == set([None])
     assert set(cache['ip_admin_eth0.netmask_admin_eth0'].keys()) == set([None, 0, 1])
     #DEL, insert, ...
+
+
+def return_value(value=None):
+    return value
+
+
+def test_cache_callback():
+    val1 = StrOption('val1', "", 'val')
+    val2 = StrOption('val2', "", callback=return_value, callback_params={'': ((val1, False),)}, properties=('mandatory',))
+    val3 = StrOption('val3', "", callback=return_value, callback_params={'': ('yes',)})
+    val4 = StrOption('val4', "", callback=return_value, callback_params={'value': ((val1, False),)})
+    val5 = StrOption('val5', "", callback=return_value, callback_params={'value': ('yes',)}, multi=True)
+    maconfig = OptionDescription('rootconfig', '', [val1, val2, val3, val4, val5])
+    cfg = Config(maconfig)
+    cfg.cfgimpl_get_settings().remove('expire')
+    cfg.read_write()
+    cfg.cfgimpl_get_values().force_cache()
+    assert cfg.cfgimpl_get_settings()._p_.get_cached(cfg) == {'val1': {None: (set([]), None)},
+                                                              'val2': {None: (set(['mandatory']), None)},
+                                                              'val3': {None: (set([]), None)},
+                                                              'val4': {None: (set([]), None)},
+                                                              'val5': {None: (set(['empty']), None)}}
+    assert cfg.cfgimpl_get_values()._p_.get_cached(cfg) == {'val1': {None: ('val', None)},
+                                                            'val2': {None: ('val', None)},
+                                                            'val3': {None: ('yes', None)},
+                                                            'val4': {None: ('val', None)},
+                                                            'val5': {None: (['yes'], None)}}
+    cfg.val1 = 'new'
+    assert cfg.cfgimpl_get_settings()._p_.get_cached(cfg) == {'val3': {None: (set([]), None)},
+                                                              'val5': {None: (set(['empty']), None)}}
+    assert cfg.cfgimpl_get_values()._p_.get_cached(cfg) == {'val3': {None: ('yes', None)},
+                                                            'val5': {None: (['yes'], None)}}
+    cfg.cfgimpl_get_values().force_cache()
+    assert cfg.cfgimpl_get_settings()._p_.get_cached(cfg) == {'val1': {None: (set([]), None)},
+                                                              'val2': {None: (set(['mandatory']), None)},
+                                                              'val3': {None: (set([]), None)},
+                                                              'val4': {None: (set([]), None)},
+                                                              'val5': {None: (set(['empty']), None)}}
+    assert cfg.cfgimpl_get_values()._p_.get_cached(cfg) == {'val1': {None: ('new', None)},
+                                                            'val2': {None: ('new', None)},
+                                                            'val3': {None: ('yes', None)},
+                                                            'val4': {None: ('new', None)},
+                                                            'val5': {None: (['yes'], None)}}
+    cfg.val3 = 'new2'
+    assert cfg.cfgimpl_get_settings()._p_.get_cached(cfg) == {'val1': {None: (set([]), None)},
+                                                              'val2': {None: (set(['mandatory']), None)},
+                                                              'val4': {None: (set([]), None)},
+                                                              'val5': {None: (set(['empty']), None)}}
+    assert cfg.cfgimpl_get_values()._p_.get_cached(cfg) == {'val1': {None: ('new', None)},
+                                                            'val2': {None: ('new', None)},
+                                                            'val4': {None: ('new', None)},
+                                                            'val5': {None: (['yes'], None)}}
+    cfg.cfgimpl_get_values().force_cache()
+    assert cfg.cfgimpl_get_settings()._p_.get_cached(cfg) == {'val1': {None: (set([]), None)},
+                                                              'val2': {None: (set(['mandatory']), None)},
+                                                              'val3': {None: (set([]), None)},
+                                                              'val4': {None: (set([]), None)},
+                                                              'val5': {None: (set(['empty']), None)}}
+    assert cfg.cfgimpl_get_values()._p_.get_cached(cfg) == {'val1': {None: ('new', None)},
+                                                            'val2': {None: ('new', None)},
+                                                            'val3': {None: ('new2', None)},
+                                                            'val4': {None: ('new', None)},
+                                                            'val5': {None: (['yes'], None)}}
+    cfg.val4 = 'new3'
+    assert cfg.cfgimpl_get_settings()._p_.get_cached(cfg) == {'val1': {None: (set([]), None)},
+                                                              'val2': {None: (set(['mandatory']), None)},
+                                                              'val3': {None: (set([]), None)},
+                                                              'val5': {None: (set(['empty']), None)}}
+    assert cfg.cfgimpl_get_values()._p_.get_cached(cfg) == {'val1': {None: ('new', None)},
+                                                            'val2': {None: ('new', None)},
+                                                            'val3': {None: ('new2', None)},
+                                                            'val5': {None: (['yes'], None)}}
+    cfg.cfgimpl_get_values().force_cache()
+    assert cfg.cfgimpl_get_settings()._p_.get_cached(cfg) == {'val1': {None: (set([]), None)},
+                                                              'val2': {None: (set(['mandatory']), None)},
+                                                              'val3': {None: (set([]), None)},
+                                                              'val4': {None: (set([]), None)},
+                                                              'val5': {None: (set(['empty']), None)}}
+    assert cfg.cfgimpl_get_values()._p_.get_cached(cfg) == {'val1': {None: ('new', None)},
+                                                            'val2': {None: ('new', None)},
+                                                            'val3': {None: ('new2', None)},
+                                                            'val4': {None: ('new3', None)},
+                                                            'val5': {None: (['yes'], None)}}
+    cfg.val5.append('new4')
+    assert cfg.cfgimpl_get_settings()._p_.get_cached(cfg) == {'val1': {None: (set([]), None)},
+                                                              'val2': {None: (set(['mandatory']), None)},
+                                                              'val3': {None: (set([]), None)},
+                                                              'val4': {None: (set([]), None)}}
+    assert cfg.cfgimpl_get_values()._p_.get_cached(cfg) == {'val1': {None: ('new', None)},
+                                                            'val2': {None: ('new', None)},
+                                                            'val3': {None: ('new2', None)},
+                                                            'val4': {None: ('new3', None)}}
+    cfg.cfgimpl_get_values().force_cache()
+    assert cfg.cfgimpl_get_settings()._p_.get_cached(cfg) == {'val1': {None: (set([]), None)},
+                                                              'val2': {None: (set(['mandatory']), None)},
+                                                              'val3': {None: (set([]), None)},
+                                                              'val4': {None: (set([]), None)},
+                                                              'val5': {None: (set(['empty']), None)}}
+    assert cfg.cfgimpl_get_values()._p_.get_cached(cfg) == {'val1': {None: ('new', None)},
+                                                            'val2': {None: ('new', None)},
+                                                            'val3': {None: ('new2', None)},
+                                                            'val4': {None: ('new3', None)},
+                                                            'val5': {None: (['yes', 'new4'], None)}}
+
+
+def test_cache_master_and_slaves_master():
+    val1 = StrOption('val1', "", multi=True)
+    val2 = StrOption('val2', "", multi=True)
+    interface1 = OptionDescription('val1', '', [val1, val2])
+    interface1.impl_set_group_type(groups.master)
+    maconfig = OptionDescription('rootconfig', '', [interface1])
+    cfg = Config(maconfig)
+    cfg.cfgimpl_get_settings().remove('expire')
+    cfg.read_write()
+    cfg.cfgimpl_get_values().force_cache()
+    assert cfg.cfgimpl_get_settings()._p_.get_cached(cfg) == {'val1': {None: (set([]), None)},
+                                                              'val1.val1': {None: (set(['empty']), None)},
+                                                              'val1.val2': {None: (set([]), None)}}
+    assert cfg.cfgimpl_get_values()._p_.get_cached(cfg) == {'val1.val1': {None: ([], None)}, 'val1.val2': {None: ([], None)}}
+    cfg.val1.val1.append()
+    assert cfg.cfgimpl_get_settings()._p_.get_cached(cfg) == {'val1': {None: (set([]), None)}}
+    assert cfg.cfgimpl_get_values()._p_.get_cached(cfg) == {}
+    cfg.cfgimpl_get_values().force_cache()
+    assert cfg.cfgimpl_get_settings()._p_.get_cached(cfg) == {'val1': {None: (set([]), None)},
+                                                              'val1.val1': {None: (set(['empty']), None)},
+                                                              'val1.val2': {None: (set([]), None), 0: (set([]), None)}}
+    assert cfg.cfgimpl_get_values()._p_.get_cached(cfg) == {'val1.val1': {None: ([None], None)},
+                                                            'val1.val2': {None: ([None], None), 0: (None, None)}}
+    cfg.val1.val1.append()
+    cfg.cfgimpl_get_values().force_cache()
+    cfg.val1.val2[1] = 'oui'
+    assert cfg.cfgimpl_get_settings()._p_.get_cached(cfg) == {'val1': {None: (set([]), None)},
+                                                              'val1.val1': {None: (set(['empty']), None)}}
+    assert cfg.cfgimpl_get_values()._p_.get_cached(cfg) == {'val1.val1': {None: ([None, None], None)}}
+    cfg.cfgimpl_get_values().force_cache()
+    assert cfg.cfgimpl_get_settings()._p_.get_cached(cfg) == {'val1': {None: (set([]), None)},
+                                                              'val1.val1': {None: (set(['empty']), None)},
+                                                              'val1.val2': {None: (set([]), None), 0: (set([]), None), 1: (set([]), None)}}
+    assert cfg.cfgimpl_get_values()._p_.get_cached(cfg) == {'val1.val1': {None: ([None, None], None)},
+                                                            'val1.val2': {None: ([None, 'oui'], None), 0: (None, None), 1: ('oui', None)}}
+
+
+def test_cache_master_callback():
+    val1 = StrOption('val1', "", multi=True)
+    val2 = StrOption('val2', "", multi=True, callback=return_value, callback_params={'value': ((val1, False),)})
+    interface1 = OptionDescription('val1', '', [val1, val2])
+    interface1.impl_set_group_type(groups.master)
+    maconfig = OptionDescription('rootconfig', '', [interface1])
+    cfg = Config(maconfig)
+    cfg.cfgimpl_get_settings().remove('expire')
+    cfg.read_write()
+    cfg.cfgimpl_get_values().force_cache()
+    assert cfg.cfgimpl_get_settings()._p_.get_cached(cfg) == {'val1': {None: (set([]), None)},
+                                                              'val1.val1': {None: (set(['empty']), None)},
+                                                              'val1.val2': {None: (set([]), None)}}
+    assert cfg.cfgimpl_get_values()._p_.get_cached(cfg) == {'val1.val1': {None: ([], None)}, 'val1.val2': {None: ([], None)}}
+    cfg.val1.val1.append()
+    assert cfg.cfgimpl_get_settings()._p_.get_cached(cfg) == {'val1': {None: (set([]), None)}}
+    assert cfg.cfgimpl_get_values()._p_.get_cached(cfg) == {}
+    cfg.cfgimpl_get_values().force_cache()
+    assert cfg.cfgimpl_get_settings()._p_.get_cached(cfg) == {'val1': {None: (set([]), None)},
+                                                              'val1.val1': {None: (set(['empty']), None)},
+                                                              'val1.val2': {None: (set([]), None), 0: (set([]), None)}}
+    assert cfg.cfgimpl_get_values()._p_.get_cached(cfg) == {'val1.val1': {None: ([None], None)},
+                                                            'val1.val2': {None: ([None], None), 0: (None, None)}}
+
+
+def test_cache_requires():
+    a = BoolOption('activate_service', '', True)
+    b = IPOption('ip_address_service', '',
+                 requires=[{'option': a, 'expected': False, 'action': 'disabled'}])
+    od = OptionDescription('service', '', [a, b])
+    c = Config(od)
+    c.cfgimpl_get_settings().remove('expire')
+    c.read_write()
+    assert c.cfgimpl_get_settings()._p_.get_cached(c) == {}
+    assert c.cfgimpl_get_values()._p_.get_cached(c) == {}
+    assert c.ip_address_service == None
+    assert c.cfgimpl_get_settings()._p_.get_cached(c) == {'activate_service': {None: (set([]), None)},
+                                                          'ip_address_service': {None: (set([]), None)}}
+
+    assert c.cfgimpl_get_values()._p_.get_cached(c) == {'ip_address_service': {None: (None, None)}}
+    c.cfgimpl_get_values().force_cache()
+    assert c.cfgimpl_get_settings()._p_.get_cached(c) == {'activate_service': {None: (set([]), None)},
+                                                          'ip_address_service': {None: (set([]), None)}}
+
+    assert c.cfgimpl_get_values()._p_.get_cached(c) == {'ip_address_service': {None: (None, None)},
+                                                        'activate_service': {None: (True, None)}}
+    c.ip_address_service = '1.1.1.1'
+    assert c.cfgimpl_get_settings()._p_.get_cached(c) == {'activate_service': {None: (set([]), None)}}
+
+    assert c.cfgimpl_get_values()._p_.get_cached(c) == {'activate_service': {None: (True, None)}}
+    c.cfgimpl_get_values().force_cache()
+    assert c.cfgimpl_get_settings()._p_.get_cached(c) == {'activate_service': {None: (set([]), None)},
+                                                          'ip_address_service': {None: (set([]), None)}}
+
+    assert c.cfgimpl_get_values()._p_.get_cached(c) == {'ip_address_service': {None: ('1.1.1.1', None)},
+                                                        'activate_service': {None: (True, None)}}
+    c.activate_service = False
+    assert c.cfgimpl_get_settings()._p_.get_cached(c) == {}
+
+    assert c.cfgimpl_get_values()._p_.get_cached(c) == {}
+    c.cfgimpl_get_values().force_cache()
+    assert c.cfgimpl_get_settings()._p_.get_cached(c) == {'activate_service': {None: (set([]), None)},
+                                                          'ip_address_service': {None: (set(['disabled']), None)}}
+
+    assert c.cfgimpl_get_values()._p_.get_cached(c) == {'activate_service': {None: (False, None)}}
index dd56b63..7a78ebc 100644 (file)
@@ -3,7 +3,7 @@ do_autopath()
 
 from tiramisu.option import BoolOption, UnicodeOption, SymLinkOption, \
     IntOption, IPOption, NetmaskOption, StrOption, OptionDescription, \
-    DynOptionDescription
+    DynOptionDescription, MasterSlaves
 from tiramisu.config import Config, GroupConfig, MetaConfig
 from tiramisu.setting import groups, owners
 from tiramisu.storage import delete_session
@@ -118,8 +118,15 @@ def _diff_opt(opt1, opt2):
                 assert val1.impl_getname() == val2.impl_getname()
             except AttributeError:
                 assert val1 == val2
+        elif attr == '_dependencies':
+            assert len(val1) == len(val2)
+            for idx, val in enumerate(val1):
+                if isinstance(val, MasterSlaves):
+                    assert val._p_.master.impl_getname() == val2[idx]._p_.master.impl_getname()
+                else:
+                    assert val.impl_getname() == val2[idx].impl_getname()
         else:
-            assert val1 == val2
+            assert val1 == val2, "error for {}".format(attr)
 
 
 def _diff_opts(opt1, opt2):
index f5f3f32..b92b780 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (C) 2012-2013 Team tiramisu (see AUTHORS for all contributors)
+# Copyright (C) 2012-2017 Team tiramisu (see AUTHORS for all contributors)
 #
 # This program is free software: you can redistribute it and/or modify it
 # under the terms of the GNU Lesser General Public License as published by the
index 1ceb0a7..3c4530b 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (C) 2012-2013 Team tiramisu (see AUTHORS for all contributors)
+# Copyright (C) 2012-2017 Team tiramisu (see AUTHORS for all contributors)
 #
 # This program is free software: you can redistribute it and/or modify it
 # under the terms of the GNU Lesser General Public License as published by the
index 7fd8269..cc61b29 100644 (file)
@@ -1,5 +1,5 @@
 # -*- coding: utf-8 -*-
-# Copyright (C) 2012-2013 Team tiramisu (see AUTHORS for all contributors)
+# Copyright (C) 2012-2017 Team tiramisu (see AUTHORS for all contributors)
 #
 # This program is free software: you can redistribute it and/or modify it
 # under the terms of the GNU Lesser General Public License as published by the
@@ -21,6 +21,7 @@
 "options handler global entry point"
 import weakref
 import sys
+from time import time
 
 
 from .error import PropertiesOptionError, ConfigError, ConflictError
@@ -70,10 +71,78 @@ class SubConfig(object):
         self._impl_context = context
         self._impl_path = subpath
 
-    def cfgimpl_reset_cache(self, only_expired=False, only=('values',
-                                                            'settings')):
-        "remove cache (in context)"
-        self._cfgimpl_get_context().cfgimpl_reset_cache(only_expired, only)  # pragma: optional cover
+    def cfgimpl_reset_cache(self,
+                            only_expired=False,
+                            only=('values', 'settings'),
+                            opt=None,
+                            path=None):
+        """reset all settings in cache
+
+        :param only_expired: if True reset only expired cached values
+        :type only_expired: boolean
+        """
+        context = self._cfgimpl_get_context()
+        if 'values' in only:
+            values = context.cfgimpl_get_values()
+        if 'settings' in only:
+            settings = context.cfgimpl_get_settings()
+        if only_expired:
+            if 'values' in only:
+                values._p_.reset_expired_cache(int(time()))
+            if 'settings' in only:
+                settings._p_.reset_expired_cache(int(time()))
+        elif not None in (opt, path):
+            if opt.__class__.__name__ == 'DynOptionDescription':
+                descr = context.cfgimpl_get_description()
+                spath = path.split('.')
+                subpath = '.'.join(spath[:-1])
+                dynopt = getattr(descr, subpath)._getattr(spath[-1], context=context,
+                                                          dyn=False)
+                for suffix in dynopt._impl_get_suffixes(context):
+                    path = subpath + '.' + spath[-1] + suffix
+                    if 'values' in only:
+                        values._p_.delcache(path)
+                    if 'settings' in only:
+                        settings._p_.delcache(path)
+            elif not isinstance(opt, DynSymLinkOption) and opt._is_subdyn():
+                descr = context.cfgimpl_get_description()
+                spath = path.split('.')
+                try:
+                    subpath = '.'.join(spath[:-2])
+                    dynsubopt = getattr(descr, subpath)
+                    spath1 = spath[-2]
+                    spath2 = spath[-1]
+                    spath3 = None
+                except AttributeError:
+                    subpath = '.'.join(spath[:-3])
+                    dynsubopt = getattr(descr, subpath)
+                    spath1 = spath[-3]
+                    spath2 = spath[-2]
+                    spath3 = spath[-1]
+                dynopt = dynsubopt._getattr(spath1, context=context, dyn=False)
+                for suffix in dynopt._impl_get_suffixes(context):
+                    path = subpath + '.' + spath1 + suffix + '.' + spath2 + suffix
+                    if spath3:
+                        path += '.' + spath3 + suffix
+                    if 'values' in only:
+                        values._p_.delcache(path)
+                    if 'settings' in only:
+                        settings._p_.delcache(path)
+            else:
+                if 'values' in only:
+                    values._p_.delcache(path)
+                if 'settings' in only:
+                    settings._p_.delcache(path)
+            for option in getattr(opt, '_dependencies', []):
+                if 'values' in only:
+                    option.reset_cache(opt, values, 'values')
+                if 'settings' in only:
+                    option.reset_cache(opt, settings, 'settings')
+        else:
+            if 'values' in only:
+                values._p_.reset_all_cache()
+            if 'settings' in only:
+                settings._p_.reset_all_cache()
 
     def cfgimpl_get_home_by_path(self, path, force_permissive=False,
                                  returns_raise=False):
@@ -678,7 +747,7 @@ class Config(_CommonConfig):
 
     def __init__(self, descr, session_id=None, persistent=False,
                  name=undefined, force_values=None, force_settings=None,
-                 _duplicate=False):
+                 _duplicate=False, mandatory_name=False):
         """ Configuration option management master class
 
         :param descr: describes the configuration schema
@@ -700,6 +769,8 @@ class Config(_CommonConfig):
                 name = 'config'
                 if session_id is not None:
                     name += session_id
+            if mandatory_name and name is None:
+                raise ValueError(_("name is mandatory for the config").format(name))
             if name is not None and not valid_name(name):  # pragma: optional cover
                 raise ValueError(_("invalid name: {0} for config").format(name))
             self._impl_settings = Settings(self, settings)
@@ -712,14 +783,6 @@ class Config(_CommonConfig):
             self._impl_build_all_caches()
         self._impl_name = name
 
-    def cfgimpl_reset_cache(self,
-                            only_expired=False,
-                            only=('values', 'settings')):
-        if 'values' in only:
-            self.cfgimpl_get_values().reset_cache(only_expired=only_expired)
-        if 'settings' in only:
-            self.cfgimpl_get_settings().reset_cache(only_expired=only_expired)
-
     def impl_getname(self):
         return self._impl_name
 
@@ -763,19 +826,15 @@ class GroupConfig(_CommonConfig):
     def cfgimpl_get_children(self):
         return self._impl_children
 
-    #def cfgimpl_get_context(self):
-    #    "a meta config is a config which has a setting, that is itself"
-    #    return self
-
     def cfgimpl_reset_cache(self,
                             only_expired=False,
-                            only=('values', 'settings')):
-        if 'values' in only:
-            self.cfgimpl_get_values().reset_cache(only_expired=only_expired)
-        if 'settings' in only:
-            self.cfgimpl_get_settings().reset_cache(only_expired=only_expired)
+                            only=('values', 'settings'),
+                            opt=None,
+                            path=None):
+        if isinstance(self, MetaConfig):
+            super(GroupConfig, self).cfgimpl_reset_cache(only_expired=only_expired, only=only, opt=opt, path=path)
         for child in self._impl_children:
-            child.cfgimpl_reset_cache(only_expired=only_expired, only=only)
+            child.cfgimpl_reset_cache(only_expired=only_expired, only=only, opt=opt, path=path)
 
     def set_value(self, path, value):
         """Setattr not in current GroupConfig, but in each children
@@ -906,3 +965,7 @@ class MetaConfig(GroupConfig):
                         setattr(child, path, child_value)
 
         setattr(self, path, value)
+
+    def new_config(self, session_id=None, name=undefined):
+        return Config(self._impl_descr, _duplicate=True, session_id=session_id, name=name,
+                      mandatory_name=True)
index 987263e..a904bd3 100644 (file)
@@ -1,5 +1,5 @@
 # -*- coding: utf-8 -*-
-# Copyright (C) 2012-2013 Team tiramisu (see AUTHORS for all contributors)
+# Copyright (C) 2012-2017 Team tiramisu (see AUTHORS for all contributors)
 #
 # This program is free software: you can redistribute it and/or modify it
 # under the terms of the GNU Lesser General Public License as published by the
index b9931b8..580767a 100644 (file)
@@ -1,5 +1,5 @@
 # -*- coding: UTF-8 -*-
-# Copyright (C) 2012-2013 Team tiramisu (see AUTHORS for all contributors)
+# Copyright (C) 2012-2017 Team tiramisu (see AUTHORS for all contributors)
 #
 # This program is free software: you can redistribute it and/or modify it
 # under the terms of the GNU Lesser General Public License as published by the
index a2435ef..13c99d5 100644 (file)
@@ -1,5 +1,5 @@
 # -*- coding: utf-8 -*-
-# Copyright (C) 2014 Team tiramisu (see AUTHORS for all contributors)
+# Copyright (C) 2014-2017 Team tiramisu (see AUTHORS for all contributors)
 #
 # This program is free software: you can redistribute it and/or modify it
 # under the terms of the GNU Lesser General Public License as published by the
@@ -25,7 +25,7 @@ import sys
 from inspect import getargspec
 
 from ..i18n import _
-from ..setting import log, undefined, debug
+from ..setting import log, undefined, debug, groups
 from ..autolib import carry_out_calculation
 from ..error import (ConfigError, ValueWarning, PropertiesOptionError,
                      display_list)
@@ -58,7 +58,7 @@ def valid_name(name):
         return False
 
 
-def validate_callback(callback, callback_params, type_):
+def validate_callback(callback, callback_params, type_, callbackoption):
     if not isinstance(callback, FunctionType):
         raise ValueError(_('{0} must be a function').format(type_))
     if callback_params is not None:
@@ -94,6 +94,17 @@ def validate_callback(callback, callback_params, type_):
                                                ' not a {} for second argument'
                                               ).format(type_, type(
                                                   force_permissive)))
+                        if isinstance(option, SymLinkOption):
+                            cur_opt = option._impl_getopt()
+                        else:
+                            cur_opt = option
+                        if cur_opt != callbackoption:
+                            if not getattr(cur_opt, '_dependencies', None):
+                                options = []
+                            else:
+                                options = list(cur_opt._dependencies)
+                            options.append(callbackoption)
+                            cur_opt._dependencies = tuple(options)
 #____________________________________________________________
 #
 
@@ -127,7 +138,7 @@ class Base(StorageBase):
         if not is_multi and unique is True:
             raise ValueError(_('unique must be set only with multi value'))
         if requires is not None:
-            calc_properties, requires = validate_requires_arg(is_multi,
+            calc_properties, requires = validate_requires_arg(self, is_multi,
                                                               requires, name)
         else:
             calc_properties = frozenset()
@@ -143,7 +154,7 @@ class Base(StorageBase):
             if multi:  # and validator_params is None:
                 validator_params = self._build_validator_params(validator, validator_params)
 
-            validate_callback(validator, validator_params, 'validator')
+            validate_callback(validator, validator_params, 'validator', self)
             self._set_validator(validator, validator_params)
             self._set_has_dependency()
         if calc_properties != frozenset([]) and properties is not tuple():
@@ -217,7 +228,7 @@ class Base(StorageBase):
                                 "cannot set another one's").format(self.impl_getname()))
         self._validate_callback(callback, callback_params)
         if callback is not None:
-            validate_callback(callback, callback_params, 'callback')
+            validate_callback(callback, callback_params, 'callback', self)
             self._set_callback(callback, callback_params)
 
     def impl_is_optiondescription(self):
@@ -239,6 +250,36 @@ class BaseOption(Base):
 
     # ____________________________________________________________
     # serialize object
+    def _impl_convert_dependencies(self, descr, load=False):
+        """export of the requires during the serialization process
+
+        :type descr: :class:`tiramisu.option.OptionDescription`
+        :param load: `True` if we are at the init of the option description
+        :type load: bool
+        """
+        if not load and getattr(self, '_dependencies', None) is None:
+            self._state_dependencies = None
+        elif load and self._state_dependencies is None:
+            del(self._state_dependencies)
+        else:
+            if load:
+                self._dependencies = []
+                for dependency in self._state_dependencies:
+                    option = descr.impl_get_opt_by_path(dependency)
+                    if option.impl_is_optiondescription() and \
+                            option.impl_get_group_type() == groups.master:
+                        master_path = dependency + '.' + dependency.split('.')[-1]
+                        option = descr.impl_get_opt_by_path(master_path).impl_get_master_slaves()
+                    self._dependencies.append(option)
+                del(self._state_dependencies)
+            else:
+                self._state_dependencies = []
+                for dependency in self._dependencies:
+                    if isinstance(dependency, MasterSlaves):
+                        self._state_dependencies.append('.'.join(descr.impl_get_path_by_opt(dependency._p_.master).split('.')[:-1]))
+                    else:
+                        self._state_dependencies.append(descr.impl_get_path_by_opt(dependency))
+
     def _impl_convert_requires(self, descr, load=False):
         """export of the requires during the serialization process
 
@@ -417,6 +458,14 @@ class BaseOption(Base):
             name = name.encode('utf8')
         return name
 
+    def reset_cache(self, opt, obj, type_):
+        context = obj._getcontext()
+        path = self.impl_getpath(context)
+        obj._p_.delcache(path)
+        context.cfgimpl_reset_cache(only=(type_,),
+                                    opt=self,
+                                    path=path)
+
 
 class OnlyOption(BaseOption):
     __slots__ = tuple()
@@ -927,7 +976,7 @@ class Option(OnlyOption):
                              "is calculated").format(self.impl_getname()))
 
 
-def validate_requires_arg(multi, requires, name):
+def validate_requires_arg(new_option, multi, requires, name):
     """check malformed requirements
     and tranform dict to internal tuple
 
@@ -936,6 +985,14 @@ def validate_requires_arg(multi, requires, name):
                      know more about
                      the description of the requires dictionary
     """
+    def set_dependency(option):
+        if not getattr(option, '_dependencies', None):
+            options = []
+        else:
+            options = list(option._dependencies)
+        options.append(new_option)
+        option._dependencies = tuple(options)
+
     def get_option(require):
         option = require['option']
         if not isinstance(option, Option):
@@ -945,6 +1002,7 @@ def validate_requires_arg(multi, requires, name):
             raise ValueError(_('malformed requirements '
                                'multi option must not set '
                                'as requires of non multi option {0}').format(name))
+        set_dependency(option)
         return option
 
     def _set_expected(action, inverse, transitive, same_action, option, expected, operator):
@@ -970,6 +1028,7 @@ def validate_requires_arg(multi, requires, name):
                     raise ValueError(_('malformed requirements expected must have '
                                        'option and value for option {0}').format(name))
                 option = exp['option']
+                set_dependency(option)
                 if option is not None:
                     err = option._validate(exp['value'])
                     if err:
index 4f7e61c..5fded26 100644 (file)
@@ -1,6 +1,6 @@
 # -*- coding: utf-8 -*-
 "master slave support"
-# Copyright (C) 2014 Team tiramisu (see AUTHORS for all contributors)
+# Copyright (C) 2014-2017 Team tiramisu (see AUTHORS for all contributors)
 #
 # This program is free software: you can redistribute it and/or modify it
 # under the terms of the GNU Lesser General Public License as published by the
@@ -275,3 +275,8 @@ class MasterSlaves(object):
             raise SlaveError(_("invalid len for the slave: {0}"
                                " which has {1} as master").format(
                                    name, self.getmaster(opt).impl_getname()))
+
+    def reset_cache(self, opt, values, type_):
+        for slave in self.getslaves(opt):
+            slave_path = slave.impl_getpath(values._getcontext())
+            values._p_.delcache(slave_path)
index 90634ae..9997be5 100644 (file)
@@ -1,6 +1,6 @@
 # -*- coding: utf-8 -*-
 "option types and option description"
-# Copyright (C) 2012-2013 Team tiramisu (see AUTHORS for all contributors)
+# Copyright (C) 2012-2017 Team tiramisu (see AUTHORS for all contributors)
 #
 # This program is free software: you can redistribute it and/or modify it
 # under the terms of the GNU Lesser General Public License as published by the
@@ -49,7 +49,7 @@ class ChoiceOption(Option):
         :param values: is a list of values the option can possibly take
         """
         if isinstance(values, FunctionType):
-            validate_callback(values, values_params, 'values')
+            validate_callback(values, values_params, 'values', self)
         else:
             if values_params is not None:
                 raise ValueError(_('values is not a function, so values_params must be None'))
index 991274b..32abf7b 100644 (file)
@@ -1,5 +1,5 @@
 # -*- coding: utf-8 -*-
-# Copyright (C) 2014 Team tiramisu (see AUTHORS for all contributors)
+# Copyright (C) 2014-2017 Team tiramisu (see AUTHORS for all contributors)
 #
 # This program is free software: you can redistribute it and/or modify it
 # under the terms of the GNU Lesser General Public License as published by the
@@ -125,6 +125,13 @@ class OptionDescription(BaseOption, StorageOptionDescription):
                                         cache_option, force_store_values)
                 #cannot set multi option as OptionDescription requires
             else:
+                if option.impl_is_master_slaves('master'):
+                    if not getattr(option, '_dependencies', None):
+                        options = []
+                    else:
+                        options = list(option._dependencies)
+                    options.append(option.impl_get_master_slaves())
+                    option._dependencies = tuple(options)
                 option._set_readonly(True)
                 is_multi = option.impl_is_multi()
                 if not isinstance(option, SymLinkOption) and 'force_store_value' in option.impl_getproperties():
@@ -132,8 +139,8 @@ class OptionDescription(BaseOption, StorageOptionDescription):
                 for func, all_cons_opts, params in option._get_consistencies():
                     option._valid_consistencies(all_cons_opts[1:], init=False)
                     if func not in allowed_const_list and is_multi:
-                        is_slave = option.impl_is_master_slaves()
-                        if not is_slave:
+                        is_masterslaves = option.impl_is_master_slaves()
+                        if not is_masterslaves:
                             raise ValueError(_('malformed consistency option "{0}" '
                                                'must be a master/slaves').format(
                                                    option.impl_getname()))
@@ -178,7 +185,6 @@ class OptionDescription(BaseOption, StorageOptionDescription):
                                                                'must not be a multi for {1}').format(
                                                                    require_opt.impl_getname(), option.impl_getname()))
         if init:
-            session = config._impl_values._p_.getsession()
             if len(cache_option) != len(set(cache_option)):
                 for idx in xrange(1, len(cache_option) + 1):
                     opt = cache_option.pop(0)
@@ -194,7 +200,6 @@ class OptionDescription(BaseOption, StorageOptionDescription):
                     self._cache_consistencies[opt] = tuple(cons)
             self._cache_force_store_values = force_store_values
             self._set_readonly(False)
-            del(session)
 
 
     def impl_build_force_store_values(self, config):
@@ -408,8 +413,7 @@ class SynDynOptionDescription(object):
     def _impl_getchildren(self, dyn=True, context=undefined):
         children = []
         for child in self._opt._impl_getchildren():
-            children.append(self._opt._impl_get_dynchild(child, self._suffix))
-        return children
+            yield(self._opt._impl_get_dynchild(child, self._suffix))
 
     def impl_getchildren(self):
         return self._impl_getchildren()
index ce3d1e5..7a1cc90 100644 (file)
@@ -1,6 +1,6 @@
 # -*- coding: utf-8 -*-
 "sets the options of the configuration objects Config object itself"
-# Copyright (C) 2012-2013 Team tiramisu (see AUTHORS for all contributors)
+# Copyright (C) 2012-2017 Team tiramisu (see AUTHORS for all contributors)
 #
 # This program is free software: you can redistribute it and/or modify it
 # under the terms of the GNU Lesser General Public License as published by the
@@ -269,7 +269,7 @@ class Property(object):
             raise ConfigError(_('cannot add those properties: {0}').format(propname))
         self._properties.add(propname)
         if save:
-            self._setting._setproperties(self._properties, self._path, force=True)
+            self._setting._setproperties(self._properties, self._opt, self._path, force=True)
 
     def remove(self, propname):
         """Removes a property named propname
@@ -279,7 +279,7 @@ class Property(object):
         """
         if propname in self._properties:
             self._properties.remove(propname)
-            self._setting._setproperties(self._properties, self._path)
+            self._setting._setproperties(self._properties, self._opt, self._path)
 
     def extend(self, propnames):
         """Extends properties to the existing properties
@@ -289,7 +289,7 @@ class Property(object):
         """
         for propname in propnames:
             self._append(propname, save=False)
-        self._setting._setproperties(self._properties, self._path)
+        self._setting._setproperties(self._properties, self._opt, self._path)
 
     def reset(self):
         """resets the properties (does not **clear** the properties,
@@ -370,7 +370,7 @@ class Settings(object):
             if opt is not None and _path is None:
                 _path = opt.impl_getpath(self._getcontext())
             self._p_.delproperties(_path)
-        self._getcontext().cfgimpl_reset_cache()
+        self._getcontext().cfgimpl_reset_cache(opt=opt, path=_path)
 
     def _getproperties(self, opt=None, path=None,
                        setting_properties=undefined, read_write=True,
@@ -415,20 +415,20 @@ class Settings(object):
         props = self._p_.getproperties(None, default_properties)
         if propname not in props:
             props.add(propname)
-            self._setproperties(props, None)
+            self._setproperties(props, None, None)
 
     def remove(self, propname):
         "deletes property propname in the Config's properties attribute"
         props = self._p_.getproperties(None, default_properties)
         if propname in props:
             props.remove(propname)
-            self._setproperties(props, None)
+            self._setproperties(props, None, None)
 
     def extend(self, propnames):
         for propname in propnames:
             self.append(propname)
 
-    def _setproperties(self, properties, path, force=False):
+    def _setproperties(self, properties, opt, path, force=False):
         """save properties for specified path
         (never save properties if same has option properties)
         """
@@ -438,7 +438,7 @@ class Settings(object):
                 raise ConfigError(_('cannot add those properties: {0}').format(
                     ' '.join(forbidden_properties)))
         self._p_.setproperties(path, properties)
-        self._getcontext().cfgimpl_reset_cache()
+        self._getcontext().cfgimpl_reset_cache(opt=opt, path=path)
 
     #____________________________________________________________
     def validate_properties(self, opt_or_descr, is_descr, check_frozen, path,
@@ -541,7 +541,7 @@ class Settings(object):
         if not isinstance(permissive, tuple):  # pragma: optional cover
             raise TypeError(_('permissive must be a tuple'))
         self._p_.setpermissive(path, permissive)
-        self._getcontext().cfgimpl_reset_cache()
+        self._getcontext().cfgimpl_reset_cache(opt=opt, path=path)
 
     #____________________________________________________________
     def setowner(self, owner):
@@ -564,7 +564,7 @@ class Settings(object):
             props = props | append
             modified = True
         if modified:
-            self._setproperties(props, None)
+            self._setproperties(props, None, None)
 
     def read_only(self):
         "convenience method to freeze, hide and disable"
@@ -574,17 +574,6 @@ class Settings(object):
         "convenience method to freeze, hide and disable"
         self._read(rw_remove, rw_append)
 
-    def reset_cache(self, only_expired):
-        """reset all settings in cache
-
-        :param only_expired: if True reset only expired cached values
-        :type only_expired: boolean
-        """
-        if only_expired:
-            self._p_.reset_expired_cache(int(time()))
-        else:
-            self._p_.reset_all_cache()
-
     def apply_requires(self, opt, path, setting_properties, index, debug):
         """carries out the jit (just in time) requirements between options
 
index cf7e03d..9ff39ef 100644 (file)
@@ -1,5 +1,5 @@
 # -*- coding: utf-8 -*-
-# Copyright (C) 2013-2014 Team tiramisu (see AUTHORS for all contributors)
+# Copyright (C) 2013-2017 Team tiramisu (see AUTHORS for all contributors)
 #
 # This program is free software: you can redistribute it and/or modify it
 # under the terms of the GNU Lesser General Public License as published by the
index 716eab0..b866330 100644 (file)
@@ -56,6 +56,7 @@ class StorageBase(object):
                  '_choice_values_params',
                  #other
                  '_has_dependency',
+                 '_dependencies',
                  '_state_master_slaves',
                  '_state_val_call',
                  '_state_requires',
@@ -64,8 +65,9 @@ class StorageBase(object):
                  '_state_informations',
                  '_state_extra',
                  '_state_readonly',
+                 '_state_dependencies',
                  '__weakref__'
-                 )
+                )
 
     def __init__(self, name, multi, warnings_only, doc, extra, calc_properties,
                  requires, properties, allow_empty_list, unique, opt=undefined,
@@ -588,10 +590,10 @@ class StorageMasterSlaves(object):
 
     def __init__(self, master, slaves):
         self.master = master
-        self.slaves = slaves
+        self.slaves = tuple(slaves)
 
     def _sm_getmaster(self):
         return self.master
 
     def _sm_getslaves(self):
-        return tuple(self.slaves)
+        return self.slaves
index 2d8ab06..9022bc1 100644 (file)
@@ -1,6 +1,6 @@
 # -*- coding: utf-8 -*-
 "default plugin for setting: set it in a simple dictionary"
-# Copyright (C) 2013 Team tiramisu (see AUTHORS for all contributors)
+# Copyright (C) 2013-2017 Team tiramisu (see AUTHORS for all contributors)
 #
 # This program is free software: you can redistribute it and/or modify it
 # under the terms of the GNU Lesser General Public License as published by the
index c868928..e356b07 100644 (file)
@@ -1,5 +1,5 @@
 # -*- coding: utf-8 -*-
-# Copyright (C) 2013 Team tiramisu (see AUTHORS for all contributors)
+# Copyright (C) 2013-2017 Team tiramisu (see AUTHORS for all contributors)
 #
 # This program is free software: you can redistribute it and/or modify it
 # under the terms of the GNU Lesser General Public License as published by the
index 0a03e99..a37388a 100644 (file)
@@ -1,6 +1,6 @@
 # -*- coding: utf-8 -*-
 "default plugin for value: set it in a simple dictionary"
-# Copyright (C) 2013-2014 Team tiramisu (see AUTHORS for all contributors)
+# Copyright (C) 2013-2017 Team tiramisu (see AUTHORS for all contributors)
 #
 # This program is free software: you can redistribute it and/or modify it
 # under the terms of the GNU Lesser General Public License as published by the
index a9f67d7..3bd8e0c 100644 (file)
@@ -1,5 +1,5 @@
 # -*- coding: utf-8 -*-
-# Copyright (C) 2013 Team tiramisu (see AUTHORS for all contributors)
+# Copyright (C) 2013-2017 Team tiramisu (see AUTHORS for all contributors)
 #
 # This program is free software: you can redistribute it and/or modify it
 # under the terms of the GNU Lesser General Public License as published by the
index 064d0a1..c0c55f5 100644 (file)
@@ -1,6 +1,6 @@
 # -*- coding: utf-8 -*-
 "utils used by storage"
-# Copyright (C) 2013 Team tiramisu (see AUTHORS for all contributors)
+# Copyright (C) 2013-2017 Team tiramisu (see AUTHORS for all contributors)
 #
 # This program is free software: you can redistribute it and/or modify it
 # under the terms of the GNU Lesser General Public License as published by the
@@ -98,6 +98,9 @@ class Cache(object):
             setattr(self, key, value)
 
     def setcache(self, path, val, time, index):
+        """add val in cache for a specified path
+        if slave, add index
+        """
         self._cache.setdefault(path, {})[index] = (val, time)
 
     def getcache(self, path, exp, index):
@@ -106,6 +109,12 @@ class Cache(object):
             return True, value
         return False, None  # pragma: no cover
 
+    def delcache(self, path):
+        """remove cache for a specified path
+        """
+        if path in  self._cache:
+            del self._cache[path]
+
     def hascache(self, path, index):
         """ path is in the cache
 
index afe8ea5..82e4ce9 100644 (file)
@@ -201,7 +201,7 @@ class Values(object):
                 self._setvalue(opt, path, value, force_owner=owners.forced)
             else:
                 self._p_.resetvalue(path, session)
-            context.cfgimpl_reset_cache()
+            context.cfgimpl_reset_cache(opt=opt, path=path)
 
     def _isempty(self, opt, value, force_allow_empty_list=False, index=None):
         "convenience method to know if an option is empty"
@@ -427,7 +427,7 @@ class Values(object):
 
     def _setvalue(self, opt, path, value, force_owner=undefined, index=None):
         context = self._getcontext()
-        context.cfgimpl_reset_cache()
+        context.cfgimpl_reset_cache(opt=opt, path=path)
         if force_owner is undefined:
             owner = context.cfgimpl_get_settings().getowner()
         else:
@@ -599,15 +599,6 @@ class Values(object):
                            index=index, force_permissive=force_permissive)
         return d == owners.default
 
-    def reset_cache(self, only_expired):
-        """
-        clears the cache if necessary
-        """
-        if only_expired:
-            self._p_.reset_expired_cache(int(time()))
-        else:
-            self._p_.reset_all_cache()
-
     # information
     def set_information(self, key, value):
         """updates the information's attribute
@@ -699,8 +690,7 @@ class Values(object):
         if not 'cache' in context.cfgimpl_get_settings():
             raise ConfigError(_('can force cache only if cache '
                                 'is actived in config'))
-        #remove all cached properties and value to update "expired" time
-        context.cfgimpl_reset_cache()
+        #FIXME properties and value should update "expired" time
         for path in context.cfgimpl_get_description().impl_getpaths(
                 include_groups=True):
             err = context.getattr(path, returns_raise=True)