merge from val_prop_plugin branch
[tiramisu.git] / tiramisu / setting.py
index 94c26a5..a341d7a 100644 (file)
@@ -25,6 +25,7 @@ from copy import copy
 from tiramisu.error import RequirementError, PropertiesOptionError
 from tiramisu.i18n import _
 
+
 default_encoding = 'utf-8'
 expires_time = 5
 ro_remove = ('permissive', 'hidden')
@@ -33,6 +34,7 @@ ro_append = ('frozen', 'disabled', 'validator', 'everything_frozen',
 rw_remove = ('permissive', 'everything_frozen', 'mandatory')
 rw_append = ('frozen', 'disabled', 'validator', 'hidden')
 default_properties = ('expire', 'validator')
+default_storage = 'dictionary'
 
 
 class _const:
@@ -159,12 +161,12 @@ class Property(object):
 
     def append(self, propname):
         self._properties.add(propname)
-        self._setting._set_properties(self._properties, self._opt)
+        self._setting._setproperties(self._properties, self._opt)
 
     def remove(self, propname):
         if propname in self._properties:
             self._properties.remove(propname)
-            self._setting._set_properties(self._properties, self._opt)
+            self._setting._setproperties(self._properties, self._opt)
 
     def reset(self):
         self._setting.reset(opt=self._opt)
@@ -177,31 +179,37 @@ class Property(object):
 
 
 #____________________________________________________________
-class Setting(object):
+class Settings(object):
     "``Config()``'s configuration options"
-    __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 = {}
-        # permissive properties
-        self._permissives = {}
+    __slots__ = ('context', '_owner', '_p_')
+
+    def __init__(self, context, config_id, plugin_name):
         # generic owner
         self._owner = owners.user
         self.context = context
-        self._cache = {}
+        import_lib = 'tiramisu.plugins.{0}.setting'.format(plugin_name)
+        self._p_ = __import__(import_lib, globals(), locals(), ['Settings'],
+                              -1).Settings(config_id)
+
+    def _getkey(self, opt):
+        if self._p_.key_is_path:
+            if opt is None:
+                return '_none'
+            else:
+                return self._get_opt_path(opt)
+        else:
+            return opt
 
     #____________________________________________________________
     # properties methods
     def __contains__(self, propname):
-        return propname in self._get_properties()
+        return propname in self._getproperties()
 
     def __repr__(self):
-        return str(list(self._get_properties()))
+        return str(list(self._getproperties()))
 
     def __getitem__(self, opt):
-        return Property(self, self._get_properties(opt), opt)
+        return Property(self, self._getproperties(opt), opt)
 
     def __setitem__(self, opt, value):
         raise ValueError('you must only append/remove properties')
@@ -211,50 +219,49 @@ class Setting(object):
             raise ValueError(_('opt and all_properties must not be set '
                                'together in reset'))
         if all_properties:
-            self._properties = {}
+            self._p_.reset_all_propertives()
         else:
-            try:
-                del(self._properties[opt])
-            except KeyError:
-                pass
+            self._p_.reset_properties(self._getkey(opt))
         self.context.cfgimpl_reset_cache()
 
-    def _get_properties(self, opt=None, is_apply_req=True):
+    def _getproperties(self, opt=None, is_apply_req=True):
         if opt is None:
-            props = self._properties.get(opt, set(default_properties))
+            props = self._p_.getproperties(self._getkey(opt), default_properties)
         else:
-            exp = None
-            if opt in self._cache:
-                exp = time()
-                props, created = self._cache[opt]
-                if exp < created:
+            ntime = None
+            if self._p_.hascache('property', self._getkey(opt)):
+                ntime = time()
+                is_cached, props = self._p_.getcache('property', self._getkey(opt), ntime)
+                if is_cached:
                     return props
             if is_apply_req:
                 self.apply_requires(opt)
-            props = self._properties.get(opt, set(opt._properties))
-            self._set_cache(opt, props, exp)
+            props = self._p_.getproperties(self._getkey(opt), opt._properties)
+            if 'expire' in self:
+                if ntime is None:
+                    ntime = time()
+                self._p_.setcache('property', self._getkey(opt), props, ntime + expires_time)
         return props
 
     def append(self, propname):
         "puts property propname in the Config's properties attribute"
-        Property(self, self._get_properties()).append(propname)
+        Property(self, self._getproperties()).append(propname)
 
     def remove(self, propname):
         "deletes property propname in the Config's properties attribute"
-        Property(self, self._get_properties()).remove(propname)
+        Property(self, self._getproperties()).remove(propname)
 
-    def _set_properties(self, properties, opt=None):
+    def _setproperties(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._p_.setproperties(self._getkey(opt), properties)
         else:
             if set(opt._properties) == properties:
-                if opt in self._properties:
-                    del(self._properties[opt])
+                self._p_.reset_properties(self._getkey(opt))
             else:
-                self._properties[opt] = properties
+                self._p_.setproperties(self._getkey(opt), properties)
         self.context.cfgimpl_reset_cache()
 
     #____________________________________________________________
@@ -262,25 +269,25 @@ class Setting(object):
                             value=None, force_permissive=False,
                             force_properties=None):
         """
-        validation upon the properties related to `opt_or_descr` 
-        
+        validation upon the properties related to `opt_or_descr`
+
         :param opt_or_descr: an option or an option description object
-        :param force_permissive: behaves as if the permissive property was present 
-        :param is_descr: we have to know if we are in an option description, 
-                         just because the mandatory property doesn't exist there 
-                         
+        :param force_permissive: behaves as if the permissive property was present
+        :param is_descr: we have to know if we are in an option description,
+                         just because the mandatory property doesn't exist there
+
         :param is_write: in the validation process, an option is to be modified,
-                         the behavior can be different (typically with the `frozen` 
+                         the behavior can be different (typically with the `frozen`
                          property)
         """
-        # opt properties
-        properties = copy(self._get_properties(opt_or_descr))
-        # remove opt permissive
-        properties -= self._get_permissive(opt_or_descr)
-        # remove global permissive if need
-        self_properties = copy(self._get_properties())
-        if force_permissive is True or 'permissive' in self_properties:
-            properties -= self._get_permissive()
+        #opt properties
+        properties = copy(self._getproperties(opt_or_descr))
+        #remove opt permissive
+        properties -= self._p_.getpermissive(self._getkey(opt_or_descr))
+        #remove global permissive if need
+        self_properties = copy(self._getproperties())
+            if force_permissive is True or 'permissive' in self_properties:
+            properties -= self._p_.getpermissive()
 
         # global properties
         if force_properties is not None:
@@ -293,14 +300,14 @@ class Setting(object):
             properties -= frozenset(('mandatory', 'frozen'))
         else:
             if 'mandatory' in properties and \
-                not self.context.cfgimpl_get_values()._is_empty(opt_or_descr,
-                                                                    value):
+                    not self.context.cfgimpl_get_values()._isempty(
+                        opt_or_descr, value):
                 properties.remove('mandatory')
             if is_write and 'everything_frozen' in self_properties:
                 properties.add('frozen')
             elif 'frozen' in properties and not is_write:
                 properties.remove('frozen')
-        # at this point an option should not remain in properties 
+        # at this point an option should not remain in properties
         if properties != frozenset():
             props = list(properties)
             if 'frozen' in properties:
@@ -315,13 +322,11 @@ class Setting(object):
                                               "").format(opt_or_descr._name,
                                               str(props)), props)
 
-    def _get_permissive(self, opt=None):
-        return self._permissives.get(opt, frozenset())
-
+    #FIXME should be setpermissive
     def set_permissive(self, permissive, opt=None):
         if not isinstance(permissive, tuple):
             raise TypeError(_('permissive must be a tuple'))
-        self._permissives[opt] = frozenset(permissive)
+        self._p_.setpermissive(self._getkey(opt), permissive)
 
     #____________________________________________________________
     def setowner(self, owner):
@@ -348,22 +353,11 @@ class Setting(object):
         "convenience method to freeze, hidde and disable"
         self._read(rw_remove, rw_append)
 
-    def _set_cache(self, opt, props, exp):
-        if 'expire' in self:
-            if exp is None:
-                exp = time()
-            self._cache[opt] = (props, time() + expires_time)
-
     def reset_cache(self, only_expired):
         if only_expired:
-            exp = time()
-            keys = self._cache.keys()
-            for key in keys:
-                props, created = self._cache[key]
-                if exp > created:
-                    del(self._cache[key])
+            self._p_.reset_expired_cache('property', time())
         else:
-            self._cache.clear()
+            self._p_.reset_all_cache('property')
 
     def apply_requires(self, opt):
         "carries out the jit (just in time requirements between options"
@@ -371,7 +365,7 @@ class Setting(object):
             return
 
         # filters the callbacks
-        setting = Property(self, self._get_properties(opt, False), opt)
+        setting = Property(self, self._getproperties(opt, False), opt)
         descr = self.context.cfgimpl_get_description()
         optpath = descr.impl_get_path_by_opt(opt)
         for requires in opt._requires:
@@ -413,3 +407,6 @@ class Setting(object):
             # no requirement has been triggered, then just reverse the action
             if not matches:
                 setting.remove(action)
+
+    def _get_opt_path(self, opt):
+        return self.context.cfgimpl_get_description().impl_get_path_by_opt(opt)