pass force_permissive to slave for a master or to master for a slave
[tiramisu.git] / tiramisu / option / masterslave.py
index 9e0426d..09c77b3 100644 (file)
 # the whole pypy projet is under MIT licence
 # ____________________________________________________________
 from tiramisu.i18n import _
-from tiramisu.setting import log
+from tiramisu.setting import log, undefined
 from tiramisu.error import SlaveError, ConfigError
-from .baseoption import SymLinkOption, Option
+from .baseoption import DynSymLinkOption, SymLinkOption, Option
 
 
 class MasterSlaves(object):
     __slots__ = ('master', 'slaves')
 
-    def __init__(self, name, childs):
+    def __init__(self, name, childs, validate=True):
         #if master (same name has group) is set
         #for collect all slaves
         self.master = None
         slaves = []
         for child in childs:
-            if isinstance(child, SymLinkOption):
+            if isinstance(child, SymLinkOption):  # pragma: optional cover
                 raise ValueError(_("master group {0} shall not have "
                                    "a symlinkoption").format(name))
-            if not isinstance(child, Option):
+            if not isinstance(child, Option):  # pragma: optional cover
                 raise ValueError(_("master group {0} shall not have "
                                    "a subgroup").format(name))
-            if not child.impl_is_multi():
+            if not child.impl_is_multi():  # pragma: optional cover
                 raise ValueError(_("not allowed option {0} "
                                    "in group {1}"
                                    ": this option is not a multi"
-                                   "").format(child._name, name))
-            if child._name == name:
+                                   "").format(child.impl_getname(), name))
+            if child.impl_getname() == name:
                 self.master = child
             else:
                 slaves.append(child)
-        if self.master is None:
+        if self.master is None:  # pragma: optional cover
             raise ValueError(_('master group with wrong'
                                ' master name for {0}'
                                ).format(name))
-        if self.master._callback is not None and self.master._callback[1] is not None:
-            for key, callbacks in self.master._callback[1].items():
-                for callbk in callbacks:
-                    if isinstance(callbk, tuple):
-                        if callbk[0] in slaves:
-                            raise ValueError(_("callback of master's option shall "
-                                               "not refered a slave's ones"))
+        if validate:
+            callback, callback_params = self.master.impl_get_callback()
+            if callback is not None and callback_params != {}:  # pragma: optional cover
+                for key, callbacks in callback_params.items():
+                    for callbk in callbacks:
+                        if isinstance(callbk, tuple):
+                            if callbk[0] in slaves:
+                                raise ValueError(_("callback of master's option shall "
+                                                   "not refered a slave's ones"))
         #everything is ok, store references
         self.slaves = tuple(slaves)
         for child in childs:
             child._master_slaves = self
 
     def is_master(self, opt):
-        return opt == self.master
+        return opt == self.master or (isinstance(opt, DynSymLinkOption) and
+                                      opt._opt == self.master)
+
+    def getmaster(self, opt):
+        if isinstance(opt, DynSymLinkOption):
+            suffix = opt.impl_getsuffix()
+            name = self.master.impl_getname() + suffix
+            base_path = opt._dyn.split('.')[0] + '.'
+            path = base_path + name
+            master = self.master._impl_to_dyn(name, path)
+        else:  # pragma: no dynoptiondescription cover
+            master = self.master
+        return master
+
+    def getslaves(self, opt):
+        if isinstance(opt, DynSymLinkOption):
+            for slave in self.slaves:
+                suffix = opt.impl_getsuffix()
+                name = slave.impl_getname() + suffix
+                base_path = opt._dyn.split('.')[0] + '.'
+                path = base_path + name
+                yield slave._impl_to_dyn(name, path)
+        else:  # pragma: no dynoptiondescription cover
+            for slave in self.slaves:
+                yield slave
 
     def in_same_group(self, opt):
-        return opt == self.master or opt in self.slaves
+        if isinstance(opt, DynSymLinkOption):
+            return opt._opt == self.master or opt._opt in self.slaves
+        else:  # pragma: no dynoptiondescription cover
+            return opt == self.master or opt in self.slaves
 
-    def reset(self, values):
-        for slave in self.slaves:
+    def reset(self, opt, values):
+        #FIXME pas de opt ???
+        for slave in self.getslaves(opt):
             values.reset(slave)
 
-    def pop(self, values, index):
+    def pop(self, opt, values, index):
         #FIXME pas test de meta ...
-        for slave in self.slaves:
+        for slave in self.getslaves(opt):
             if not values.is_default_owner(slave, validate_properties=False,
                                            validate_meta=False):
                 values._get_cached_item(slave, validate=False,
@@ -86,41 +116,60 @@ class MasterSlaves(object):
         pass
 
     def getitem(self, values, opt, path, validate, force_permissive,
-                force_properties, validate_properties):
-        if opt == self.master:
-            value = values._get_validated_value(opt, path, validate,
-                                                force_permissive,
-                                                force_properties,
-                                                validate_properties)
-            if validate is True:
-                masterlen = len(value)
-                for slave in self.slaves:
-                    try:
-                        slave_path = values._get_opt_path(slave)
+                force_properties, validate_properties, slave_path=undefined,
+                slave_value=undefined):
+        if self.is_master(opt):
+            return self._getmaster(values, opt, path, validate,
+                                   force_permissive, force_properties,
+                                   validate_properties, slave_path,
+                                   slave_value)
+        else:
+            return self._getslave(values, opt, path, validate,
+                                  force_permissive, force_properties,
+                                  validate_properties)
+
+    def _getmaster(self, values, opt, path, validate, force_permissive,
+                   force_properties, validate_properties, c_slave_path,
+                   c_slave_value):
+        value = values._get_validated_value(opt, path, validate,
+                                            force_permissive,
+                                            force_properties,
+                                            validate_properties)
+        if validate is True:
+            masterlen = len(value)
+            for slave in self.getslaves(opt):
+                try:
+                    slave_path = slave.impl_getpath(values._getcontext())
+                    if c_slave_path == slave_path:
+                        slave_value = c_slave_value
+                    else:
                         slave_value = values._get_validated_value(slave,
                                                                   slave_path,
                                                                   False,
                                                                   False,
                                                                   None, False,
                                                                   None)  # not undefined
-                        slavelen = len(slave_value)
-                        self.validate_slave_length(masterlen, slavelen, slave._name)
-                    except ConfigError:
-                        pass
-            return value
-        else:
-            value = values._get_validated_value(opt, path, validate,
-                                                force_permissive,
-                                                force_properties,
-                                                validate_properties,
-                                                None)  # not undefined
-            return self.get_slave_value(values, opt, value, validate, validate_properties)
+                    slavelen = len(slave_value)
+                    self.validate_slave_length(masterlen, slavelen, slave.impl_getname(), opt)
+                except ConfigError:  # pragma: optional cover
+                    pass
+        return value
+
+    def _getslave(self, values, opt, path, validate, force_permissive,
+                  force_properties, validate_properties):
+        value = values._get_validated_value(opt, path, validate,
+                                            force_permissive,
+                                            force_properties,
+                                            validate_properties,
+                                            None)  # not undefined
+        return self.get_slave_value(values, opt, value, validate,
+                                    validate_properties, force_permissive)
 
     def setitem(self, values, opt, value, path):
-        if opt == self.master:
+        if self.is_master(opt):
             masterlen = len(value)
-            for slave in self.slaves:
-                slave_path = values._get_opt_path(slave)
+            for slave in self.getslaves(opt):
+                slave_path = slave.impl_getpath(values._getcontext())
                 slave_value = values._get_validated_value(slave,
                                                           slave_path,
                                                           False,
@@ -128,26 +177,32 @@ class MasterSlaves(object):
                                                           None, False,
                                                           None)  # not undefined
                 slavelen = len(slave_value)
-                self.validate_slave_length(masterlen, slavelen, slave._name)
+                self.validate_slave_length(masterlen, slavelen, slave.impl_getname(), opt)
         else:
-            self.validate_slave_length(self.get_length(values), len(value),
-                                       opt._name, setitem=True)
+            self.validate_slave_length(self.get_length(values, opt,
+                                                       slave_path=path), len(value),
+                                       opt.impl_getname(), opt, setitem=True)
 
-    def get_length(self, values, validate=True):
-        masterp = values._get_opt_path(self.master)
-        return len(self.getitem(values, self.master, masterp, validate, False,
-                                None, True))
+    def get_length(self, values, opt, validate=True, slave_path=undefined,
+                   slave_value=undefined, force_permissive=False):
+        """get master len with slave option"""
+        masterp = self.getmaster(opt).impl_getpath(values._getcontext())
+        if slave_value is undefined:
+            slave_path = undefined
+        return len(self.getitem(values, self.getmaster(opt), masterp, validate,
+                                force_permissive, None, True, slave_path,
+                                slave_value))
 
-    def validate_slave_length(self, masterlen, valuelen, name, setitem=False):
-        if valuelen > masterlen or (valuelen < masterlen and setitem):
+    def validate_slave_length(self, masterlen, valuelen, name, opt, setitem=False):
+        if valuelen > masterlen or (valuelen < masterlen and setitem):  # pragma: optional cover
             log.debug('validate_slave_length: masterlen: {0}, valuelen: {1}, '
                       'setitem: {2}'.format(masterlen, valuelen, setitem))
             raise SlaveError(_("invalid len for the slave: {0}"
                                " which has {1} as master").format(
-                                   name, self.master._name))
+                                   name, self.getmaster(opt).impl_getname()))
 
     def get_slave_value(self, values, opt, value, validate=True,
-                        validate_properties=True):
+                        validate_properties=True, force_permissive=False):
         """
         if master has length 0:
             return []
@@ -170,11 +225,12 @@ class MasterSlaves(object):
                 list is greater than master: raise SlaveError
         """
         #if slave, had values until master's one
-        masterlen = self.get_length(values, validate)
+        path = opt.impl_getpath(values._getcontext())
+        masterlen = self.get_length(values, opt, validate, path, value,
+                                    force_permissive)
         valuelen = len(value)
         if validate:
-            self.validate_slave_length(masterlen, valuelen, opt._name)
-        path = values._get_opt_path(opt)
+            self.validate_slave_length(masterlen, valuelen, opt.impl_getname(), opt)
         if valuelen < masterlen:
             for num in range(0, masterlen - valuelen):
                 index = valuelen + num