Add MasterSlaves object

This commit is contained in:
2017-10-14 13:33:25 +02:00
parent 7e281235bc
commit 5a1987f2e6
25 changed files with 685 additions and 649 deletions

View File

@ -23,11 +23,11 @@ import re
from ..i18n import _
from ..setting import groups, undefined, owners # , log
from ..setting import groups, undefined, owners, log, debug
from .baseoption import BaseOption
from .option import Option, ALLOWED_CONST_LIST
from . import MasterSlaves
from ..error import ConfigError, ConflictError
#from . import MasterSlaves
from ..error import ConfigError, ConflictError, SlaveError, PropertiesOptionError
from ..autolib import carry_out_calculation
@ -461,6 +461,7 @@ class OptionDescription(OptionDescriptionWalk):
if isinstance(group_type, groups.GroupType):
self._group_type = group_type
if isinstance(group_type, groups.MasterGroupType):
raise Exception('please use MasterSlaves object instead of OptionDescription')
children = self.impl_getchildren()
for child in children:
if child._is_symlinkoption(): # pragma: optional cover
@ -557,6 +558,300 @@ class SynDynOptionDescription(object):
return self._opt
class MasterSlaves(OptionDescription):
__slots__ = ('master', 'slaves')
def __init__(self, name, doc, children, requires=None, properties=None):
#if master (same name has group) is set
#for collect all slaves
super(MasterSlaves, self).__init__(name,
doc,
children,
requires=requires,
properties=properties)
self._group_type = groups.master
slaves = []
master = children[0]
if master.impl_getname() != name:
raise ValueError(_('master group with wrong'
' master name for {0}'
).format(name))
for child in children[1:]:
if child.impl_getdefault() != []:
raise ValueError(_("not allowed default value for option {0} "
"in master/slave object {1}").format(child.impl_getname(),
name))
slaves.append(child)
child._add_dependency(self)
for child in children:
if child._is_symlinkoption(): # pragma: optional cover
raise ValueError(_("master group {0} shall not have "
"a symlinkoption").format(self.impl_getname()))
if not isinstance(child, Option): # pragma: optional cover
raise ValueError(_("master group {0} shall not have "
"a subgroup").format(self.impl_getname()))
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.impl_getname(), self.impl_getname()))
callback, callback_params = master.impl_get_callback()
if callback is not None and callback_params != {}:
for callbacks in callback_params.values():
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.master = master
#self.slaves = tuple(slaves)
for child in children:
child._master_slaves = self
master._add_dependency(self)
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, opt):
master = self._children[1][0]
if opt is not None and opt.impl_is_dynsymlinkoption():
suffix = opt.impl_getsuffix()
name = master.impl_getname() + suffix
base_path = opt._dyn.split('.')[0] + '.'
path = base_path + name
master = master._impl_to_dyn(name, path)
return master
def getslaves(self, opt):
if opt.impl_is_dynsymlinkoption():
for slave in self._children[1][1:]:
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:
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, opt, values, setting_properties, _commit=True):
for slave in self.getslaves(opt):
values.reset(slave, validate=False, _setting_properties=setting_properties,
_commit=_commit)
def pop(self, opt, values, index):
for slave in self.getslaves(opt):
if not values.is_default_owner(slave, validate_properties=False,
validate_meta=False, index=index):
multi = values._get_cached_value(slave, validate=False,
validate_properties=False,
)
if isinstance(multi, Exception):
raise multi
multi.pop(index, force=True)
def getitem(self, values, opt, path, validate, force_permissive,
trusted_cached_properties, validate_properties,
slave_path=undefined, slave_value=undefined,
setting_properties=undefined, self_properties=undefined, index=None,
check_frozen=False):
if self.is_master(opt):
return self._getmaster(values, opt, path, validate,
force_permissive,
validate_properties, slave_path,
slave_value, self_properties, index,
setting_properties, check_frozen)
else:
return self._getslave(values, opt, path, validate,
force_permissive, trusted_cached_properties,
validate_properties, setting_properties,
self_properties, index,
check_frozen)
def _getmaster(self, values, opt, path, validate, force_permissive,
validate_properties, c_slave_path,
c_slave_value, self_properties, index,
setting_properties, check_frozen):
return values._get_cached_value(opt, path=path, validate=validate,
force_permissive=force_permissive,
validate_properties=validate_properties,
self_properties=self_properties,
from_masterslave=True, index=index,
setting_properties=setting_properties,
check_frozen=check_frozen)
def _getslave(self, values, opt, path, validate, force_permissive,
trusted_cached_properties, validate_properties, setting_properties,
self_properties, index, check_frozen):
"""
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
"""
master = self.getmaster(opt)
context = values._getcontext()
masterp = master.impl_getpath(context)
mastervalue = values._get_cached_value(master, path=masterp, validate=validate,
force_permissive=force_permissive,
validate_properties=validate_properties,
self_properties=self_properties,
from_masterslave=True,
setting_properties=setting_properties,
check_frozen=check_frozen)
if isinstance(mastervalue, Exception):
if isinstance(mastervalue, PropertiesOptionError):
mastervalue.set_orig_opt(opt)
return mastervalue
masterlen = len(mastervalue)
master_is_meta = values._is_meta(master, masterp, force_permissive=force_permissive)
multi = values._get_multi(opt, path)
if validate_properties:
props = context.cfgimpl_get_settings().validate_properties(opt, False,
check_frozen,
value=multi,
path=path,
force_permissive=force_permissive,
setting_properties=setting_properties)
if props:
return props
if index is None:
indexes = xrange(0, masterlen)
else:
indexes = [index]
for idx in indexes:
value = values._get_cached_value(opt, path, validate,
force_permissive,
trusted_cached_properties,
validate_properties,
with_meta=master_is_meta,
index=idx,
# not self_properties,
# depends to index
#self_properties=self_properties,
setting_properties=setting_properties,
masterlen=masterlen,
from_masterslave=True,
check_frozen=check_frozen)
if isinstance(value, Exception):
if isinstance(value, PropertiesOptionError):
err = value
if index is None:
multi.append_properties_error(value)
else:
multi = value
else:
return value
elif index is None:
multi.append(value, setitem=False, force=True, validate=False,
force_permissive=force_permissive)
else:
multi = value
return multi
def validate(self, values, opt, index, path, setitem):
if self.is_master(opt):
#for regen slave path
base_path = '.'.join(path.split('.')[:-1]) + '.'
for slave in self.getslaves(opt):
slave_path = base_path + slave.impl_getname()
slavelen = values._p_.get_max_length(slave_path)
self.validate_slave_length(index, slavelen, slave.impl_getname(), opt)
else:
val_len = self.get_length(values, opt, slave_path=path)
if isinstance(val_len, Exception):
return val_len
self.validate_slave_length(val_len, index,
opt.impl_getname(), opt, setitem=setitem)
def get_length(self, values, opt, validate=True, slave_path=undefined,
slave_value=undefined, force_permissive=False, master=None,
masterp=None, setting_properties=undefined):
"""get master len with slave option"""
if master is None:
master = self.getmaster(None)
if masterp is None:
masterp = master.impl_getpath(self._getcontext())
if slave_value is undefined:
slave_path = undefined
value = self.getitem(values, master, masterp, validate,
force_permissive, None, True, slave_path=slave_path,
slave_value=slave_value, setting_properties=setting_properties)
if isinstance(value, Exception):
return value
return len(value)
def validate_slave_length(self, masterlen, valuelen, name, opt, setitem=False):
if valuelen > masterlen or (valuelen < masterlen and setitem):
if debug: # pragma: no cover
log.debug('validate_slave_length: masterlen: {0}, valuelen: {1}, '
'setitem: {2}'.format(masterlen, valuelen, setitem))
if not opt.impl_is_master_slaves('master'):
opt = self.getmaster(opt)
raise SlaveError(_("invalid len for the slave: {0}"
" which has {1} as master").format(
name, opt.impl_getname()))
def reset_cache(self, opt, values, type_, orig_opts):
path = self.getmaster(opt).impl_getpath(values._getcontext())
values._p_.delcache(path)
for slave in self.getslaves(opt):
slave_path = slave.impl_getpath(values._getcontext())
values._p_.delcache(slave_path)
def _getattr(self, name, suffix=undefined, context=undefined, dyn=True):
return super(MasterSlaves, self)._getattr(name, suffix, context, dyn)
def impl_validate(self, context, force_permissive, setting_properties, masterlen=None,
slavelen=None, opt=None, setitem=False):
values = context.cfgimpl_get_values()
if masterlen is None:
master = self.getmaster(opt)
masterp = master.impl_getpath(context)
mastervalue = values._get_cached_value(master, path=masterp,
force_permissive=force_permissive,
from_masterslave=True,
setting_properties=setting_properties)
if isinstance(mastervalue, Exception):
return mastervalue
masterlen = len(mastervalue)
else:
master = opt
if slavelen is not None:
self.validate_slave_length(masterlen, slavelen, opt.impl_getname(), master, setitem=setitem)
else:
for slave in self.getslaves(master):
slave_path = slave.impl_getpath(context)
slavelen = values._p_.get_max_length(slave_path, None)
self.validate_slave_length(masterlen, slavelen, slave.impl_getname(), master)
def _impl_getpaths(klass, include_groups, _currpath):
"""returns a list of all paths in klass, recursively
_currpath should not be provided (helps with recursion)