list is Multi now which enables us to implement item access
[tiramisu.git] / config.py
index e5498c5..f4fabdd 100644 (file)
--- a/config.py
+++ b/config.py
@@ -17,7 +17,7 @@
 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 #
 # The original `Config` design model is unproudly borrowed from 
-# the rough gus of pypy: pypy: http://codespeak.net/svn/pypy/dist/pypy/config/
+# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
 # the whole pypy projet is under MIT licence
 # ____________________________________________________________
 from error import (HiddenOptionError, ConfigError, NotFoundError, 
@@ -25,16 +25,18 @@ from error import (HiddenOptionError, ConfigError, NotFoundError,
                             SpecialOwnersError, MandatoryError, MethodCallError, 
                                            DisabledOptionError, ModeOptionError)
 from option import (OptionDescription, Option, SymLinkOption, group_types, 
-                                                          apply_requires, modes)
-import autolib
+                    Multi, apply_requires, modes)
 from autolib import special_owners, special_owner_factory
+# ______________________________________________________________________
+# generic owner. 'default' is the general config owner after init time
+default_owner = 'user'
 # ____________________________________________________________
 class Config(object):
     _cfgimpl_hidden = True
     _cfgimpl_disabled = True
     _cfgimpl_mandatory = True
     _cfgimpl_frozen = False
-    _cfgimpl_owner = "user"
+    _cfgimpl_owner = default_owner
     _cfgimpl_toplevel = None
     _cfgimpl_mode = 'normal'
     
@@ -42,7 +44,7 @@ class Config(object):
         self._cfgimpl_descr = descr
         self._cfgimpl_value_owners = {}
         self._cfgimpl_parent = parent
-        # `Config()` indeed supports the configuration `Option()`'s values...
+        # `Config()` indeed takes care of the `Option()`'s values
         self._cfgimpl_values = {}
         self._cfgimpl_previous_values = {}
         # XXX warnings are a great idea, let's make up a better use of it 
@@ -50,7 +52,6 @@ class Config(object):
         self._cfgimpl_toplevel = self._cfgimpl_get_toplevel()
         # `freeze()` allows us to carry out this calculation again if necessary 
         self._cfgimpl_frozen = self._cfgimpl_toplevel._cfgimpl_frozen 
-        #
         self._cfgimpl_build(overrides)
 
     def _validate_duplicates(self, children):
@@ -59,14 +60,22 @@ class Config(object):
             if dup._name not in duplicates:
                 duplicates.append(dup._name)
             else:
-                raise ConflictConfigError('duplicate option name: <%s>' % \
-                                                                      dup._name)
+                raise ConflictConfigError('duplicate option name: 
+                    '{0}'.format(dup._name))
 
     def _cfgimpl_build(self, overrides):
         self._validate_duplicates(self._cfgimpl_descr._children)
         for child in self._cfgimpl_descr._children:
             if isinstance(child, Option):
-                self._cfgimpl_values[child._name] = child.getdefault()
+                if child.is_multi():
+                    childdef = Multi(child.getdefault(), config=self, 
+                                     child=child)
+                    self._cfgimpl_values[child._name] = childdef
+                    self._cfgimpl_previous_values[child._name] = childdef
+                else:
+                    childdef = child.getdefault()
+                    self._cfgimpl_values[child._name] = childdef
+                    self._cfgimpl_previous_values[child._name] = childdef 
                 if child.getcallback() is not None:
                     if child._is_hidden():
                         self._cfgimpl_value_owners[child._name] = 'auto'
@@ -74,7 +83,8 @@ class Config(object):
                         self._cfgimpl_value_owners[child._name] = 'fill'
                 else:
                     if child.is_multi():
-                        self._cfgimpl_value_owners[child._name] = ['default']
+                        self._cfgimpl_value_owners[child._name] = ['default' \
+                            for i in range(len(child.getdefault() ))]
                     else:
                         self._cfgimpl_value_owners[child._name] = 'default'
             elif isinstance(child, OptionDescription):
@@ -91,7 +101,7 @@ class Config(object):
             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
+                    # FIXME and ['default', ...] if is_multi() ?
                     self._cfgimpl_value_owners[child._name] = 'default'
             elif isinstance(child, OptionDescription):
                 if child._name not in self._cfgimpl_values:
@@ -154,10 +164,10 @@ class Config(object):
         if type(getattr(self._cfgimpl_descr, name)) != SymLinkOption:
             self._validate(name, getattr(self._cfgimpl_descr, name))
         self.setoption(name, value, self._cfgimpl_owner)
-            
+        
     def _validate(self, name, opt_or_descr):
+        apply_requires(opt_or_descr, self) 
         if not type(opt_or_descr) == OptionDescription:
-            apply_requires(opt_or_descr, self) 
             # hidden options
             if self._cfgimpl_toplevel._cfgimpl_hidden and \
                 (opt_or_descr._is_hidden() or self._cfgimpl_descr._is_hidden()):
@@ -174,8 +184,6 @@ class Config(object):
                 if opt_or_descr.get_mode() != 'normal':
                     raise ModeOptionError("this option's mode is not normal:"
                                                             " {0}".format(name))
-        if type(opt_or_descr) == OptionDescription:
-            apply_requires(opt_or_descr, self) 
 
     def __getattr__(self, name):
         # attribute access by passing a path, 
@@ -199,7 +207,6 @@ class Config(object):
                                  (self.__class__, name))
         if name in self._cfgimpl_value_owners:
             owner = self._cfgimpl_value_owners[name]
-            # special owners
             if owner in special_owners:
                 value = self._cfgimpl_values[name]
                 if value != None:
@@ -216,16 +223,14 @@ 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:
                     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):
                     raise ConfigError('invalid calculated value returned'
                         ' for option {0}'.format(name))
-                
                 if opt_or_descr.is_multi():
-                    if value == None:
+                    if value == []:
                         _result = [result]
                     else:
                         _result = []
@@ -245,8 +250,19 @@ 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__)
@@ -318,7 +334,14 @@ class Config(object):
             if who == 'auto':
                 if not child._is_hidden():
                     child.hide()
-            self._cfgimpl_value_owners[name] = newowner
+            if (value is None and who != 'default' and not child.is_multi()):
+                child.setowner(self, 'default')
+                self._cfgimpl_values[name] = 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()
+            else:         
+                child.setowner(self, newowner)
         else:
             homeconfig = self._cfgimpl_get_toplevel()
             child.setoption(homeconfig, value, who)
@@ -372,10 +395,13 @@ class Config(object):
             self = self._cfgimpl_parent
         return self
 
-    def cfgimpl_previous_values(self, path):
+    def cfgimpl_previous_value(self, path):
         home, name = self._cfgimpl_get_home_by_path(path)
         return home._cfgimpl_previous_values[name]
-        
+    
+    def get_previous_value(self, name):
+        return self._cfgimpl_previous_values[name]
+             
     def add_warning(self, warning):
         self._cfgimpl_get_toplevel()._cfgimpl_warnings.append(warning)