tiramisu/tiramisu/option/masterslave.py

189 lines
7.5 KiB
Python

# -*- coding: utf-8 -*-
"master slave support"
# Copyright (C) 2014-2018 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
# ____________________________________________________________
import weakref
from itertools import chain
from ..i18n import _
from ..setting import groups, undefined
from .optiondescription import OptionDescription
from .option import Option
from ..error import SlaveError, PropertiesOptionError
from ..function import ParamOption
class MasterSlaves(OptionDescription):
__slots__ = ('master', 'slaves')
def __init__(self,
name,
doc,
children,
requires=None,
properties=None):
super(MasterSlaves, self).__init__(name,
doc,
children,
requires=requires,
properties=properties)
self._group_type = groups.master
slaves = []
if len(children) < 2:
raise ValueError(_('a master and a slave are mandatories in masterslaves "{}"').format(name))
master = children[0]
for idx, child in enumerate(children):
if child.impl_is_symlinkoption(): # pragma: optional cover
raise ValueError(_('masterslaves "{0}" shall not have '
"a symlinkoption").format(self.impl_get_display_name()))
if not isinstance(child, Option): # pragma: optional cover
raise ValueError(_('masterslaves "{0}" shall not have '
'a subgroup').format(self.impl_get_display_name()))
if not child.impl_is_multi(): # pragma: optional cover
raise ValueError(_('only multi option allowed in masterslaves "{0}" but option '
'"{1}" is not a multi').format(self.impl_get_display_name(),
child.impl_get_display_name()))
if idx != 0 and child.impl_getdefault() != []:
raise ValueError(_('not allowed default value for option "{0}" '
'in masterslaves "{1}"'
'').format(child.impl_get_display_name(),
self.impl_get_display_name()))
# no empty property for save
if idx != 0:
properties = list(child._properties)
properties.remove('empty')
child._properties = frozenset(properties)
slaves.append(child)
child._add_dependency(self)
child._master_slaves = weakref.ref(self)
callback, callback_params = master.impl_get_callback()
if callback is not None and callback_params != None:
for callbk in chain(callback_params.args, callback_params.kwargs.values()):
if isinstance(callbk, ParamOption):
if callbk.option in slaves:
raise ValueError(_("callback of master's option shall "
"not refered a slave's ones"))
def is_master(self, opt):
master = self._children[0][0]
return opt.impl_getname() == master or (opt.impl_is_dynsymlinkoption() and
opt._opt.impl_getname() == master)
def getmaster(self):
return self._children[1][0]
def getslaves(self):
for slave in self._children[1][1:]:
yield slave
def in_same_group(self, opt):
if opt.impl_is_dynsymlinkoption():
c_opt = opt._opt
else:
c_opt = opt
return c_opt in self._children[1]
def reset(self,
values,
config_bag,
_commit=True):
for slave in self.getslaves():
sconfig_bag = config_bag.copy('nooption')
sconfig_bag.option = slave
sconfig_bag.validate = False
slave_path = slave.impl_getpath(values._getcontext())
values.reset(slave_path,
sconfig_bag,
_commit=_commit)
def pop(self,
values,
index,
config_bag,
slaves=undefined):
context = values._getcontext()
if slaves is undefined:
slaves = self.getslaves()
for slave in slaves:
slave_path = slave.impl_getpath(context)
slavelen = values._p_.get_max_length(slave_path)
sconfig_bag = config_bag.copy('nooption')
sconfig_bag.option = slave
if not values.is_default_owner(slave_path,
index,
config_bag,
validate_meta=False):
if slavelen > index:
values._p_.resetvalue_index(slave_path,
index)
if slavelen > index + 1:
for idx in range(index + 1, slavelen):
values._p_.reduce_index(slave_path,
idx)
def reset_cache(self,
path,
values,
settings,
resetted_opts):
master = self.getmaster()
slaves = self.getslaves()
self._reset_cache(master,
slaves,
values,
settings,
resetted_opts)
def _reset_cache(self,
master,
slaves,
values,
settings,
resetted_opts):
context = values._getcontext()
mpath = master.impl_getpath(context)
master.reset_cache(mpath,
values,
settings,
None)
for slave in slaves:
spath = slave.impl_getpath(context)
slave.reset_cache(spath,
values,
settings,
None)
resetted_opts.append(spath)
def impl_validate_value(self,
option,
value,
context):
if option.impl_is_master_slaves('master') and isinstance(value, list):
if len(value) < context._impl_length:
raise SlaveError(_('cannot reduce length of the master "{}"'
'').format(option.impl_get_display_name()))
def impl_is_master_slaves(self, *args, **kwargs):
return True