add masters/slaves in the Values()
authorgwen <gremond@cadoles.com>
Fri, 22 Feb 2013 10:09:17 +0000 (11:09 +0100)
committergwen <gremond@cadoles.com>
Fri, 22 Feb 2013 10:09:17 +0000 (11:09 +0100)
tiramisu/config.py
tiramisu/error.py
tiramisu/value.py

index c31ada8..961d5dc 100644 (file)
@@ -27,7 +27,8 @@ from tiramisu.error import (PropertiesOptionError, ConfigError, NotFoundError,
 from tiramisu.option import (OptionDescription, Option, SymLinkOption,
     apply_requires)
 from tiramisu.setting import groups, owners, Setting
-from tiramisu.value import OptionValues
+from tiramisu.value import Values
+
 
 # ____________________________________________________________
 class Config(object):
@@ -53,9 +54,9 @@ class Config(object):
             self._cfgimpl_context = self
         else:
             self._cfgimpl_context = context
-        if parent == None:
+        if parent is None:
             self._cfgimpl_settings = Setting()
-            self._cfgimpl_values = OptionValues(self._cfgimpl_context)
+            self._cfgimpl_values = Values(self._cfgimpl_context)
         else:
             if context is None:
                 raise ConfigError("cannot find a value for this config")
@@ -95,7 +96,7 @@ class Config(object):
         if self._cfgimpl_descr.group_type == groups.master:
             mastername = self._cfgimpl_descr._name
             masteropt = getattr(self._cfgimpl_descr, mastername)
-            self._cfgimpl_values.master_groups[masteropt] = []
+            self._cfgimpl_values.masters[masteropt] = []
 
         for child in self._cfgimpl_descr._children:
             if isinstance(child, OptionDescription):
@@ -104,11 +105,9 @@ class Config(object):
                                                 context=self._cfgimpl_context)
             if (self._cfgimpl_descr.group_type == groups.master and
                     child != masteropt):
-                self._cfgimpl_values.master_groups[child] = []
-                self._cfgimpl_values.master_groups[masteropt].append(child)
+                self._cfgimpl_values.slaves[child] = masteropt
+                self._cfgimpl_values.masters[masteropt].append(child)
 
-        if self._cfgimpl_descr.group_type == groups.master:
-            print self._cfgimpl_values.master_groups
     # ____________________________________________________________
     # attribute methods
     def __setattr__(self, name, value):
@@ -241,7 +240,7 @@ class Config(object):
                 except MandatoryError:
                     pass
                 except Exception, e:
-                    raise e # HiddenOptionError or DisabledOptionError
+                    raise e  # HiddenOptionError or DisabledOptionError
                 homeconfig.setoption(name, value)
             elif len(candidates) > 1:
                 raise AmbigousOptionError(
@@ -249,7 +248,7 @@ class Config(object):
             else:
                 raise NoMatchingOptionFound(
                     'there is no option that matches %s'
-                    ' or the option is hidden or disabled'% (key, ))
+                    ' or the option is hidden or disabled' % (key, ))
 
     def get(self, name):
         """
@@ -379,7 +378,6 @@ class Config(object):
 
     __repr__ = __str__
 
-
     def getpaths(self, include_groups=False, allpaths=False, mandatory=False):
         """returns a list of all paths in self, recursively, taking care of
         the context of properties (hidden/disabled)
@@ -438,7 +436,7 @@ class Config(object):
                 value = getattr(self, path)
                 if value == byvalue:
                     return True
-            except: # a property restricts the access of the value
+            except:  # a property restricts the access of the value
                 pass
             return False
         def _filter_by_type():
@@ -497,6 +495,7 @@ class Config(object):
         """
         return self._find(bytype, byname, byvalue, byattrs, first=True)
 
+
 def make_dict(config, flatten=False):
     """export the whole config into a `dict`
     :returns: dict of Option's name (or path) and values"""
@@ -511,10 +510,11 @@ def make_dict(config, flatten=False):
             value = getattr(config, path)
             pathsvalues.append((pathname, value))
         except:
-            pass # this just a hidden or disabled option
+            pass  # this just a hidden or disabled option
     options = dict(pathsvalues)
     return options
 
+
 def mandatory_warnings(config):
     """convenience function to trace Options that are mandatory and
     where no value has been set
index 0880e0f..fae89a7 100644 (file)
@@ -25,3 +25,5 @@ class NoValueReturned(Exception):
     pass
 class OptionValueError(Exception):
     pass
+class MultiTypeError(Exception):
+    pass
index d6182f6..07236d5 100644 (file)
@@ -21,9 +21,9 @@
 # the whole pypy projet is under MIT licence
 # ____________________________________________________________
 from tiramisu.error import NoValueReturned, MandatoryError
-from tiramisu.setting import owners
+from tiramisu.setting import owners, multitypes
 
-class OptionValues(object):
+class Values(object):
     def __init__(self, context):
         """
         Initializes the values's dict.
@@ -34,17 +34,25 @@ class OptionValues(object):
         "Config's root indeed is in charge of the `Option()`'s values"
         self.values = {}
         self.previous_values = {}
-        self.master_groups = {}
+        self.masters = {}
+        self.slaves = {}
         self.context = context
 
     def _get_value(self, opt):
         "special case for the multis: they never return None"
-        if opt.is_multi():
-            if opt not in self.values:
+        if opt not in self.values:
+            if opt.is_multi():
+                if opt in self.slaves:
+                    # slave
+                    multitype = multitypes.slave
+                elif opt in self.masters:
+                    # master
+                    multitype = multitypes.master
                 # FIXME : default value for a multi, we shall work on groups
-                return Multi(opt.getdefault(), self.context, opt)
-        else:
-            if opt not in self.values:
+                else:
+                    multitype = multitypes.default
+                return Multi(opt.getdefault(), self.context, opt, multitype)
+            else:
                 return opt.getdefault()
         return self.values[opt]
 
@@ -128,6 +136,21 @@ class OptionValues(object):
         return value
 
     def __setitem__(self, opt, value):
+        if opt in self.masters:
+            masterlen = len(value)
+            for slave in masters[opt]:
+                if len(self._get_value(slave)) != masterlen:
+                    raise MultiTypeError("invalid len for the slave: {0}"
+                    "which has {1} as master".format(slave._name,
+                                                     master._name))
+        elif opt in self.slaves:
+            if len(self._get_value(self.slaves[opt])) != len(value):
+                   raise MultiTypeError("invalid len for the slave: {0}"
+                    "which has {1} as master".format(slave._name,
+                                                     master._name))
+        self.setitem(opt, value)
+
+    def setitem(self, opt, value):
         self.set_previous_value(opt)
         self.values[opt] = value
         self.setowner(opt, self.context._cfgimpl_settings.getowner())
@@ -149,7 +172,7 @@ class OptionValues(object):
 class Multi(list):
     """multi options values container
     that support item notation for the values of multi options"""
-    def __init__(self, lst, context, opt, multitype=settings.multitypes.default):
+    def __init__(self, lst, context, opt, multitype):
         """
         :param lst: the Multi wraps a list value
         :param context: the home config that has the settings and the values
@@ -160,40 +183,48 @@ class Multi(list):
         self.values = context._cfgimpl_values
         self.multitype = multitype
         super(Multi, self).__init__(lst)
-
+        if multitype == multitypes.master:
+            self.slaves = context._cfgimpl_values.masters[opt]
+        else:
+            self.slaves = None
     def __setitem__(self, key, value):
-        self._setvalue(value, key, who=self.settings.getowner())
+        self._validate(value)
+        self.values[self.opt] = self
+        super(Multi, self).__setitem__(key, value)
 
-    def append(self, value):
+    def append(self, value, force=False):
         """the list value can be updated (appened)
         only if the option is a master
         """
-        self._setvalue(value, who=self.settings.getowner(self.opt))
-
-    def _setvalue(self, value, key=None, who=None):
-        if value != None:
-            if not self.opt._validate(value):
-                raise ConfigError("invalid value {0} "
+        if not force:
+            if self.multitype == multitypes.slave:
+                raise MultiTypeError("cannot append a value on a multi option {0}"
+                        " wich is a slave".format(self.opt._name))
+            elif self.multitype == multitypes.master:
+                for slave in self.slaves:
+                    self.values[slave].append(None, force=True)
+        self._validate(value)
+        self.values.setitem(self.opt, self)
+        super(Multi, self).append(value)
+
+    def _validate(self, value):
+        if value != None and not self.opt._validate(value):
+            raise ConfigError("invalid value {0} "
                     "for option {1}".format(str(value), self.opt._name))
-        oldvalue = list(self)
-        if key is None:
-            super(Multi, self).append(value)
-        else:
-            super(Multi, self).__setitem__(key, value)
-        if who != None:
-            if not isinstance(who, owners.Owner):
-                raise TypeError("invalid owner {0} for the value {1}".format(
-                                str(who), str(value)))
-            self.values.setowner(self.opt, getattr(owners, who))
-        self.values.previous_values[self.opt] = oldvalue
-
-    def pop(self, key):
+
+    def pop(self, key, force=False):
         """the list value can be updated (poped)
         only if the option is a master
 
         :param key: index of the element to pop
         :return: the requested element
         """
-        self.values.setowner(opt, self.settings.get_owner())
-        self.values.previous_values[self.opt] = list(self)
+        if not force:
+            if self.multitype == multitypes.slave:
+                raise MultiTypeError("cannot append a value on a multi option {0}"
+                        " wich is a slave".format(self.opt._name))
+            elif self.multitype == multitypes.master:
+                for slave in self.slaves:
+                    self.values[slave].pop(key, force=True)
+        self.values.setitem(self.opt, self)
         return super(Multi, self).pop(key)