all multi gestion is now in Multi
authorEmmanuel Garette <egarette@cadoles.com>
Thu, 18 Apr 2013 21:06:14 +0000 (23:06 +0200)
committerEmmanuel Garette <egarette@cadoles.com>
Thu, 18 Apr 2013 21:06:14 +0000 (23:06 +0200)
test/test_parsing_group.py
tiramisu/setting.py
tiramisu/value.py

index 5ddd2f3..ef162b6 100644 (file)
@@ -141,12 +141,17 @@ def test_values_with_master_and_slaves():
     maconfig = OptionDescription('toto', '', [interface1])
     cfg = Config(maconfig)
     opt = cfg.unwrap_from_path("ip_admin_eth0.ip_admin_eth0")
+    opt_slave = cfg.unwrap_from_path("ip_admin_eth0.netmask_admin_eth0")
     owner = cfg._cfgimpl_context._cfgimpl_settings.getowner()
     assert interface1.get_group_type() == groups.master
     assert cfg.cfgimpl_get_values().getowner(opt) == owners.default
+    assert cfg.cfgimpl_get_values().getowner(opt_slave) == owners.default
+    assert cfg.ip_admin_eth0.netmask_admin_eth0 == []
     cfg.ip_admin_eth0.ip_admin_eth0.append("192.168.230.145")
-    assert  cfg.ip_admin_eth0.ip_admin_eth0 == ["192.168.230.145"]
+    assert cfg.ip_admin_eth0.ip_admin_eth0 == ["192.168.230.145"]
+    assert cfg.ip_admin_eth0.netmask_admin_eth0 == [None]
     assert cfg.cfgimpl_get_values().getowner(opt) == owner
+    assert cfg.cfgimpl_get_values().getowner(opt_slave) == owners.default
 
 
 def test_reset_values_with_master_and_slaves():
@@ -157,11 +162,54 @@ def test_reset_values_with_master_and_slaves():
     maconfig = OptionDescription('toto', '', [interface1])
     cfg = Config(maconfig)
     opt = cfg.unwrap_from_path("ip_admin_eth0.ip_admin_eth0")
+    opt_slave = cfg.unwrap_from_path("ip_admin_eth0.netmask_admin_eth0")
     owner = cfg._cfgimpl_context._cfgimpl_settings.getowner()
     assert interface1.get_group_type() == groups.master
     assert cfg.cfgimpl_get_values().getowner(opt) == owners.default
+    assert cfg.cfgimpl_get_values().getowner(opt_slave) == owners.default
     cfg.ip_admin_eth0.ip_admin_eth0.append("192.168.230.145")
     assert cfg.cfgimpl_get_values().getowner(opt) == owner
+    assert cfg.cfgimpl_get_values().getowner(opt_slave) == owners.default
     del(cfg.ip_admin_eth0.ip_admin_eth0)
     assert cfg.cfgimpl_get_values().getowner(opt) == owners.default
-    assert  cfg.ip_admin_eth0.ip_admin_eth0 == []
+    assert cfg.cfgimpl_get_values().getowner(opt_slave) == owners.default
+    assert cfg.ip_admin_eth0.ip_admin_eth0 == []
+    assert cfg.ip_admin_eth0.netmask_admin_eth0 == []
+
+
+def test_values_with_master_and_slaves_slave():
+    ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)
+    netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True)
+    interface1 = OptionDescription('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
+    interface1.set_group_type(groups.master)
+    maconfig = OptionDescription('toto', '', [interface1])
+    cfg = Config(maconfig)
+    assert cfg.ip_admin_eth0.netmask_admin_eth0 == []
+    raises(ValueError, "cfg.ip_admin_eth0.netmask_admin_eth0 = ['255.255.255.0']")
+    cfg.ip_admin_eth0.ip_admin_eth0.append("192.168.230.145")
+    cfg.ip_admin_eth0.netmask_admin_eth0 = ['255.255.255.0']
+    cfg.ip_admin_eth0.netmask_admin_eth0[0] = '255.255.255.0'
+    raises(ValueError, "cfg.ip_admin_eth0.netmask_admin_eth0 = ['255.255.255.0', '255.255.255.0']")
+    raises(ValueError, "cfg.ip_admin_eth0.netmask_admin_eth0 = []")
+    del(cfg.ip_admin_eth0.netmask_admin_eth0)
+    cfg.ip_admin_eth0.netmask_admin_eth0 = ['255.255.255.0']
+    cfg.ip_admin_eth0.ip_admin_eth0.append("192.168.230.145")
+    assert cfg.ip_admin_eth0.netmask_admin_eth0 == ['255.255.255.0', None]
+    cfg.ip_admin_eth0.netmask_admin_eth0 = ['255.255.255.0', '255.255.255.0']
+    raises(ValueError, 'cfg.ip_admin_eth0.netmask_admin_eth0.pop(1)')
+
+
+def test_values_with_master_and_slaves_master():
+    ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)
+    netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True)
+    interface1 = OptionDescription('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
+    interface1.set_group_type(groups.master)
+    maconfig = OptionDescription('toto', '', [interface1])
+    cfg = Config(maconfig)
+    cfg.ip_admin_eth0.ip_admin_eth0.append("192.168.230.145")
+    cfg.ip_admin_eth0.ip_admin_eth0 = ["192.168.230.145"]
+    cfg.ip_admin_eth0.ip_admin_eth0 = ["192.168.230.145", "192.168.230.145"]
+    cfg.ip_admin_eth0.netmask_admin_eth0 = ['255.255.255.0', '255.255.255.0']
+    raises(ValueError, 'cfg.ip_admin_eth0.ip_admin_eth0 = ["192.168.230.145"]')
+    cfg.ip_admin_eth0.ip_admin_eth0.pop(1)
+    assert cfg.ip_admin_eth0.ip_admin_eth0 == ["192.168.230.145"]
index 05071ca..f101a0c 100644 (file)
@@ -218,6 +218,30 @@ class Setting(object):
             self.set_properties(properties, opt)
         self.context.cfgimpl_clean_cache()
 
+    def _validate_mandatory(self, opt, value, force_properties=None):
+        set_mandatory = self.has_property('mandatory')
+        if force_properties is not None:
+            set_mandatory = ('mandatory' in force_properties or
+                             set_mandatory)
+        if set_mandatory and self.has_property('mandatory', opt, False) and \
+                self.context.cfgimpl_get_values()._is_empty(opt, value):
+            return True
+        return False
+
+    def _calc_properties(self, opt_or_descr, force_permissive, force_properties):
+        properties = set(self.get_properties(opt_or_descr))
+        #remove this properties, those properties are validate in after
+        properties = properties - set(['mandatory', 'frozen'])
+        set_properties = self.get_properties()
+        if force_properties is not None:
+            set_properties.extend(force_properties)
+        set_properties = set(set_properties)
+        properties = properties & set_properties
+        if force_permissive is True or self.has_property('permissive', is_apply_req=False):
+            properties = properties - set(self.get_permissive())
+        properties = properties - set(self.get_permissive(opt_or_descr))
+        return list(properties)
+
     #____________________________________________________________
     def validate_properties(self, opt_or_descr, is_descr, is_write,
                             value=None, force_permissive=False,
@@ -230,26 +254,16 @@ class Setting(object):
                 properties = props
                 is_cached = True
         if not is_cached:
-            properties = set(self.get_properties(opt_or_descr))
-            #remove this properties, those properties are validate in after
-            properties = properties - set(['mandatory', 'frozen'])
-            set_properties = self.get_properties()
-            if force_properties is not None:
-                set_properties.extend(force_properties)
-            set_properties = set(set_properties)
-            properties = properties & set_properties
-            if force_permissive is True or self.has_property('permissive', is_apply_req=False):
-                properties = properties - set(self.get_permissive())
-            properties = properties - set(self.get_permissive(opt_or_descr))
-            properties = list(properties)
+            properties = self._calc_properties(opt_or_descr, force_permissive,
+                                               force_properties)
             raise_text = _("trying to access"
                            " to an option named: {0} with properties"
                            " {1}")
             if not is_descr:
-                if self.context.cfgimpl_get_values().is_mandatory_err(opt_or_descr,
-                                                                      value,
-                                                                      force_properties=force_properties):
+                if self._validate_mandatory(opt_or_descr, value,
+                                            force_properties=force_properties):
                     properties.append('mandatory')
+                #frozen
                 if is_write and (self.has_property('everything_frozen') or (
                         self.has_property('frozen') and
                         self.has_property('frozen', opt_or_descr,
index fbd52e9..08a6f55 100644 (file)
@@ -24,45 +24,8 @@ from tiramisu.autolib import carry_out_calculation
 from tiramisu.i18n import _
 
 
-class ExpirValues(object):
-    __slots__ = ('_cache')
-
-    def __init__(self):
-        self._cache = {}
-
-    def __getitem__(self, opt):
-        return self.getitem(opt)
-
-    def getitem(self, opt, validate=True, force_permissive=False,
-                force_properties=None):
-        if opt in self._cache:
-            t = time()
-            value, created = self._cache[opt]
-            if t - created < expires_time:
-                return value
-        val = self._getitem(opt, validate, force_permissive, force_properties)
-        self._set_cache(opt, val)
-        return val
-
-    def __setitem__(self, opt, value):
-        self.setitem(opt, value)
-
-    def setitem(self, opt, value, force_permissive=False):
-        self._setitem(opt, value, force_permissive)
-
-    def __delitem__(self, opt):
-        self._reset(opt)
-
-    def _set_cache(self, opt, val):
-        if self.context.cfgimpl_get_settings().has_property('expire'):
-            self._cache[opt] = (val, time())
-
-    def reset_cache(self):
-        self._cache = {}
-
-
-class Values(ExpirValues):
-    __slots__ = ('context', '_values')
+class Values(object):
+    __slots__ = ('context', '_values', '_cache')
 
     def __init__(self, context):
         """
@@ -73,6 +36,7 @@ class Values(ExpirValues):
         "Config's root indeed is in charge of the `Option()`'s values"
         self.context = context
         self._values = {}
+        self._cache = {}
         super(Values, self).__init__()
 
     def _get_value(self, opt):
@@ -82,24 +46,14 @@ class Values(ExpirValues):
             value = opt.getdefault()
             if opt.is_multi():
                 value = Multi(value, self.context, opt)
-                #if slave, had values until master's one
-                if opt.get_multitype() == multitypes.slave:
-                    masterpath = self.context.cfgimpl_get_description().get_path_by_opt(opt.get_master_slaves())
-                    mastervalue = getattr(self.context, masterpath)
-                    masterlen = len(mastervalue)
-                    if len(value) > masterlen:
-                        raise ValueError(_("invalid len for the slave: {0}"
-                                           " which has {1} as master").format(
-                                               opt._name, masterpath))
-                    if len(value) < masterlen:
-                        for num in range(0, masterlen - len(value)):
-                            value.append(opt.getdefault_multi(), force=True)
-                    #FIXME si inferieur ??
         else:
             #if value
             value = self._values[opt][1]
         return value
 
+    def __delitem__(self, opt):
+        self._reset(opt)
+
     def _reset(self, opt):
         if opt in self._values:
             self.context.cfgimpl_clean_cache()
@@ -116,26 +70,6 @@ class Values(ExpirValues):
             return True
         return False
 
-    def is_mandatory_err(self, opt, value, force_properties=None):
-        setting = self.context.cfgimpl_get_settings()
-        set_mandatory = setting.has_property('mandatory')
-        if force_properties is not None:
-            set_mandatory = ('mandatory' in force_properties or
-                             set_mandatory)
-        if set_mandatory and setting.has_property('mandatory', opt, False) and \
-                self._is_empty(opt, value):
-            return True
-        return False
-
-    def fill_multi(self, opt, result):
-        """fills a multi option with default and calculated values
-        """
-        if not isinstance(result, list):
-            _result = [result]
-        else:
-            _result = result
-        return Multi(_result, self.context, opt)  # , multitype)
-
     def _getcallback_value(self, opt):
         callback, callback_params = opt._callback
         if callback_params is None:
@@ -144,6 +78,20 @@ class Values(ExpirValues):
                                      callback=callback,
                                      callback_params=callback_params)
 
+    def __getitem__(self, opt):
+        return self.getitem(opt)
+
+    def getitem(self, opt, validate=True, force_permissive=False,
+                force_properties=None):
+        if opt in self._cache:
+            t = time()
+            value, created = self._cache[opt]
+            if t - created < expires_time:
+                return value
+        val = self._getitem(opt, validate, force_permissive, force_properties)
+        self._set_cache(opt, val)
+        return val
+
     def _getitem(self, opt, validate, force_permissive, force_properties):
         # options with callbacks
         setting = self.context.cfgimpl_get_settings()
@@ -160,14 +108,14 @@ class Values(ExpirValues):
             else:
                 value = self._getcallback_value(opt)
                 if opt.is_multi():
-                    value = self.fill_multi(opt, value)
+                    value = Multi(value, self.context, opt)
                 #suppress value if already set
                 self._reset(opt)
         # frozen and force default
         elif is_frozen and setting.has_property('force_default_on_freeze', opt, False):
             value = opt.getdefault()
             if opt.is_multi():
-                value = self.fill_multi(opt, value)
+                value = Multi(value, self.context, opt)
         if validate and not opt.validate(value, self.context, setting.has_property('validator')):
             raise ValueError(_('invalid calculated value returned'
                              ' for option {0}: {1}').format(opt._name, value))
@@ -179,35 +127,20 @@ class Values(ExpirValues):
                                     force_properties=force_properties)
         return value
 
+    def __setitem__(self, opt, value):
+        self.setitem(opt, value)
+
+    def setitem(self, opt, value, force_permissive=False):
+        self._setitem(opt, value, force_permissive)
+
     def _setitem(self, opt, value, force_permissive=False, force_properties=None):
         #valid opt
         if not opt.validate(value, self.context,
                             self.context.cfgimpl_get_settings().has_property('validator')):
             raise ValueError(_('invalid value {}'
                              ' for option {}').format(value, opt._name))
-        if opt.is_multi():
-            if opt.get_multitype() == multitypes.master:
-                masterlen = len(value)
-                for slave in opt.master_slaves:
-                    value_slave = self._get_value(slave)
-                    if len(value_slave) > masterlen:
-                        raise ValueError(_("invalid len for the slave: {0}"
-                                           " which has {1} as master").format(
-                                               slave._name, opt._name))
-                    elif len(value_slave) < masterlen:
-                        for num in range(0, masterlen - len(value_slave)):
-                            value_slave.append(slave.getdefault_multi(), force=True)
-
-            elif opt.get_multitype() == multitypes.slave:
-                if len(self._get_value(opt.master_slaves)) != len(value):
-                    raise ValueError(_("invalid len for the slave: {0}"
-                                       " which has {1} as master").format(
-                                           opt._name, opt.master_slaves._name))
-            if not isinstance(value, Multi):
-                value = Multi(value, self.context, opt)
-        if type(value) == list:
-            raise ValueError(_("the type of the value {0} which is multi shall "
-                               "be Multi and not list").format(str(value)))
+        if opt.is_multi() and not isinstance(value, Multi):
+            value = Multi(value, self.context, opt)
         self._setvalue(opt, value, force_permissive=force_permissive,
                        force_properties=force_properties)
 
@@ -238,6 +171,13 @@ class Values(ExpirValues):
         """
         return self.getowner(opt) == owners.default
 
+    def _set_cache(self, opt, val):
+        if self.context.cfgimpl_get_settings().has_property('expire'):
+            self._cache[opt] = (val, time())
+
+    def reset_cache(self):
+        self._cache = {}
+
     def __contains__(self, opt):
         return opt in self._values
 
@@ -250,15 +190,53 @@ class Multi(list):
     that support item notation for the values of multi options"""
     __slots__ = ('opt', 'context')
 
-    def __init__(self, lst, context, opt):
+    def __init__(self, value, context, opt):
         """
-        :param lst: the Multi wraps a list value
+        :param value: the Multi wraps a list value
         :param context: the home config that has the values
         :param opt: the option object that have this Multi value
         """
         self.opt = opt
         self.context = context
-        super(Multi, self).__init__(lst)
+        if not isinstance(value, list):
+            value = [value]
+        if self.opt.get_multitype() == multitypes.slave:
+            value = self._valid_slave(value)
+        elif self.opt.get_multitype() == multitypes.master:
+            self._valid_master(value)
+        super(Multi, self).__init__(value)
+
+    def _valid_slave(self, value):
+        #if slave, had values until master's one
+        masterp = self.context.cfgimpl_get_description().get_path_by_opt(
+            self.opt.get_master_slaves())
+        mastervalue = getattr(self.context, masterp)
+        masterlen = len(mastervalue)
+        if len(value) > masterlen or (len(value) < masterlen and
+                                      not self.context.cfgimpl_get_values().is_default_owner(self.opt)):
+            raise ValueError(_("invalid len for the slave: {0}"
+                               " which has {1} as master").format(
+                                   self.opt._name, masterp))
+        elif len(value) < masterlen:
+            for num in range(0, masterlen - len(value)):
+                value.append(self.opt.getdefault_multi())
+        #else: same len so do nothing
+        return value
+
+    def _valid_master(self, value):
+        masterlen = len(value)
+        values = self.context.cfgimpl_get_values()
+        for slave in self.opt._master_slaves:
+            if not values.is_default_owner(slave):
+                value_slave = values._get_value(slave)
+                if len(value_slave) > masterlen:
+                    raise ValueError(_("invalid len for the master: {0}"
+                                       " which has {1} as slave with"
+                                       " greater len").format(
+                                           self.opt._name, slave._name))
+                elif len(value_slave) < masterlen:
+                    for num in range(0, masterlen - len(value_slave)):
+                        value_slave.append(slave.getdefault_multi(), force=True)
 
     def __setitem__(self, key, value):
         self._validate(value)
@@ -276,8 +254,10 @@ class Multi(list):
                                    " which is a slave").format(self.opt._name))
             elif self.opt.get_multitype() == multitypes.master:
                 for slave in self.opt.get_master_slaves():
-                    self.context.cfgimpl_get_values()[slave].append(
-                        slave.getdefault_multi(), force=True)
+                    values = self.context.cfgimpl_get_values()
+                    if not values.is_default_owner(slave):
+                        values[slave].append(slave.getdefault_multi(),
+                                             force=True)
         self._validate(value)
         #assume not checking mandatory property
         self.context.cfgimpl_get_values()._setvalue(self.opt, self)
@@ -297,10 +277,10 @@ class Multi(list):
         :return: the requested element
         """
         if not force:
-            if self.opt.multitype == multitypes.slave:
-                raise ValueError(_("cannot append a value on a multi option {0}"
+            if self.opt.get_multitype() == multitypes.slave:
+                raise ValueError(_("cannot pop a value on a multi option {0}"
                                    " which is a slave").format(self.opt._name))
-            elif self.opt.multitype == multitypes.master:
+            elif self.opt.get_multitype() == multitypes.master:
                 for slave in self.opt.get_master_slaves():
                     self.context.cfgimpl_get_values()[slave].pop(key, force=True)
         self.context.cfgimpl_get_values()._setvalue(self.opt, self)