diff --git a/tiramisu/basetype.py b/tiramisu/basetype.py index 712fe1b..02d3550 100644 --- a/tiramisu/basetype.py +++ b/tiramisu/basetype.py @@ -32,9 +32,8 @@ class BaseType(object): if not propname in self.properties: self.properties.append(propname) def del_property(self, propname): - if not self.has_property(propname): - raise TypeError("option has no property " + propname) - self.properties.remove(propname) + if self.has_property(propname): + self.properties.remove(propname) class HiddenBaseType(BaseType): def hide(self): diff --git a/tiramisu/config.py b/tiramisu/config.py index e9dcb79..b6b5b46 100644 --- a/tiramisu/config.py +++ b/tiramisu/config.py @@ -169,6 +169,16 @@ class Config(object): rootconfig = self._cfgimpl_get_toplevel() if 'disabled' in rootconfig._cfgimpl_properties: rootconfig._cfgimpl_properties.remove('disabled') + + def cfgimpl_non_mandatory(self): + if self._cfgimpl_parent != None: + raise MethodCallError("this method root_mandatory machin() shall not be" + "used with non-root Confit() object") + rootconfig = self._cfgimpl_get_toplevel() + if 'mandatory' in rootconfig._cfgimpl_properties: + rootconfig._cfgimpl_properties.remove('mandatory') + + # ____________________________________________________________ def __setattr__(self, name, value): if '.' in name: @@ -195,16 +205,25 @@ class Config(object): if self._cfgimpl_toplevel._cfgimpl_has_properties() and \ opt_or_descr.has_properties(): raise PropertiesOptionError("trying to access" - " to an option named: {0}".format(name), + " to an option named: {0} with properties" + " {1}".format(name, opt_or_descr.properties), opt_or_descr.properties) if self._cfgimpl_toplevel._cfgimpl_has_properties() and \ self._cfgimpl_descr.has_properties(): raise PropertiesOptionError("trying to access" " to an option's group named: {0}" - " for option named: {1}".format( - self._cfgimpl_descr._name, name), + " for option named: {1} with properties {2}".format( + self._cfgimpl_descr._name, name, + opt_or_descr.properties), self._cfgimpl_descr.properties) + def _is_empty(self, opt): + if (not opt.is_multi() and self._cfgimpl_values[opt._name] == None) or \ + (opt.is_multi() and (self._cfgimpl_values[opt._name] == [] or \ + None in self._cfgimpl_values[name])): + return True + return False + def __getattr__(self, name): # attribute access by passing a path, # for instance getattr(self, "creole.general.family.adresse_ip_eth0") @@ -265,8 +284,14 @@ class Config(object): homeconfig = self._cfgimpl_get_toplevel() mandatory = homeconfig._cfgimpl_mandatory if opt_or_descr.is_mandatory() and mandatory: - if self._cfgimpl_values[name] == None\ - and opt_or_descr.getdefault() == None: + if name == 'ip_ssh_eth0': + print "c'est bien une mandataire2" + print self._cfgimpl_values[name] + print self._is_empty(opt_or_descr) + print type(opt_or_descr) + print opt_or_descr.is_empty_by_default() + if self._is_empty(opt_or_descr) and \ + opt_or_descr.is_empty_by_default(): raise MandatoryError("option: {0} is mandatory " "and shall have a value".format(name)) # frozen and force default @@ -523,14 +548,15 @@ class Config(object): for path in self._cfgimpl_descr.getpaths(include_groups=include_groups): try: value = getattr(self, path) + except MandatoryError: if mandatory or allpaths: paths.append(path) - except Exception, e: + except PropertiesOptionError: if allpaths: paths.append(path) # hidden or disabled or mandatory option added else: - paths.append(path) + paths.append(path) return paths def make_dict(config, flatten=False): @@ -552,9 +578,11 @@ def make_dict(config, flatten=False): def mandatory_warnings(config): mandatory = config._cfgimpl_get_toplevel()._cfgimpl_mandatory config._cfgimpl_get_toplevel()._cfgimpl_mandatory = True - for path in config.getpaths(mandatory=True): + for path in config._cfgimpl_descr.getpaths(include_groups=True): try: value = getattr(config, path) except MandatoryError: yield path + except PropertiesOptionError: + pass config._cfgimpl_get_toplevel()._cfgimpl_mandatory = mandatory diff --git a/tiramisu/option.py b/tiramisu/option.py index fed7c5d..c9a2533 100644 --- a/tiramisu/option.py +++ b/tiramisu/option.py @@ -120,7 +120,7 @@ class Option(HiddenBaseType, DisabledBaseType): "for option {1}".format(str(default), name)) self.default = default self.properties = [] # 'hidden', 'disabled'... - + def validate(self, value): if self.multi == False: # None allows the reset of the value @@ -141,6 +141,12 @@ class Option(HiddenBaseType, DisabledBaseType): def getdefault(self): return self.default + def is_empty_by_default(self): + if ((not self.is_multi() and self.default == None) or + (self.is_multi() and self.default == []) or None in self.default): + return True + return False + def force_default(self): self._force_default_on_freeze = True @@ -194,9 +200,11 @@ class Option(HiddenBaseType, DisabledBaseType): if self.is_mandatory(): # value shall not be '' for a mandatory option # so '' is considered as being None - if value == '': + if not self.is_multi() and value == '': value = None - if config.is_mandatory() and ((self.is_multi() and value == []) or + if self.is_multi() and '' in value: + value = Multi([{'': None}.get(i, i) for i in value], config, self) + if config.is_mandatory() and ((self.is_multi() and value == []) or \ (not self.is_multi() and value is None)): raise MandatoryError('cannot override value to %s for ' 'option %s' % (value, name)) @@ -531,8 +539,8 @@ def apply_requires(opt, config): if action not in available_actions: raise RequiresError("malformed requirements" " for option: {0}".format(opt._name)) - # FIXME generic programming opt.property_launch(action, False) 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... raise NotFoundError("required option not found: "