# -*- coding: utf-8 -*- "master slave support" # Copyright (C) 2014 Team tiramisu (see AUTHORS for all contributors) # # This program is free software: you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License as published by the # Free Software Foundation, either version 3 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more # details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . # # The original `Config` design model is unproudly borrowed from # the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/ # the whole pypy projet is under MIT licence # ____________________________________________________________ from tiramisu.i18n import _ from tiramisu.setting import log from tiramisu.error import SlaveError, ConfigError from .baseoption import SymLinkOption, Option class MasterSlaves(object): __slots__ = ('master', 'slaves') def __init__(self, name, childs): #if master (same name has group) is set #for collect all slaves self.master = None slaves = [] for child in childs: if isinstance(child, SymLinkOption): raise ValueError(_("master group {0} shall not have " "a symlinkoption").format(name)) if not isinstance(child, Option): raise ValueError(_("master group {0} shall not have " "a subgroup").format(name)) if not child.impl_is_multi(): raise ValueError(_("not allowed option {0} " "in group {1}" ": this option is not a multi" "").format(child._name, name)) if child._name == name: self.master = child else: slaves.append(child) if self.master is None: raise ValueError(_('master group with wrong' ' master name for {0}' ).format(name)) callback, callback_params = self.master.impl_get_callback() if callback is not None and callback_params is not None: 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 def in_same_group(self, opt): return opt == self.master or opt in self.slaves def reset(self, values): for slave in self.slaves: values.reset(slave) def pop(self, values, index): #FIXME pas test de meta ... for slave in self.slaves: if not values.is_default_owner(slave, validate_properties=False, validate_meta=False): values._get_cached_item(slave, validate=False, validate_properties=False ).pop(index, force=True) pass def getitem(self, values, opt, path, validate, force_permissive, force_properties, validate_properties): if opt == self.master: return self._getmaster(values, opt, path, validate, force_permissive, force_properties, validate_properties) 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): 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) 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 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) def setitem(self, values, opt, value, path): if opt == self.master: masterlen = len(value) for slave in self.slaves: slave_path = values._get_opt_path(slave) 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) else: self.validate_slave_length(self.get_length(values), len(value), opt._name, 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 validate_slave_length(self, masterlen, valuelen, name, setitem=False): if valuelen > masterlen or (valuelen < masterlen and setitem): 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)) def get_slave_value(self, values, opt, value, validate=True, validate_properties=True): """ if master has length 0: return [] if master has length bigger than 0: if default owner: if has callback: if return a list: list same length as master: return list list is smaller than master: return list + None list is greater than master: raise SlaveError if has default value: list same length as master: return list list is smaller than master: return list + None list is greater than master: raise SlaveError if has default_multi value: return default_multi * master's length if has value: list same length as master: return list list is smaller than master: return list + None list is greater than master: raise SlaveError """ #if slave, had values until master's one masterlen = self.get_length(values, validate) valuelen = len(value) if validate: self.validate_slave_length(masterlen, valuelen, opt._name) path = values._get_opt_path(opt) if valuelen < masterlen: for num in range(0, masterlen - valuelen): index = valuelen + num value.append(values._get_validated_value(opt, path, True, False, None, validate_properties, index=index), setitem=False, force=True) return value