multies are working now
authorgwen <gremond@cadoles.com>
Mon, 23 Jul 2012 12:30:06 +0000 (14:30 +0200)
committergwen <gremond@cadoles.com>
Mon, 23 Jul 2012 12:30:06 +0000 (14:30 +0200)
src/config.py
src/option.py

index f4fabdd..851ac77 100644 (file)
@@ -27,6 +27,7 @@ from error import (HiddenOptionError, ConfigError, NotFoundError,
 from option import (OptionDescription, Option, SymLinkOption, group_types, 
                     Multi, apply_requires, modes)
 from autolib import special_owners, special_owner_factory
+from copy import copy
 # ______________________________________________________________________
 # generic owner. 'default' is the general config owner after init time
 default_owner = 'user'
@@ -68,10 +69,10 @@ class Config(object):
         for child in self._cfgimpl_descr._children:
             if isinstance(child, Option):
                 if child.is_multi():
-                    childdef = Multi(child.getdefault(), config=self, 
+                    childdef = Multi(copy(child.getdefault()), config=self, 
                                      child=child)
                     self._cfgimpl_values[child._name] = childdef
-                    self._cfgimpl_previous_values[child._name] = childdef
+                    self._cfgimpl_previous_values[child._name] = list(childdef)
                 else:
                     childdef = child.getdefault()
                     self._cfgimpl_values[child._name] = childdef
@@ -100,9 +101,14 @@ class Config(object):
         for child in self._cfgimpl_descr._children:
             if isinstance(child, Option):
                 if child._name not in self._cfgimpl_values:
-                    self._cfgimpl_values[child._name] = child.getdefault()
-                    # FIXME and ['default', ...] if is_multi() ?
-                    self._cfgimpl_value_owners[child._name] = 'default'
+                    if child.is_multi():
+                        self._cfgimpl_values[child._name] = Multi(
+                                copy(child.getdefault()), config=self, child=child)
+                        self._cfgimpl_value_owners[child._name] = ['default' \
+                                for i in range(len(child.getdefault() ))]
+                    else:
+                        self._cfgimpl_values[child._name] = copy(child.getdefault())
+                        self._cfgimpl_value_owners[child._name] = 'default'
             elif isinstance(child, OptionDescription):
                 if child._name not in self._cfgimpl_values:
                     self._cfgimpl_values[child._name] = Config(child, parent=self)
@@ -223,7 +229,7 @@ class Config(object):
                             config=self._cfgimpl_get_toplevel())
                 # this result **shall not** be a list 
                 # for example, [1, 2, 3, None] -> [1, 2, 3, result]
-                if type(result) == list:
+                if isinstance(result, list):
                     raise ConfigError('invalid calculated value returned'
                         ' for option {0} : shall not be a list'.format(name))
                 if result != None and not opt_or_descr._validate(result):
@@ -231,9 +237,9 @@ class Config(object):
                         ' for option {0}'.format(name))
                 if opt_or_descr.is_multi():
                     if value == []:
-                        _result = [result]
+                        _result = Multi([result], value.config, value.child)
                     else:
-                        _result = []
+                        _result = Multi([], value.config, value.child)
                         for val in value:
                             if val == None:
                                 val = result
@@ -250,19 +256,8 @@ class Config(object):
                   and opt_or_descr.getdefault() == None:
                     raise MandatoryError("option: {0} is mandatory " 
                                           "and shall have a value".format(name))
-        # for multi types with None in the value (ex: ["egg", None, "spam"])
-        # None is replaced by default_multi
-        if not isinstance(opt_or_descr, OptionDescription):
-            if opt_or_descr.is_multi() and None in self._cfgimpl_values[name]:
-                newvalue = []
-                for val in self._cfgimpl_values[name]:
-                    if val is None:
-                        newvalue.append(opt_or_descr.default_multi)
-                    else:
-                        newvalue.append(val)
-                return newvalue
         return self._cfgimpl_values[name]
-        
+                
     def __dir__(self):
         #from_type = dir(type(self))
         from_dict = list(self.__dict__)
@@ -301,6 +296,7 @@ class Config(object):
 
     def setoption(self, name, value, who=None):
         #who is **not necessarily** a owner, because it cannot be a list
+        #FIXME : sortir le setoption pour les multi, ca ne devrait pas être la
         child = getattr(self._cfgimpl_descr, name)
         if who == None:
             if child.is_multi():
@@ -310,8 +306,11 @@ class Config(object):
         else:
             if type(child) != SymLinkOption:
                 if child.is_multi():
-                    if type(value) != list:
-                        raise ConfigError("invalid value for option:"
+                    if type(value) != Multi:
+                        if type(value) == list:
+                            value = Multi(value, self, child)
+                        else:
+                            raise ConfigError("invalid value for option:"
                                        " {0} that is set to multi".format(name))
                     newowner = [who for i in range(len(value))]
                 else:
@@ -336,10 +335,11 @@ class Config(object):
                     child.hide()
             if (value is None and who != 'default' and not child.is_multi()):
                 child.setowner(self, 'default')
-                self._cfgimpl_values[name] = child.getdefault()
+                self._cfgimpl_values[name] = copy(child.getdefault())
             elif (value == [] and who != 'default' and child.is_multi()):
                 child.setowner(self, ['default' for i in range(len(child.getdefault()))])
-                self._cfgimpl_values[name] = child.getdefault()
+                self._cfgimpl_values[name] = Multi(copy(child.getdefault()),
+                            config=self, child=child)
             else:         
                 child.setowner(self, newowner)
         else:
@@ -444,7 +444,7 @@ class Config(object):
         self.cfgimpl_unfreeze()
         rootconfig = self._cfgimpl_get_toplevel()
         rootconfig._cfgimpl_hidden = True
-        rootconfig._cfgimpl_disabled = False
+        rootconfig._cfgimpl_disabled = True
         rootconfig._cfgimpl_mandatory = False
     # ____________________________________________________________
     def getkey(self):
index ce06324..d6de739 100644 (file)
@@ -31,49 +31,53 @@ reverse_actions = {'hide': 'show', 'show': 'hide',
 # OptionDescription authorized group_type values
 group_types = ['default', 'family', 'group', 'master']
 # multi types 
+
 class Multi(list):
     "container that support items for the values of list (multi) options" 
-    def __init__(self, lst, config=None, child=None):
+    def __init__(self, lst, config, child):
         self.config = config
         self.child = child
         super(Multi, self).__init__(lst)
         
-    def __getitem__(self, key):
-        value =  super(Multi, self).__getitem__(key)
-        if value is None:
-            return self.child.default_multi
-        else:
-            return value
-                        
     def __setitem__(self, key, value):
-        if value is None:
-            owner = 'default'
-        else:
-            owner = self.config._cfgimpl_owner 
-        oldowner = self.child.getowner(self.config)
-        oldowner[key] = owner        
-        self.child.setowner(self.config, oldowner)
-        if value != None and not self.child._validate(value):
-            raise ConfigError("invalid value {0} "
-                "for option {1}".format(str(value), self.child._name))
-        return super(Multi, self).__setitem__(key, value)
+        return self.setoption(value, key)
 
     def append(self, value):
-        if value is None:
-            owner = 'default'
+        self.setoption(value)
+   
+    def setoption(self, value, key=None):
+        owners = self.child.getowner(self.config)
+        # None is replaced by default_multi
+        if value == None:
+            defval = self.child.getdefault()
+            if key is not None and len(defval) > key:
+                value = defval[key]
+            else:
+                value = self.child.default_multi
+            who = 'default'
         else:
-            owner = self.config._cfgimpl_owner 
+            who = self.config._cfgimpl_owner
+            if not self.child._validate(value):
+                raise ConfigError("invalid value {0} "
+                    "for option {1}".format(str(value), self.child._name))
+        oldvalue = list(self)
         oldowner = self.child.getowner(self.config)
-        oldowner.append(owner)
+        if key is None:
+            ret = super(Multi, self).append(value)
+            oldvalue.append(None)
+            oldowner.append(who)
+        else:
+            ret = super(Multi, self).__setitem__(key, value)
+            oldowner[key] = who
+        self.config._cfgimpl_previous_values[self.child._name] = oldvalue
         self.child.setowner(self.config, oldowner)
-        # changer dans la config la valeur par défaut et le owner
-        if value != None and not self.child._validate(value):
-            raise ConfigError("invalid value {0} "
-                "for option {1}".format(str(value), self.child._name))
-        super(Multi, self).append(value)
-    
-#    def pop(self):
-#        pass 
+        return ret
+        
+    def pop(self, key):
+        oldowner = self.child.getowner(self.config)
+        oldowner.pop(key)
+        self.child.setowner(self.config, oldowner)
+        super(Multi, self).pop(key)
 # ____________________________________________________________
 #
 class Option(HiddenBaseType, DisabledBaseType, ModeBaseType):
@@ -202,7 +206,10 @@ class Option(HiddenBaseType, DisabledBaseType, ModeBaseType):
 #                            raise ConflictConfigError("an option with requires "
 #                             "has not the same length of the others " 
 #                             "in the group : {0}".format(reqname)) 
-        config._cfgimpl_previous_values[name] = config._cfgimpl_values[name] 
+        if type(config._cfgimpl_values[name]) == Multi:
+            config._cfgimpl_previous_values[name] = list(config._cfgimpl_values[name])
+        else:
+            config._cfgimpl_previous_values[name] = config._cfgimpl_values[name] 
         config._cfgimpl_values[name] = value
 
     def getkey(self, value):
@@ -224,10 +231,14 @@ class Option(HiddenBaseType, DisabledBaseType, ModeBaseType):
 class ChoiceOption(Option):
     opt_type = 'string'
     
-    def __init__(self, name, doc, values, default=None, requires=None,
-                 callback=None, callback_params=None, multi=False, 
-                                                           mandatory=False):
+    def __init__(self, name, doc, values, open_values=False, default=None,
+                 requires=None, callback=None, callback_params=None,
+                 multi=False, mandatory=False):
         self.values = values
+        if open_values not in [True, False]:
+            raise ConfigError('Open_values must be a boolean for '
+                              '{0}'.format(name))
+        self.open_values = open_values
         super(ChoiceOption, self).__init__(name, doc, default=default,
                            callback=callback, callback_params=callback_params, 
                            requires=requires, multi=multi, mandatory=mandatory)
@@ -237,7 +248,10 @@ class ChoiceOption(Option):
         super(ChoiceOption, self).setoption(config, value, who)
 
     def _validate(self, value):
-        return value is None or value in self.values
+        if not self.open_values:
+            return value is None or value in self.values
+        else:
+            return True
 
 class BoolOption(Option):
     opt_type = 'bool'