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
24 from tiramisu.error import SlaveError, ConfigError
25 from .baseoption import SymLinkOption, Option
28 class MasterSlaves(object):
29 __slots__ = ('master', 'slaves')
31 def __init__(self, name, childs):
32 #if master (same name has group) is set
33 #for collect all slaves
37 if isinstance(child, SymLinkOption):
38 raise ValueError(_("master group {0} shall not have "
39 "a symlinkoption").format(name))
40 if not isinstance(child, Option):
41 raise ValueError(_("master group {0} shall not have "
42 "a subgroup").format(name))
43 if not child.impl_is_multi():
44 raise ValueError(_("not allowed option {0} "
46 ": this option is not a multi"
47 "").format(child._name, name))
48 if child._name == name:
52 if self.master is None:
53 raise ValueError(_('master group with wrong'
54 ' master name for {0}'
56 callback, callback_params = self.master.impl_get_callback()
57 if callback is not None and callback_params is not None:
58 for key, callbacks in callback_params.items():
59 for callbk in callbacks:
60 if isinstance(callbk, tuple):
61 if callbk[0] in slaves:
62 raise ValueError(_("callback of master's option shall "
63 "not refered a slave's ones"))
64 #everything is ok, store references
65 self.slaves = tuple(slaves)
67 child._master_slaves = self
69 def is_master(self, opt):
70 return opt == self.master
72 def in_same_group(self, opt):
73 return opt == self.master or opt in self.slaves
75 def reset(self, values):
76 for slave in self.slaves:
79 def pop(self, values, index):
80 #FIXME pas test de meta ...
81 for slave in self.slaves:
82 if not values.is_default_owner(slave, validate_properties=False,
84 values._get_cached_item(slave, validate=False,
85 validate_properties=False
86 ).pop(index, force=True)
89 def getitem(self, values, opt, path, validate, force_permissive,
90 force_properties, validate_properties):
91 if opt == self.master:
92 value = values._get_validated_value(opt, path, validate,
97 masterlen = len(value)
98 for slave in self.slaves:
100 slave_path = values._get_opt_path(slave)
101 slave_value = values._get_validated_value(slave,
106 None) # not undefined
107 slavelen = len(slave_value)
108 self.validate_slave_length(masterlen, slavelen, slave._name)
113 value = values._get_validated_value(opt, path, validate,
117 None) # not undefined
118 return self.get_slave_value(values, opt, value, validate, validate_properties)
120 def setitem(self, values, opt, value, path):
121 if opt == self.master:
122 masterlen = len(value)
123 for slave in self.slaves:
124 slave_path = values._get_opt_path(slave)
125 slave_value = values._get_validated_value(slave,
130 None) # not undefined
131 slavelen = len(slave_value)
132 self.validate_slave_length(masterlen, slavelen, slave._name)
134 self.validate_slave_length(self.get_length(values), len(value),
135 opt._name, setitem=True)
137 def get_length(self, values, validate=True):
138 masterp = values._get_opt_path(self.master)
139 return len(self.getitem(values, self.master, masterp, validate, False,
142 def validate_slave_length(self, masterlen, valuelen, name, setitem=False):
143 if valuelen > masterlen or (valuelen < masterlen and setitem):
144 log.debug('validate_slave_length: masterlen: {0}, valuelen: {1}, '
145 'setitem: {2}'.format(masterlen, valuelen, setitem))
146 raise SlaveError(_("invalid len for the slave: {0}"
147 " which has {1} as master").format(
148 name, self.master._name))
150 def get_slave_value(self, values, opt, value, validate=True,
151 validate_properties=True):
153 if master has length 0:
155 if master has length bigger than 0:
159 list same length as master: return list
160 list is smaller than master: return list + None
161 list is greater than master: raise SlaveError
162 if has default value:
163 list same length as master: return list
164 list is smaller than master: return list + None
165 list is greater than master: raise SlaveError
166 if has default_multi value:
167 return default_multi * master's length
169 list same length as master: return list
170 list is smaller than master: return list + None
171 list is greater than master: raise SlaveError
173 #if slave, had values until master's one
174 masterlen = self.get_length(values, validate)
175 valuelen = len(value)
177 self.validate_slave_length(masterlen, valuelen, opt._name)
178 path = values._get_opt_path(opt)
179 if valuelen < masterlen:
180 for num in range(0, masterlen - valuelen):
181 index = valuelen + num
182 value.append(values._get_validated_value(opt, path, True,