masters shall have the same names as groups
authorgwen <gremond@cadoles.com>
Wed, 6 Feb 2013 15:21:30 +0000 (16:21 +0100)
committergwen <gremond@cadoles.com>
Wed, 6 Feb 2013 15:21:30 +0000 (16:21 +0100)
test/test_parsing_group.py
tiramisu/config.py
tiramisu/option.py
tiramisu/setting.py

index bfb0df8..c7b442d 100644 (file)
@@ -82,69 +82,21 @@ def test_iter_on_empty_group():
         pass
     assert [] == list(config)
 
-def make_master_group():
-    numero_etab = StrOption('numero_etab', "identifiant de l'établissement")
-    nom_machine = StrOption('nom_machine', "nom de la machine", default="eoleng")
-    nombre_interfaces = IntOption('nombre_interfaces', "nombre d'interfaces à activer",
-                                   default=1)
-    activer_proxy_client = BoolOption('activer_proxy_client', "utiliser un proxy",
-                                      default=False)
-    mode_conteneur_actif = BoolOption('mode_conteneur_actif', "le serveur est en mode conteneur",
-                                      default=False)
-    adresse_serveur_ntp = StrOption('serveur_ntp', "adresse serveur ntp", multi=True)
-    time_zone = ChoiceOption('time_zone', 'fuseau horaire du serveur',
-                                ['Paris', 'Londres'], 'Paris')
-
+def test_allowed_groups():
     ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé")
     netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau")
+    interface1 = OptionDescription('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
+    raises(ConfigError, "interface1.set_group_type('toto')")
 
-    master = OptionDescription('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
-    interface1 = OptionDescription('interface1', '', [master])
-    interface1.set_group_type('toto', master='interface1')
-
-    general = OptionDescription('general', '', [numero_etab, nom_machine,
-                                             nombre_interfaces, activer_proxy_client,
-                                             mode_conteneur_actif, adresse_serveur_ntp,
-                                             time_zone])
-    general.set_group_type(groups.family)
-    creole = OptionDescription('creole', 'first tiramisu configuration', [general, interface1])
-    descr = OptionDescription('baseconfig', 'baseconifgdescr', [creole] )
-    return descr
-
-def test_allowed_groups():
-    raises(ConfigError, "descr = make_master_group()")
-
-def make_master_group2():
-    numero_etab = StrOption('numero_etab', "identifiant de l'établissement")
-    nom_machine = StrOption('nom_machine', "nom de la machine", default="eoleng")
-    nombre_interfaces = IntOption('nombre_interfaces', "nombre d'interfaces à activer",
-                                   default=1)
-    activer_proxy_client = BoolOption('activer_proxy_client', "utiliser un proxy",
-                                      default=False)
-    mode_conteneur_actif = BoolOption('mode_conteneur_actif', "le serveur est en mode conteneur",
-                                      default=False)
-    adresse_serveur_ntp = StrOption('serveur_ntp', "adresse serveur ntp", multi=True)
-    time_zone = ChoiceOption('time_zone', 'fuseau horaire du serveur',
-                                ['Paris', 'Londres'], 'Paris')
-
+def test_master_not_valid_name():
     ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé")
     netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau")
+    invalid_group = OptionDescription('interface1', '', [ip_admin_eth0, netmask_admin_eth0])
+    raises(ConfigError, "invalid_group.set_group_type(groups.master)")
 
-    master = OptionDescription('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
-    interface1 = OptionDescription('interface1', '', [master])
-    interface1.set_group_type(groups.group, master='interface1')
-
-    general = OptionDescription('general', '', [numero_etab, nom_machine,
-                                             nombre_interfaces, activer_proxy_client,
-                                             mode_conteneur_actif, adresse_serveur_ntp,
-                                             time_zone])
-    general.set_group_type(groups.family)
-    creole = OptionDescription('creole', 'first tiramisu configuration', [general, interface1])
-    descr = OptionDescription('baseconfig', 'baseconifgdescr', [creole] )
-    return descr
-
-def test_group_is_master():
-    descr = make_master_group2()
-    conf = Config(descr)
-    interface1 = conf.creole.interface1
-    assert interface1._cfgimpl_descr.get_master_name() == "interface1"
+def test_sub_group_in_master_group():
+    ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé")
+    netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau")
+    subgroup = OptionDescription("subgroup", '', [])
+    invalid_group = OptionDescription('ip_admin_eth0', '', [subgroup, ip_admin_eth0, netmask_admin_eth0])
+    raises(ConfigError, "invalid_group.set_group_type(groups.master)")
index fb112e4..c2ac18e 100644 (file)
@@ -74,10 +74,8 @@ class Config(object):
         for child in self._cfgimpl_descr._children:
             if isinstance(child, Option):
                 if child.is_multi():
-                    #force_append to load values without append value to
-                    #child/master
                     childdef = Multi(copy(child.getdefault()), config=self,
-                                     opt=child, force_append=False)
+                                     opt=child)
                     max_len_child = max(max_len_child, len(childdef))
                     self._cfgimpl_values[child._name] = childdef
                     self._cfgimpl_previous_values[child._name] = list(childdef)
@@ -90,25 +88,6 @@ class Config(object):
                 self._validate_duplicates(child._children)
                 self._cfgimpl_values[child._name] = Config(child, parent=self)
 
-        try:
-            master = self._cfgimpl_descr.get_master_name()
-        except TypeError:
-            pass
-        else:
-            #if master/slave group, add default_multi value if length of value
-            #is inferior of length's group
-            for child in self._cfgimpl_descr._children:
-                if isinstance(child, Option):
-                    value = self._cfgimpl_values[child._name]
-                    if value is None:
-                        len_child = 0
-                        value = Multi([], config=self, opt=child, force_append=False)
-                    else:
-                        len_child = len(value)
-                    if len_child < max_len_child:
-                        for num in range(len_child, max_len_child):
-                            value._append_default()
-
     def cfgimpl_update(self):
         """dynamically adds `Option()` or `OptionDescription()`
         """
@@ -181,53 +160,12 @@ class Config(object):
     def __getattr__(self, name):
         return self._getattr(name)
 
-    def _get_master_len(self, slave_name):
-        try:
-            master_name = self._cfgimpl_descr.get_master_name()
-            if master_name == slave_name:
-                return None
-            master_value = self._cfgimpl_values[master_name]
-            return len(master_value)
-        except TypeError, err:
-            # in this case we just don't care about the len
-            return None
-
-    def _valid_len(self, slave_name, slave_value):
-        master_len = self._get_master_len(slave_name)
-        if master_len == None:
-            return True
-        if master_len != len(slave_value):
-            master_name = self._cfgimpl_descr.get_master_name()
-            master_value = self._cfgimpl_values[master_name]
-            raise ValueError("invalid len of '{0}={1}' for the group of"
-                             " '{2}={3}'".format(slave_name,
-                                                 slave_value,
-                                                 master_name,
-                                                 master_value))
-
     def fill_multi(self, name, result, use_default_multi=False, default_multi=None):
         """fills a multi option with default and calculated values
         """
         value = self._cfgimpl_values[name]
-        master_len = self._get_master_len(name)
         if not isinstance(result, list):
-            if master_len is None:
-                master_len = 1
-            # a list is built with the same len as the master
-            _result = []
-            for i in range(master_len):
-                _result.append(result)
-        elif use_default_multi != False:
-            _result = result
-            if master_len != None:
-                slave_len = len(result)
-                if slave_len > master_len:
-                    raise ValueError("invalid value's len for"
-                            "the option: {1}".format(name))
-                if slave_len != master_len:
-                    delta_len = master_len - len(result)
-                    for i in range(delta_len):
-                        _result.append(default_multi)
+            _result = [result]
         else:
             _result = result
         return Multi(_result, value.config, opt=value.opt)
@@ -268,7 +206,6 @@ class Config(object):
                 if (not opt_or_descr.is_frozen() or \
                         not opt_or_descr.is_forced_on_freeze()) and \
                         not opt_or_descr.is_default_owner(self):
-                    self._valid_len(name, value)
                     return value
                 try:
                     result = opt_or_descr.getcallback_value(
@@ -301,7 +238,6 @@ class Config(object):
                 opt_or_descr.setowner(self, owners.default)
             self._test_mandatory(name, opt_or_descr)
         value = self._cfgimpl_values[name]
-        self._valid_len(name, value)
         return value
 
     def unwrap_from_name(self, name):
@@ -351,7 +287,6 @@ class Config(object):
                     value = self.fill_multi(name, child.getdefault(),
                                         use_default_multi=True,
                                         default_multi=child.getdefault_multi())
-                self._valid_len(name, value)
             if not isinstance(who, owners.Owner):
                 raise TypeError("invalid owner [{0}] for option: {1}".format(
                                 str(who), name))
index 2f1f356..0d397f1 100644 (file)
@@ -42,61 +42,24 @@ for act1, act2 in requires_actions:
 class Multi(list):
     """multi options values container
     that support item notation for the values of multi options"""
-    def __init__(self, lst, config, opt, force_append=True):
+    def __init__(self, lst, config, opt):
         """
         :param lst: the Multi wraps a list value
         :param config: the parent config
         :param opt: the option object that have this Multi value
-        :param force_append: - True to append child value with master's one
-                             - False to force lst value
         """
         self.config = config
         self.opt = opt
-        if force_append and self.opt.is_master(config):
-            # we pass the list at the list type's init
-            # because a normal init cannot return anything
-            super(Multi, self).__init__(lst)
-            # we add the slaves without modifying the master
-            for l in lst:
-                self.append(l, add_master=False)
-        else:
-            if force_append:
-                self.config._valid_len(self.opt._name, lst)
-            super(Multi, self).__init__(lst)
+        super(Multi, self).__init__(lst)
 
     def __setitem__(self, key, value):
         self._setvalue(value, key, who=settings.get_owner())
 
-    def append(self, value, add_master=True):
+    def append(self, value):
         """the list value can be updated (appened)
         only if the option is a master
-        :param add_master: adds slaves without modifiying the master option
-                           if True, adds slaves **and** the master option
         """
-        try:
-            master = self.config._cfgimpl_descr.get_master_name()
-            if master != self.opt._name:
-                raise IndexError("in a group with a master, you mustn't add "
-                        "a value in a slave's Multi value")
-        except TypeError:
-            # Not a master/slaves
-            self._setvalue(value, who=settings.get_owner())
-            return
-
-        multis = []
-        for opt in self.config._cfgimpl_descr._children:
-            if isinstance(opt, OptionDescription):
-                continue
-            multi = self.config._cfgimpl_values[opt._name]
-            if master == multi.opt._name:
-                if add_master:
-                    multi._setvalue(value, who=settings.get_owner())
-            elif len(multi) == 0 or len(multi) < len(self):
-                multi._append_default()
-
-    def _append_default(self):
-        default_value = self.opt.getdefault_multi()
-        self._setvalue(default_value)
+        self._setvalue(value, who=settings.get_owner())
 
     def _setvalue(self, value, key=None, who=None):
         if value != None:
@@ -123,35 +86,7 @@ class Multi(list):
         :return: the requested element
 
         """
-        try:
-            master = self.config._cfgimpl_descr.get_master_name()
-            if master != self.opt._name:
-                raise IndexError("in a group with a master, you mustn't remove "
-                        "a value in a slave's Multi value")
-        except TypeError:
-            return self._pop(key)
-
-        multis = []
-        for name, multi in self.config:
-            multis.append(multi)
-        for multi in multis:
-            if master == multi.opt._name:
-                ret = multi._pop(key)
-            else:
-                change_who = False
-                # the value owner has to be updated because
-                # the default value doesn't have the same length
-                # of the new value
-                if len(multi.opt.getdefault()) >= len(multi):
-                    change_who = True
-                multi._pop(key, change_who=change_who)
-        if ret not in locals():
-            raise ConfigError('Unexpected multi pop error: ret must be defined')
-        return ret
-
-    def _pop(self, key, change_who=True):
-        if change_who:
-            self.opt.setowner(self.config, settings.get_owner())
+        self.opt.setowner(self.config, settings.get_owner())
         self.config._cfgimpl_previous_values[self.opt._name] = list(self)
         return super(Multi, self).pop(key)
 # ____________________________________________________________
@@ -382,13 +317,6 @@ class Option(HiddenBaseType, DisabledBaseType):
 
     def getkey(self, value):
         return value
-
-    def is_master(self, config):
-        try:
-            self.master = config._cfgimpl_descr.get_master_name()
-        except TypeError:
-            return False
-        return self.master is not None and self.master == self._name
     # ____________________________________________________________
     "freeze utility"
     def freeze(self):
@@ -498,9 +426,6 @@ class OptionDescription(HiddenBaseType, DisabledBaseType):
         self._requires = requires
         self._build()
         self.properties = [] # 'hidden', 'disabled'...
-        # if this group is a master group, master is set
-        # to the master option name. it's just a ref to a name
-        self.master = None
 
     def getdoc(self):
         return self.doc
@@ -551,7 +476,7 @@ class OptionDescription(HiddenBaseType, DisabledBaseType):
                 paths.append('.'.join(currpath + [attr]))
         return paths
     # ____________________________________________________________
-    def set_group_type(self, group_type, master=None):
+    def set_group_type(self, group_type):
         """sets a given group object to an OptionDescription
 
         :param group_type: an instance of `GroupType` or `MasterGroupType`
@@ -560,28 +485,21 @@ class OptionDescription(HiddenBaseType, DisabledBaseType):
         if isinstance(group_type, groups.GroupType):
             self.group_type = group_type
             if isinstance(group_type, groups.MasterGroupType):
-                if master is None:
-                    raise ConfigError('this group type ({0}) needs a master '
-                            'for OptionDescription {1}'.format(group_type,
-                                self._name))
-            else:
-                if master is not None:
-                    raise ConfigError("this group type ({0}) doesn't need a "
-                            "master for OptionDescription {1}".format(
-                                group_type, self._name))
-            self.master = master
+                identical_master_child_name = False
+                for child in self._children:
+                    if isinstance(child, OptionDescription):
+                        raise ConfigError("master group {} shall not have "
+                         "a subgroup".format(self._name))
+                    if child._name == self._name:
+                        identical_master_child_name = True
+                if not identical_master_child_name:
+                    raise ConfigError("the master group: {} has not any "
+                     "master child".format(self._name))
         else:
             raise ConfigError('not allowed group_type : {0}'.format(group_type))
 
     def get_group_type(self):
         return self.group_type
-
-    def get_master_name(self):
-        if self.master is None:
-            raise TypeError('get_master_name() shall not be called in case of '
-                'non-master OptionDescription')
-        return self.master
-
     # ____________________________________________________________
     "actions API"
     def hide(self):
index d1dcb6e..76a7d98 100644 (file)
@@ -56,17 +56,10 @@ groups = GroupModule()
 
 def populate_groups():
     "populates the available groups in the appropriate namespaces"
-    _available_group_names = ('default', 'family', 'group')
-    _available_groups_with_a_master = ('group', )
-    _available_default_groups = ('default', )
-    # populates normal or master groups
-    for grp in _available_group_names:
-        if grp in _available_groups_with_a_master:
-            setattr(groups, grp, groups.MasterGroupType(grp))
-        elif grp in _available_default_groups:
-            setattr(groups, grp, groups.DefaultGroupType(grp))
-        else:
-            setattr(groups, grp, groups.GroupType(grp))
+    groups.master = groups.MasterGroupType('master')
+    groups.default = groups.DefaultGroupType('default')
+    groups.family = groups.GroupType('family')
+
 # names are in the module now
 populate_groups()
 # ____________________________________________________________