1 # -*- coding: utf-8 -*-
3 # Copyright (C) 2014 Team tiramisu (see AUTHORS for all contributors)
5 # This program is free software: you can redistribute it and/or modify it
6 # under the terms of the GNU Lesser General Public License as published by the
7 # Free Software Foundation, either version 3 of the License, or (at your
8 # option) any later version.
10 # This program is distributed in the hope that it will be useful, but WITHOUT
11 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
15 # You should have received a copy of the GNU Lesser General Public License
16 # along with this program. If not, see <http://www.gnu.org/licenses/>.
18 # The original `Config` design model is unproudly borrowed from
19 # the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
20 # the whole pypy projet is under MIT licence
21 # ____________________________________________________________
22 from tiramisu.i18n import _
23 from tiramisu.setting import log, undefined
24 from tiramisu.error import SlaveError, ConfigError
25 from .baseoption import DynSymLinkOption, SymLinkOption, Option
28 class MasterSlaves(object):
29 __slots__ = ('master', 'slaves')
31 def __init__(self, name, childs, validate=True):
32 #if master (same name has group) is set
33 #for collect all slaves
37 if isinstance(child, SymLinkOption): # pragma: optional cover
38 raise ValueError(_("master group {0} shall not have "
39 "a symlinkoption").format(name))
40 if not isinstance(child, Option): # pragma: optional cover
41 raise ValueError(_("master group {0} shall not have "
42 "a subgroup").format(name))
43 if not child.impl_is_multi(): # pragma: optional cover
44 raise ValueError(_("not allowed option {0} "
46 ": this option is not a multi"
47 "").format(child.impl_getname(), name))
48 if child.impl_getname() == name:
52 if self.master is None: # pragma: optional cover
53 raise ValueError(_('master group with wrong'
54 ' master name for {0}'
57 callback, callback_params = self.master.impl_get_callback()
58 if callback is not None and callback_params != {}: # pragma: optional cover
59 for key, callbacks in callback_params.items():
60 for callbk in callbacks:
61 if isinstance(callbk, tuple):
62 if callbk[0] in slaves:
63 raise ValueError(_("callback of master's option shall "
64 "not refered a slave's ones"))
65 #everything is ok, store references
66 self.slaves = tuple(slaves)
68 child._master_slaves = self
70 def is_master(self, opt):
71 return opt == self.master or (isinstance(opt, DynSymLinkOption) and
72 opt._opt == self.master)
74 def getmaster(self, opt):
75 if isinstance(opt, DynSymLinkOption):
76 suffix = opt.impl_getsuffix()
77 name = self.master.impl_getname() + suffix
78 base_path = opt._dyn.split('.')[0] + '.'
79 path = base_path + name
80 master = self.master._impl_to_dyn(name, path)
81 else: # pragma: no dynoptiondescription cover
85 def getslaves(self, opt):
86 if isinstance(opt, DynSymLinkOption):
87 for slave in self.slaves:
88 suffix = opt.impl_getsuffix()
89 name = slave.impl_getname() + suffix
90 base_path = opt._dyn.split('.')[0] + '.'
91 path = base_path + name
92 yield slave._impl_to_dyn(name, path)
93 else: # pragma: no dynoptiondescription cover
94 for slave in self.slaves:
97 def in_same_group(self, opt):
98 if isinstance(opt, DynSymLinkOption):
99 return opt._opt == self.master or opt._opt in self.slaves
100 else: # pragma: no dynoptiondescription cover
101 return opt == self.master or opt in self.slaves
103 def reset(self, opt, values):
104 #FIXME pas de opt ???
105 for slave in self.getslaves(opt):
108 def pop(self, opt, values, index):
109 #FIXME pas test de meta ...
110 for slave in self.getslaves(opt):
111 if not values.is_default_owner(slave, validate_properties=False,
112 validate_meta=False):
113 values._get_cached_item(slave, validate=False,
114 validate_properties=False
115 ).pop(index, force=True)
118 def getitem(self, values, opt, path, validate, force_permissive,
119 force_properties, validate_properties, slave_path=undefined,
120 slave_value=undefined):
121 if self.is_master(opt):
122 return self._getmaster(values, opt, path, validate,
123 force_permissive, force_properties,
124 validate_properties, slave_path,
127 return self._getslave(values, opt, path, validate,
128 force_permissive, force_properties,
131 def _getmaster(self, values, opt, path, validate, force_permissive,
132 force_properties, validate_properties, c_slave_path,
134 value = values._get_validated_value(opt, path, validate,
139 masterlen = len(value)
140 for slave in self.getslaves(opt):
142 slave_path = slave.impl_getpath(values._getcontext())
143 if c_slave_path == slave_path:
144 slave_value = c_slave_value
146 slave_value = values._get_validated_value(slave,
151 None) # not undefined
152 slavelen = len(slave_value)
153 self.validate_slave_length(masterlen, slavelen, slave.impl_getname(), opt)
154 except ConfigError: # pragma: optional cover
158 def _getslave(self, values, opt, path, validate, force_permissive,
159 force_properties, validate_properties):
160 value = values._get_validated_value(opt, path, validate,
164 None) # not undefined
165 return self.get_slave_value(values, opt, value, validate,
166 validate_properties, force_permissive)
168 def setitem(self, values, opt, value, path):
169 if self.is_master(opt):
170 masterlen = len(value)
171 for slave in self.getslaves(opt):
172 slave_path = slave.impl_getpath(values._getcontext())
173 slave_value = values._get_validated_value(slave,
178 None) # not undefined
179 slavelen = len(slave_value)
180 self.validate_slave_length(masterlen, slavelen, slave.impl_getname(), opt)
182 self.validate_slave_length(self.get_length(values, opt,
183 slave_path=path), len(value),
184 opt.impl_getname(), opt, setitem=True)
186 def get_length(self, values, opt, validate=True, slave_path=undefined,
187 slave_value=undefined, force_permissive=False):
188 """get master len with slave option"""
189 masterp = self.getmaster(opt).impl_getpath(values._getcontext())
190 if slave_value is undefined:
191 slave_path = undefined
192 return len(self.getitem(values, self.getmaster(opt), masterp, validate,
193 force_permissive, None, True, slave_path,
196 def validate_slave_length(self, masterlen, valuelen, name, opt, setitem=False):
197 if valuelen > masterlen or (valuelen < masterlen and setitem): # pragma: optional cover
198 log.debug('validate_slave_length: masterlen: {0}, valuelen: {1}, '
199 'setitem: {2}'.format(masterlen, valuelen, setitem))
200 raise SlaveError(_("invalid len for the slave: {0}"
201 " which has {1} as master").format(
202 name, self.getmaster(opt).impl_getname()))
204 def get_slave_value(self, values, opt, value, validate=True,
205 validate_properties=True, force_permissive=False):
207 if master has length 0:
209 if master has length bigger than 0:
213 list same length as master: return list
214 list is smaller than master: return list + None
215 list is greater than master: raise SlaveError
216 if has default value:
217 list same length as master: return list
218 list is smaller than master: return list + None
219 list is greater than master: raise SlaveError
220 if has default_multi value:
221 return default_multi * master's length
223 list same length as master: return list
224 list is smaller than master: return list + None
225 list is greater than master: raise SlaveError
227 #if slave, had values until master's one
228 path = opt.impl_getpath(values._getcontext())
229 masterlen = self.get_length(values, opt, validate, path, value,
231 valuelen = len(value)
233 self.validate_slave_length(masterlen, valuelen, opt.impl_getname(), opt)
234 if valuelen < masterlen:
235 for num in range(0, masterlen - valuelen):
236 index = valuelen + num
237 value.append(values._get_validated_value(opt, path, True,