diff --git a/.gitignore b/.gitignore
index d2b56ea..4802f20 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,5 +2,6 @@
*#
*.pyc
*.mo
+*.swp
version.in
build/
diff --git a/tiramisu/option/__init__.py b/tiramisu/option/__init__.py
index f78de2f..d770343 100644
--- a/tiramisu/option/__init__.py
+++ b/tiramisu/option/__init__.py
@@ -1,5 +1,7 @@
-from .optiondescription import OptionDescription, DynOptionDescription, \
- SynDynOptionDescription, MasterSlaves
+from .optiondescription import OptionDescription
+from .dynoptiondescription import DynOptionDescription
+from .syndynoptiondescription import SynDynOptionDescription
+from .masterslave import MasterSlaves
from .baseoption import SymLinkOption, DynSymLinkOption, submulti
from .option import Option
from .choiceoption import ChoiceOption
diff --git a/tiramisu/option/dynoptiondescription.py b/tiramisu/option/dynoptiondescription.py
new file mode 100644
index 0000000..ac48574
--- /dev/null
+++ b/tiramisu/option/dynoptiondescription.py
@@ -0,0 +1,94 @@
+# -*- coding: utf-8 -*-
+# Copyright (C) 2017 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
+# ____________________________________________________________
+import re
+
+
+from ..i18n import _
+from .optiondescription import OptionDescription
+from ..setting import groups, undefined
+from ..error import ConfigError
+from ..autolib import carry_out_calculation
+
+
+NAME_REGEXP = re.compile(r'^[a-zA-Z\d\-_]*$')
+
+
+class DynOptionDescription(OptionDescription):
+
+ def __init__(self,
+ name,
+ doc,
+ children,
+ requires=None,
+ properties=None,
+ callback=None,
+ callback_params=None):
+
+ super(DynOptionDescription, self).__init__(name,
+ doc,
+ children,
+ requires,
+ properties)
+ # check children + set relation to this dynoptiondescription
+ for child in children:
+ if isinstance(child, OptionDescription):
+ if child.impl_get_group_type() != groups.master:
+ raise ConfigError(_('cannot set optiondescription in a '
+ 'dynoptiondescription'))
+ for chld in child.impl_getchildren(setting_properties=undefined):
+ chld._impl_setsubdyn(self)
+ if child.impl_is_symlinkoption():
+ raise ConfigError(_('cannot set symlinkoption in a '
+ 'dynoptiondescription'))
+ child._impl_setsubdyn(self)
+ # add callback
+ self.impl_set_callback(callback,
+ callback_params)
+
+ def _validate_callback(self,
+ callback,
+ callback_params):
+ if callback is None:
+ raise ConfigError(_('callback is mandatory for the dynoptiondescription "{}"'
+ '').format(self.impl_get_display_name()))
+
+ def _impl_get_suffixes(self,
+ context,
+ setting_properties):
+ callback, callback_params = self.impl_get_callback()
+ values = carry_out_calculation(self,
+ context=context,
+ callback=callback,
+ callback_params=callback_params,
+ setting_properties=setting_properties)
+ if not isinstance(values, list):
+ raise ValueError(_('invalid suffix "{}" for option "{}", must be a list'
+ '').format(values,
+ self.impl_get_display_name()))
+ if len(values) > len(set(values)):
+ raise ValueError(_('DynOptionDescription callback return not unique value'))
+ for val in values:
+ if not isinstance(val, str) or re.match(NAME_REGEXP, val) is None:
+ raise ValueError(_('invalid suffix "{}" for option "{}"'
+ '').format(val,
+ self.impl_get_display_name()))
+ return values
+
diff --git a/tiramisu/option/masterslave.py b/tiramisu/option/masterslave.py
index ecb7493..f06b3a1 100644
--- a/tiramisu/option/masterslave.py
+++ b/tiramisu/option/masterslave.py
@@ -19,6 +19,430 @@
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
# the whole pypy projet is under MIT licence
# ____________________________________________________________
-from .optiondescription import MasterSlaves
+import weakref
+from ..i18n import _
+from ..setting import groups, undefined, log, debug
+from .optiondescription import OptionDescription
+from .option import Option
+from ..error import SlaveError, PropertiesOptionError
+
+
+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 = []
+ master = children[0]
+ if not children:
+ raise ValueError(_('children is mandatory in masterslaves "{}"').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 idx, child in enumerate(children):
+ if child.impl_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()))
+ # no empty property for save
+ if idx != 0:
+ properties = list(child._properties)
+ properties.remove('empty')
+ child._properties = tuple(properties)
+ 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
+ for child in children:
+ child._master_slaves = weakref.ref(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,
+ force_permissive=False):
+
+ for slave in self.getslaves(opt):
+ slave_path = slave.impl_getpath(values._getcontext())
+ values.reset(slave,
+ slave_path,
+ setting_properties,
+ validate=False,
+ _commit=_commit,
+ force_permissive=force_permissive)
+
+ def pop(self,
+ opt,
+ path,
+ values,
+ index,
+ setting_properties,
+ force_permissive=False):
+
+ for slave in self.getslaves(opt):
+ slave_path = slave.impl_getpath(values._getcontext())
+ slavelen = values._p_.get_max_length(slave_path)
+ if not values.is_default_owner(slave,
+ slave_path,
+ setting_properties,
+ validate_meta=False,
+ index=index,
+ force_permissive=force_permissive):
+ #FIXME # just for raise if needed
+ #multi = values.get_cached_value(slave,
+ # validate=False,
+ # validate_properties=False,
+ # )
+ #if isinstance(multi, Exception):
+ # raise multi
+ 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 getitem(self,
+ values,
+ opt,
+ path,
+ validate,
+ force_permissive,
+ trusted_cached_properties,
+ validate_properties,
+ 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,
+ 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,
+ self_properties,
+ index,
+ setting_properties,
+ check_frozen):
+ return values.get_cached_value(opt,
+ path=path,
+ validate=validate,
+ force_permissive=force_permissive,
+ self_properties=self_properties,
+ index=index,
+ setting_properties=setting_properties)
+
+ 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)
+ try:
+ 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)
+ except PropertiesOptionError as mastervalue:
+ mastervalue.set_orig_opt(opt)
+ raise mastervalue
+ masterlen = len(mastervalue)
+ #self._master_is_meta = values._is_meta(master, masterp, force_permissive=force_permissive)
+ multi = list() # 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
+ #FIXME shouldn't have index!!!
+ if index is None:
+ indexes = range(0, masterlen)
+ else:
+ indexes = [index]
+ for idx in indexes:
+ try:
+ value = values.get_cached_value(opt,
+ path,
+ validate,
+ force_permissive,
+ trusted_cached_properties,
+ validate_properties,
+ index=idx,
+ # not self_properties,
+ # depends to index
+ #self_properties=self_properties,
+ setting_properties=setting_properties,
+ from_masterslave=True,
+ check_frozen=check_frozen)
+ except PropertiesOptionError as perr:
+ err = perr
+ if index is None:
+ multi.append(err)
+ else:
+ multi = err
+ if index is None:
+ multi.append(value)
+ 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)
+ 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,
+ validate=True,
+ 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(values._getcontext())
+ value = self._getmaster(values,
+ master,
+ masterp,
+ validate,
+ force_permissive,
+ validate,
+ undefined,
+ None,
+ setting_properties,
+ False)
+ 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,
+ path,
+ obj,
+ type_,
+ resetted_opts):
+ context = obj._getcontext()
+ #FIXME pb avec dyn, devrait etre une option
+ mopt = self.getmaster(None)
+ mpath = mopt.impl_getpath(context)
+ mopt.reset_cache(mopt,
+ mpath,
+ obj,
+ type_,
+ resetted_opts)
+ for slave in self.getslaves(mopt):
+ spath = slave.impl_getpath(context)
+ slave.reset_cache(slave,
+ spath,
+ obj,
+ type_,
+ resetted_opts)
+
+ def impl_getchild(self,
+ name,
+ setting_properties,
+ context=undefined,
+ dyn=True):
+ return super(MasterSlaves, self).impl_getchild(name,
+ setting_properties,
+ 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,
+ 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)
+ self.validate_slave_length(masterlen, slavelen, slave.impl_getname(), master)
+
+ 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:
+ return ValueError(_('cannot reduce length of master "{}"'
+ '').format(option.impl_get_display_name()))
diff --git a/tiramisu/option/optiondescription.py b/tiramisu/option/optiondescription.py
index 6530d6e..5b107ea 100644
--- a/tiramisu/option/optiondescription.py
+++ b/tiramisu/option/optiondescription.py
@@ -19,25 +19,14 @@
# the whole pypy projet is under MIT licence
# ____________________________________________________________
from copy import copy
-import re
-import weakref
from ..i18n import _
-from ..setting import groups, undefined, owners, log, debug
+from ..setting import groups, undefined, owners
from .baseoption import BaseOption
-from .option import Option, ALLOWED_CONST_LIST
-#from . import MasterSlaves
-from ..error import ConfigError, ConflictError, SlaveError, PropertiesOptionError
-from ..autolib import carry_out_calculation
-
-
-NAME_REGEXP = re.compile(r'^[a-zA-Z\d\-_]*$')
-
-import sys
-if sys.version_info[0] >= 3: # pragma: no cover
- xrange = range
-del(sys)
+from .option import ALLOWED_CONST_LIST
+from .syndynoptiondescription import SynDynOptionDescription
+from ..error import ConfigError, ConflictError
class CacheOptionDescription(BaseOption):
@@ -138,7 +127,7 @@ class CacheOptionDescription(BaseOption):
require_opt.impl_getname(), option.impl_getname()))
if init:
if len(cache_option) != len(set(cache_option)):
- for idx in xrange(1, len(cache_option) + 1):
+ for idx in range(1, len(cache_option) + 1):
opt = cache_option.pop(0)
if opt in cache_option:
raise ConflictError(_('duplicate option: {0}').format(opt))
@@ -234,7 +223,7 @@ class OptionDescriptionWalk(CacheOptionDescription):
dynopt):
found = False
spath = path.split('.')
- for length in xrange(1, len(spath)):
+ for length in range(1, len(spath)):
subpath = '.'.join(spath[0:length])
subopt = self.impl_get_opt_by_path(subpath)
if dynopt == subopt:
@@ -243,7 +232,7 @@ class OptionDescriptionWalk(CacheOptionDescription):
if not found: # pragma: no cover
raise ConfigError(_('cannot find dynpath'))
subpath = subpath + suffix
- for slength in xrange(length, len(spath)):
+ for slength in range(length, len(spath)):
subpath = subpath + '.' + spath[slength] + suffix
return subpath
@@ -445,7 +434,7 @@ class OptionDescription(OptionDescriptionWalk):
for child in children:
name = child.impl_getname()
child_names.append(name)
- if isinstance(child, DynOptionDescription):
+ if child.impl_is_dynoptiondescription():
dynopt_names.append(name)
#better performance like this
@@ -503,536 +492,3 @@ class OptionDescription(OptionDescriptionWalk):
value,
context):
pass
-
-
-class DynOptionDescription(OptionDescription):
-
- def __init__(self,
- name,
- doc,
- children,
- requires=None,
- properties=None,
- callback=None,
- callback_params=None):
-
- super(DynOptionDescription, self).__init__(name,
- doc,
- children,
- requires,
- properties)
- # check children + set relation to this dynoptiondescription
- for child in children:
- if isinstance(child, OptionDescription):
- if child.impl_get_group_type() != groups.master:
- raise ConfigError(_('cannot set optiondescription in a '
- 'dynoptiondescription'))
- for chld in child.impl_getchildren(setting_properties=undefined):
- chld._impl_setsubdyn(self)
- if child.impl_is_symlinkoption():
- raise ConfigError(_('cannot set symlinkoption in a '
- 'dynoptiondescription'))
- child._impl_setsubdyn(self)
- # add callback
- self.impl_set_callback(callback,
- callback_params)
-
- def _validate_callback(self,
- callback,
- callback_params):
- if callback is None:
- raise ConfigError(_('callback is mandatory for the dynoptiondescription "{}"'
- '').format(self.impl_get_display_name()))
-
- def _impl_get_suffixes(self,
- context,
- setting_properties):
- callback, callback_params = self.impl_get_callback()
- values = carry_out_calculation(self,
- context=context,
- callback=callback,
- callback_params=callback_params,
- setting_properties=setting_properties)
- if not isinstance(values, list):
- raise ValueError(_('invalid suffix "{}" for option "{}", must be a list'
- '').format(values,
- self.impl_get_display_name()))
- if len(values) > len(set(values)):
- raise ValueError(_('DynOptionDescription callback return not unique value'))
- for val in values:
- if not isinstance(val, str) or re.match(NAME_REGEXP, val) is None:
- raise ValueError(_('invalid suffix "{}" for option "{}"'
- '').format(val,
- self.impl_get_display_name()))
- return values
-
-
-class SynDynOptionDescription(object):
- __slots__ = ('_opt',
- '_name',
- '_suffix')
-
- def __init__(self,
- opt,
- name,
- suffix):
-
- self._opt = opt
- self._name = name
- self._suffix = suffix
-
- def __getattr__(self, name):
- return getattr(self._opt, name)
-
- def impl_getchild(self,
- name,
- setting_properties,
- context):
- if name.endswith(self._suffix):
- oname = name[:-len(self._suffix)]
- child = self._children[1][self._children[0].index(oname)]
- return self._impl_get_dynchild(child,
- self._suffix)
- raise AttributeError(_('unknown Option {0} '
- 'in SynDynOptionDescription {1}'
- '').format(name, self.impl_getname()))
-
- def impl_getname(self):
- return self._name
-
- def impl_getchildren(self,
- setting_properties,
- dyn=True,
- context=undefined):
- children = []
- for child in self._opt.impl_getchildren(setting_properties):
- yield(self._opt._impl_get_dynchild(child,
- self._suffix))
-
- def impl_getpath(self, context):
- path = self.impl_getopt().impl_getpath(context).split('.')
- path[-1] += self._suffix
- path.append(self._name)
- return '.'.join(path)
-
- def impl_getopt(self):
- return self._opt
-
-
-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 = []
- master = children[0]
- if not children:
- raise ValueError(_('children is mandatory in masterslaves "{}"').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 idx, child in enumerate(children):
- if child.impl_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()))
- # no empty property for save
- if idx != 0:
- properties = list(child._properties)
- properties.remove('empty')
- child._properties = tuple(properties)
- 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
- for child in children:
- child._master_slaves = weakref.ref(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,
- force_permissive=False):
-
- for slave in self.getslaves(opt):
- slave_path = slave.impl_getpath(values._getcontext())
- values.reset(slave,
- slave_path,
- setting_properties,
- validate=False,
- _commit=_commit,
- force_permissive=force_permissive)
-
- def pop(self,
- opt,
- path,
- values,
- index,
- setting_properties,
- force_permissive=False):
-
- for slave in self.getslaves(opt):
- slave_path = slave.impl_getpath(values._getcontext())
- slavelen = values._p_.get_max_length(slave_path)
- if not values.is_default_owner(slave,
- slave_path,
- setting_properties,
- validate_meta=False,
- index=index,
- force_permissive=force_permissive):
- #FIXME # just for raise if needed
- #multi = values.get_cached_value(slave,
- # validate=False,
- # validate_properties=False,
- # )
- #if isinstance(multi, Exception):
- # raise multi
- if slavelen > index:
- values._p_.resetvalue_index(slave_path,
- index)
- if slavelen > index + 1:
- for idx in xrange(index + 1, slavelen):
- values._p_.reduce_index(slave_path,
- idx)
-
-
- def getitem(self,
- values,
- opt,
- path,
- validate,
- force_permissive,
- trusted_cached_properties,
- validate_properties,
- 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,
- 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,
- self_properties,
- index,
- setting_properties,
- check_frozen):
- return values.get_cached_value(opt,
- path=path,
- validate=validate,
- force_permissive=force_permissive,
- self_properties=self_properties,
- index=index,
- setting_properties=setting_properties)
-
- 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)
- try:
- 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)
- except PropertiesOptionError as mastervalue:
- mastervalue.set_orig_opt(opt)
- raise mastervalue
- masterlen = len(mastervalue)
- #self._master_is_meta = values._is_meta(master, masterp, force_permissive=force_permissive)
- multi = list() # 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
- #FIXME shouldn't have index!!!
- if index is None:
- indexes = xrange(0, masterlen)
- else:
- indexes = [index]
- for idx in indexes:
- try:
- value = values.get_cached_value(opt,
- path,
- validate,
- force_permissive,
- trusted_cached_properties,
- validate_properties,
- index=idx,
- # not self_properties,
- # depends to index
- #self_properties=self_properties,
- setting_properties=setting_properties,
- from_masterslave=True,
- check_frozen=check_frozen)
- except PropertiesOptionError as perr:
- err = perr
- if index is None:
- multi.append(err)
- else:
- multi = err
- if index is None:
- multi.append(value)
- 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)
- 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,
- validate=True,
- 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(values._getcontext())
- value = self._getmaster(values,
- master,
- masterp,
- validate,
- force_permissive,
- validate,
- undefined,
- None,
- setting_properties,
- False)
- 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,
- path,
- obj,
- type_,
- resetted_opts):
- context = obj._getcontext()
- #FIXME pb avec dyn, devrait etre une option
- mopt = self.getmaster(None)
- mpath = mopt.impl_getpath(context)
- mopt.reset_cache(mopt,
- mpath,
- obj,
- type_,
- resetted_opts)
- for slave in self.getslaves(mopt):
- spath = slave.impl_getpath(context)
- slave.reset_cache(slave,
- spath,
- obj,
- type_,
- resetted_opts)
-
- def impl_getchild(self,
- name,
- setting_properties,
- context=undefined,
- dyn=True):
- return super(MasterSlaves, self).impl_getchild(name,
- setting_properties,
- 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,
- 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)
- self.validate_slave_length(masterlen, slavelen, slave.impl_getname(), master)
-
- 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:
- return ValueError(_('cannot reduce length of master "{}"'
- '').format(option.impl_get_display_name()))
diff --git a/tiramisu/option/syndynoptiondescription.py b/tiramisu/option/syndynoptiondescription.py
new file mode 100644
index 0000000..a9facfb
--- /dev/null
+++ b/tiramisu/option/syndynoptiondescription.py
@@ -0,0 +1,74 @@
+# -*- coding: utf-8 -*-
+# Copyright (C) 2017 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 ..i18n import _
+from ..setting import undefined
+
+
+class SynDynOptionDescription(object):
+ __slots__ = ('_opt',
+ '_name',
+ '_suffix')
+
+ def __init__(self,
+ opt,
+ name,
+ suffix):
+
+ self._opt = opt
+ self._name = name
+ self._suffix = suffix
+
+ def __getattr__(self, name):
+ return getattr(self._opt, name)
+
+ def impl_getchild(self,
+ name,
+ setting_properties,
+ context):
+ if name.endswith(self._suffix):
+ oname = name[:-len(self._suffix)]
+ child = self._children[1][self._children[0].index(oname)]
+ return self._impl_get_dynchild(child,
+ self._suffix)
+ raise AttributeError(_('unknown Option {0} '
+ 'in SynDynOptionDescription {1}'
+ '').format(name, self.impl_getname()))
+
+ def impl_getname(self):
+ return self._name
+
+ def impl_getchildren(self,
+ setting_properties,
+ dyn=True,
+ context=undefined):
+ children = []
+ for child in self._opt.impl_getchildren(setting_properties):
+ yield(self._opt._impl_get_dynchild(child,
+ self._suffix))
+
+ def impl_getpath(self, context):
+ path = self.impl_getopt().impl_getpath(context).split('.')
+ path[-1] += self._suffix
+ path.append(self._name)
+ return '.'.join(path)
+
+ def impl_getopt(self):
+ return self._opt