permissive in the getattr
authorgwen <gremond@cadoles.com>
Tue, 16 Oct 2012 13:09:52 +0000 (15:09 +0200)
committergwen <gremond@cadoles.com>
Tue, 16 Oct 2012 13:09:52 +0000 (15:09 +0200)
tiramisu/autolib.py
tiramisu/config.py
tiramisu/error.py
tiramisu/option.py

index 42fcf7f..8f321cf 100644 (file)
@@ -42,12 +42,13 @@ def carry_out_calculation(name, option, config):
         if type(value) == tuple:
             path, check_disabled = value
             try:
-                opt_value = getattr(config, path)
+                #opt_value = getattr(config, path)
+                opt_value = config._getattr(path, permissive=True)
                 opt = config.unwrap_from_path(path)
-            except PropertiesOptionError, e:
+            except PropertiesOptionError, err:
                 if check_disabled:
                     continue
-                raise PropertiesOptionError(e)
+                raise PropertiesOptionError(err, err.proptype)
             is_multi = opt.is_multi()
             if is_multi:
                 if opt_value != None:
index bd0b553..72a0312 100644 (file)
@@ -34,6 +34,7 @@ default_owner = 'user'
 class Config(object):
     "properties attribute: the name of a property enables this property"
     _cfgimpl_properties = ['hidden', 'disabled']
+    _cfgimpl_permissive = []
     "mandatory means: a mandatory option has to have a value that is not None"
     _cfgimpl_mandatory = True
     _cfgimpl_frozen = True
@@ -100,6 +101,11 @@ class Config(object):
                 self._cfgimpl_values[child._name] = Config(child, parent=self)
         self.override(overrides)
 
+    def cfgimpl_set_permissive(self, permissive):
+        if not isinstance(permissive, list):
+            raise TypeError('permissive must be a list')
+        self._cfgimpl_permissive = permissive
+
     def cfgimpl_update(self):
         """dynamically adds `Option()` or `OptionDescription()`
         """
@@ -175,7 +181,7 @@ class Config(object):
             self._validate(name, getattr(self._cfgimpl_descr, name))
         self.setoption(name, value, self._cfgimpl_owner)
 
-    def _validate(self, name, opt_or_descr):
+    def _validate(self, name, opt_or_descr, permissive=False):
         "validation for the setattr and the getattr"
         apply_requires(opt_or_descr, self)
         if not isinstance(opt_or_descr, Option) and \
@@ -185,6 +191,10 @@ class Config(object):
         for proper in properties:
             if not self._cfgimpl_toplevel._cfgimpl_has_property(proper):
                 properties.remove(proper)
+        if permissive:
+            for perm in self._cfgimpl_toplevel._cfgimpl_permissive:
+                if perm in properties:
+                    properties.remove(perm)
         if properties != []:
             raise PropertiesOptionError("trying to access"
                     " to an option named: {0} with properties"
@@ -200,12 +210,15 @@ class Config(object):
         return False
 
     def __getattr__(self, name):
+        return self._getattr(name)
+
+    def _getattr(self, name, permissive=False):
         "attribute notation mechanism for accessing the value of an option"
         # attribute access by passing a path,
         # for instance getattr(self, "creole.general.family.adresse_ip_eth0")
         if '.' in name:
             homeconfig, name = self._cfgimpl_get_home_by_path(name)
-            return getattr(homeconfig, name)
+            return homeconfig._getattr(name, permissive)
         opt_or_descr = getattr(self._cfgimpl_descr, name)
         # symlink options
         if type(opt_or_descr) == SymLinkOption:
@@ -213,7 +226,7 @@ class Config(object):
         if name not in self._cfgimpl_values:
             raise AttributeError("%s object has no attribute %s" %
                                  (self.__class__, name))
-        self._validate(name, opt_or_descr)
+        self._validate(name, opt_or_descr, permissive)
         # special attributes
         if name.startswith('_cfgimpl_'):
             # if it were in __dict__ it would have been found already
@@ -271,9 +284,8 @@ class Config(object):
                     raise MandatoryError("option: {0} is mandatory "
                                           "and shall have a value".format(name))
             # frozen and force default
-            if opt_or_descr.is_forced_on_freeze():
+            if not opt_or_descr.has_callback() and opt_or_descr.is_forced_on_freeze():
                 return opt_or_descr.getdefault()
-
         return self._cfgimpl_values[name]
 
     def unwrap_from_name(self, name):
index d00d2d7..ba4a289 100644 (file)
@@ -7,7 +7,7 @@ class ConfigError(Exception):
 class ConflictConfigError(ConfigError):
     pass
 class PropertiesOptionError(AttributeError):
-    def __init__(self, msg, proptype=None):
+    def __init__(self, msg, proptype):
         self.proptype = proptype
         super(PropertiesOptionError, self).__init__(msg)
 
index ed1cbfb..abeb991 100644 (file)
@@ -22,7 +22,8 @@
 # ____________________________________________________________
 from tiramisu.basetype import HiddenBaseType, DisabledBaseType
 from tiramisu.error import (ConfigError, ConflictConfigError, NotFoundError,
-    RequiresError, RequirementRecursionError, MandatoryError)
+    RequiresError, RequirementRecursionError, MandatoryError,
+    PropertiesOptionError)
 from tiramisu.autolib import carry_out_calculation
 
 requires_actions = [('hide', 'show'), ('enable', 'disable'), ('freeze', 'unfreeze')]
@@ -195,8 +196,7 @@ class Option(HiddenBaseType, DisabledBaseType):
 
     def getcallback_value(self, config):
         return carry_out_calculation(self._name,
-                option=self,
-                config=config)
+                option=self, config=config)
 
     def getcallback_params(self):
         "if a callback has been defined, returns his arity"
@@ -539,15 +539,18 @@ def apply_requires(opt, config):
                           "imbrication detected for option: '{0}' "
                           "with requirement on: '{1}'".format(path, name))
                 homeconfig, shortname = rootconfig._cfgimpl_get_home_by_path(name)
-                if shortname in homeconfig._cfgimpl_values:
-                    value = homeconfig._cfgimpl_values[shortname]
-                    if value == expected:
-                        getattr(opt, action)() #.hide() or show() or...
-                        # FIXME generic programming opt.property_launch(action, False)
-                        matches = True
-                else: # option doesn't exist ! should not happen...
+                try:
+                    value = homeconfig._getattr(shortname, permissive=True)
+                except PropertiesOptionError, err:
+                    raise NotFoundError("required option has property error: "
+                                                             "{0} {1}".format(name, err.proptype))
+                except Exception, err:
                     raise NotFoundError("required option not found: "
                                                              "{0}".format(name))
+                if value == expected:
+                    getattr(opt, action)() #.hide() or show() or...
+                    # FIXME generic programming opt.property_launch(action, False)
+                    matches = True
             # no callback has been triggered, then just reverse the action
             if not matches:
                 getattr(opt, reverse_actions[action])()