1 # -*- coding: utf-8 -*-
3 # Copyright (C) 2014-2017 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 # ____________________________________________________________
23 from ..setting import log, undefined, debug
24 from ..error import SlaveError, PropertiesOptionError
27 class MasterSlaves(object):
28 __slots__ = ('master', 'slaves')
30 def __init__(self, name, childs=None, validate=True, add=True):
31 #if master (same name has group) is set
32 #for collect all slaves
34 if childs[0].impl_getname() == name:
37 raise ValueError(_('master group with wrong'
38 ' master name for {0}'
40 for child in childs[1:]:
41 if child.impl_getdefault() != []:
42 raise ValueError(_("not allowed default value for option {0} "
43 "in master/slave object {1}").format(child.impl_getname(),
47 callback, callback_params = master.impl_get_callback()
48 if callback is not None and callback_params != {}:
49 for callbacks in callback_params.values():
50 for callbk in callbacks:
51 if isinstance(callbk, tuple):
52 if callbk[0] in slaves:
53 raise ValueError(_("callback of master's option shall "
54 "not refered a slave's ones"))
55 #everything is ok, store references
57 self.slaves = tuple(slaves)
60 child._master_slaves = self
62 def is_master(self, opt):
63 master = self.master.impl_getname()
64 return opt.impl_getname() == master or (opt.impl_is_dynsymlinkoption() and
65 opt._opt.impl_getname() == master)
67 def getmaster(self, opt):
69 if opt.impl_is_dynsymlinkoption():
70 suffix = opt.impl_getsuffix()
71 name = master.impl_getname() + suffix
72 base_path = opt._dyn.split('.')[0] + '.'
73 path = base_path + name
74 master = master._impl_to_dyn(name, path)
77 def getslaves(self, opt):
78 if opt.impl_is_dynsymlinkoption():
79 for slave in self.slaves:
80 suffix = opt.impl_getsuffix()
81 name = slave.impl_getname() + suffix
82 base_path = opt._dyn.split('.')[0] + '.'
83 path = base_path + name
84 yield slave._impl_to_dyn(name, path)
86 for slave in self.slaves:
89 def in_same_group(self, opt):
90 if opt.impl_is_dynsymlinkoption():
91 return opt._opt == self.master or opt._opt in self.slaves
93 return opt == self.master or opt in self.slaves
95 def reset(self, opt, values, setting_properties, _commit=True):
96 for slave in self.getslaves(opt):
97 values.reset(slave, validate=False, _setting_properties=setting_properties,
100 def pop(self, opt, values, index):
101 for slave in self.getslaves(opt):
102 if not values.is_default_owner(slave, validate_properties=False,
103 validate_meta=False, index=index):
104 multi = values._get_cached_value(slave, validate=False,
105 validate_properties=False,
107 if isinstance(multi, Exception):
109 multi.pop(index, force=True)
111 def getitem(self, values, opt, path, validate, force_permissive,
112 trusted_cached_properties, validate_properties, session,
113 slave_path=undefined, slave_value=undefined,
114 setting_properties=undefined, self_properties=undefined, index=None,
116 if self.is_master(opt):
117 return self._getmaster(values, opt, path, validate,
119 validate_properties, slave_path,
120 slave_value, self_properties, index,
121 setting_properties, session, check_frozen)
123 return self._getslave(values, opt, path, validate,
124 force_permissive, trusted_cached_properties,
125 validate_properties, setting_properties,
126 self_properties, index,
127 session, check_frozen)
129 def _getmaster(self, values, opt, path, validate, force_permissive,
130 validate_properties, c_slave_path,
131 c_slave_value, self_properties, index,
132 setting_properties, session, check_frozen):
133 value = values._get_cached_value(opt, path=path, validate=validate,
134 force_permissive=force_permissive,
135 validate_properties=validate_properties,
136 self_properties=self_properties,
137 from_masterslave=True, index=index,
138 setting_properties=setting_properties,
139 check_frozen=check_frozen)
140 if isinstance(value, Exception):
142 if index is None and validate is True:
143 masterlen = len(value)
144 for slave in self.getslaves(opt):
145 slave_path = slave.impl_getpath(values._getcontext())
146 slavelen = values._p_.get_max_length(slave_path, session)
147 self.validate_slave_length(masterlen, slavelen, slave.impl_getname(), opt)
150 def _getslave(self, values, opt, path, validate, force_permissive,
151 trusted_cached_properties, validate_properties, setting_properties,
152 self_properties, index, session, check_frozen):
154 if master has length 0:
156 if master has length bigger than 0:
160 list same length as master: return list
161 list is smaller than master: return list + None
162 list is greater than master: raise SlaveError
163 if has default value:
164 list same length as master: return list
165 list is smaller than master: return list + None
166 list is greater than master: raise SlaveError
167 if has default_multi value:
168 return default_multi * master's length
170 list same length as master: return list
171 list is smaller than master: return list + None
172 list is greater than master: raise SlaveError
174 master = self.getmaster(opt)
175 context = values._getcontext()
176 masterp = master.impl_getpath(context)
177 masterlen = self.get_length(values, opt, session, validate, undefined,
178 undefined, force_permissive,
179 master=master, setting_properties=setting_properties)
180 if isinstance(masterlen, Exception):
181 if isinstance(masterlen, PropertiesOptionError):
182 masterlen.set_orig_opt(opt)
184 master_is_meta = values._is_meta(master, masterp, session)
185 multi = values._get_multi(opt, path)
186 #if masterlen is [], test properties (has no value, don't get any value)
188 if validate_properties:
189 props = context.cfgimpl_get_settings().validate_properties(opt, False,
193 force_permissive=force_permissive,
194 setting_properties=setting_properties)
199 indexes = range(0, masterlen)
203 value = values._get_cached_value(opt, path, validate,
205 trusted_cached_properties,
207 with_meta=master_is_meta,
209 # not self_properties,
211 #self_properties=self_properties,
212 setting_properties=setting_properties,
214 from_masterslave=True,
215 check_frozen=check_frozen)
216 if isinstance(value, Exception):
217 if isinstance(value, PropertiesOptionError):
220 multi.append_properties_error(value)
226 multi.append(value, setitem=False, force=True, validate=False,
227 force_permissive=force_permissive)
232 def validate(self, values, opt, index, path, session, setitem):
233 if self.is_master(opt):
234 #for regen slave path
235 base_path = '.'.join(path.split('.')[:-1]) + '.'
236 for slave in self.getslaves(opt):
237 slave_path = base_path + slave.impl_getname()
238 slavelen = values._p_.get_max_length(slave_path, session)
239 self.validate_slave_length(index, slavelen, slave.impl_getname(), opt)
241 val_len = self.get_length(values, opt, session, slave_path=path)
242 if isinstance(val_len, Exception):
244 self.validate_slave_length(val_len, index,
245 opt.impl_getname(), opt, setitem=setitem)
247 def get_length(self, values, opt, session, validate=True, slave_path=undefined,
248 slave_value=undefined, force_permissive=False, master=None,
249 masterp=None, setting_properties=undefined):
250 """get master len with slave option"""
252 master = self.getmaster(opt)
254 masterp = master.impl_getpath(values._getcontext())
255 if slave_value is undefined:
256 slave_path = undefined
257 value = self.getitem(values, master, masterp, validate,
258 force_permissive, None, True, session, slave_path=slave_path,
259 slave_value=slave_value, setting_properties=setting_properties)
260 if isinstance(value, Exception):
264 def validate_slave_length(self, masterlen, valuelen, name, opt, setitem=False):
265 if valuelen > masterlen or (valuelen < masterlen and setitem):
266 if debug: # pragma: no cover
267 log.debug('validate_slave_length: masterlen: {0}, valuelen: {1}, '
268 'setitem: {2}'.format(masterlen, valuelen, setitem))
269 raise SlaveError(_("invalid len for the slave: {0}"
270 " which has {1} as master").format(
271 name, self.getmaster(opt).impl_getname()))
273 def reset_cache(self, opt, values, type_):
274 for slave in self.getslaves(opt):
275 slave_path = slave.impl_getpath(values._getcontext())
276 values._p_.delcache(slave_path)