From a404c4c992792e102523b060ee241e681f1c6d3c Mon Sep 17 00:00:00 2001 From: gwen Date: Wed, 6 Feb 2013 16:21:30 +0100 Subject: [PATCH] masters shall have the same names as groups --- test/test_parsing_group.py | 74 +++++------------------- tiramisu/config.py | 69 +--------------------- tiramisu/option.py | 114 ++++++------------------------------- tiramisu/setting.py | 15 ++--- 4 files changed, 35 insertions(+), 237 deletions(-) diff --git a/test/test_parsing_group.py b/test/test_parsing_group.py index bfb0df8..c7b442d 100644 --- a/test/test_parsing_group.py +++ b/test/test_parsing_group.py @@ -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') - - ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé") - netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau") - - 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') - 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(groups.group, master='interface1') +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)") - 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)") diff --git a/tiramisu/config.py b/tiramisu/config.py index fb112e4..c2ac18e 100644 --- a/tiramisu/config.py +++ b/tiramisu/config.py @@ -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)) diff --git a/tiramisu/option.py b/tiramisu/option.py index 2f1f356..0d397f1 100644 --- a/tiramisu/option.py +++ b/tiramisu/option.py @@ -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): diff --git a/tiramisu/setting.py b/tiramisu/setting.py index d1dcb6e..76a7d98 100644 --- a/tiramisu/setting.py +++ b/tiramisu/setting.py @@ -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() # ____________________________________________________________