tiramisu/tiramisu/option/masterslave.py

201 lines
9.3 KiB
Python

# -*- 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 <http://www.gnu.org/licenses/>.
#
# 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