947c69745b9cf8002e3475d6686af68a01282fcd
[cascardo/ipsilon.git] / ipsilon / util / config.py
1 # Copyright (C) 2014  Ipsilon project Contributors, for licensee see COPYING
2
3 from ipsilon.util.log import Log
4 import json
5
6
7 class Config(Log):
8
9     def __init__(self, name, *args):
10         self.name = name
11         self._list = list()
12         self._dict = dict()
13         for item in args:
14             if not isinstance(item, Option):
15                 raise ValueError('Invalid option type for %s' % repr(item))
16             self._list.append(item.name)
17             self._dict[item.name] = item
18         self.debug('Config(%s) %s' % (self.name, self._dict))
19
20     def __repr__(self):
21         return '%s: %s' % (self.__class__, ', '.join(self._list))
22
23     def __str__(self):
24         return str(self._list)
25
26     def __len__(self):
27         return len(self._list)
28
29     def __getitem__(self, key):
30         return self._dict[key]
31
32     def __setitem__(self, key, value):
33         if not isinstance(value, Option):
34             raise ValueError('Invalid type for %s' % value)
35         if key != value.name:
36             raise NameError('Name mismatch, key=%s but value.name=%s' % (
37                 key, value.name))
38         if key not in self._list:
39             self._list.append(key)
40         self._dict[key] = value
41
42     def __delitem__(self, key):
43         self._list.remove(key)
44         del self._dict[key]
45
46     def __iter__(self):
47         i = 0
48         while i < len(self._list):
49             yield self._list[i]
50             i += 1
51
52     def __reversed__(self):
53         i = len(self._list)
54         while i > 0:
55             yield self._list[i - 1]
56             i -= 1
57
58     def __contains__(self, item):
59         return (item in self._dict)
60
61     def iteritems(self):
62         i = 0
63         while i < len(self._list):
64             yield (self._list[i], self._dict[self._list[i]])
65             i += 1
66
67     def items(self):
68         return [(k, self._dict[k]) for k in self._list]
69
70
71 class Option(Log):
72
73     def __init__(self, name, description):
74         self.name = name
75         self.description = description
76         self._default_value = None
77         self._assigned_value = None
78
79     def __repr__(self):
80         return "%s: %s {%s}, value = %s [def: %s]" % (self.__class__,
81                                                       self.name,
82                                                       self.description,
83                                                       self._assigned_value,
84                                                       self._default_value)
85
86     def __str__(self):
87         return '%s=%s' % (self.name, self.get_value())
88
89     def get_value(self, default=True):
90         if self._assigned_value is not None:
91             return self._assigned_value
92         elif default is True:
93             return self._default_value
94         else:
95             return None
96
97     def set_value(self, value):
98         self._assigned_value = value
99
100     def export_value(self):
101         raise NotImplementedError
102
103     def import_value(self, value):
104         raise NotImplementedError
105
106     def _str_export_value(self):
107         if self._assigned_value:
108             return str(self._assigned_value)
109         return None
110
111     def _str_import_value(self, value):
112         if type(value) is not str:
113             raise ValueError('Value must be string')
114         self._assigned_value = value
115
116
117 class String(Option):
118
119     def __init__(self, name, description, default_value=None):
120         super(String, self).__init__(name, description)
121         self._default_value = str(default_value)
122
123     def set_value(self, value):
124         self._assigned_value = str(value)
125
126     def export_value(self):
127         return self._str_export_value()
128
129     def import_value(self, value):
130         self._str_import_value(value)
131
132
133 class Template(Option):
134
135     def __init__(self, name, description, default_template=None):
136         super(Template, self).__init__(name, description)
137         self._default_value = str(default_template)
138
139     def set_value(self, value):
140         self._assigned_value = str(value)
141
142     def templatize(self, args):
143         if not args:
144             raise ValueError('Templatized called w/o arguments')
145
146         return self.get_value() % args
147
148     def export_value(self):
149         return self._str_export_value()
150
151     def import_value(self, value):
152         self._str_import_value(value)
153
154
155 class List(Option):
156
157     def __init__(self, name, description, default_list=None):
158         super(List, self).__init__(name, description)
159         if default_list:
160             self._default_value = default_list
161         else:
162             self._default_value = []
163
164     def set_value(self, value):
165         self._assigned_value = list(value)
166
167     def export_value(self):
168         if self._assigned_value:
169             return ','.join(self._assigned_value)
170         return None
171
172     def import_value(self, value):
173         if type(value) is not str:
174             raise ValueError('Value (type: %s) must be string' % type(value))
175         self._assigned_value = [x.strip() for x in value.split(',')]
176
177
178 class ComplexList(List):
179
180     def _check_value(self, value):
181         if type(value) is not list:
182             raise ValueError('The value type must be a list, not "%s"' %
183                              type(value))
184
185     def set_value(self, value):
186         self._check_value(value)
187         self._assigned_value = value
188
189     def export_value(self):
190         if self._assigned_value:
191             return json.dumps(self._assigned_value)
192         return None
193
194     def import_value(self, value):
195         if type(value) is not str:
196             raise ValueError('The value type must be a string, not "%s"' %
197                              type(value))
198         jsonval = json.loads(value)
199         self.set_value(jsonval)
200
201
202 class MappingList(ComplexList):
203
204     def _check_value(self, value):
205         if type(value) is not list:
206             raise ValueError('The value type must be a list, not "%s"' %
207                              type(value))
208         for v in value:
209             if type(v) is not list:
210                 raise ValueError('Each element must be a list, not "%s"' %
211                                  type(v))
212             if len(v) != 2:
213                 raise ValueError('Each element must contain 2 values,'
214                                  ' not %d' % len(v))
215
216     def import_value(self, value):
217         if type(value) is not str:
218             raise ValueError('Value (type: %s) must be string' % type(value))
219         jsonval = json.loads(value)
220         self.set_value(jsonval)
221
222
223 class Choice(Option):
224
225     def __init__(self, name, description, allowed=None, default=None):
226         super(Choice, self).__init__(name, description)
227         if allowed:
228             self._allowed_values = list(allowed)
229         else:
230             self._allowed_values = list()
231         self._default_value = list()
232         if default is None:
233             default = []
234         for name in default:
235             if name not in self._allowed_values:
236                 raise ValueError(
237                     'item [%s] is not in allowed [%s]' % (name, allowed))
238             self._default_value.append(name)
239
240     def __repr__(self):
241         return "%s: %s {%s}, values = %s d:%s ok:%s" % (self.__class__,
242                                                         self.name,
243                                                         self.description,
244                                                         self._assigned_value,
245                                                         self._default_value,
246                                                         self._allowed_values)
247
248     def __str__(self):
249         return '%s=%s' % (self.name, self.get_value())
250
251     def set_value(self, value):
252         if type(value) is not list:
253             value = [value]
254         self._assigned_value = list()
255         for val in value:
256             if val not in self._allowed_values:
257                 raise ValueError(
258                     'Value "%s" not allowed [%s]' % (val,
259                                                      self._allowed_values))
260             self._assigned_value.append(val)
261
262         if not self._assigned_value:
263             self._assigned_value = None
264
265     def unset_value(self, value):
266         if type(value) is str:
267             value = [value]
268         unset = list()
269         for val in value:
270             unset.append((val, False))
271         self.set_value(unset)
272
273     def get_allowed(self):
274         return self._allowed_values
275
276     def export_value(self):
277         enabled = self.get_value()
278         return ', '.join(enabled)
279
280     def import_value(self, value):
281         enabled = [x.strip() for x in value.split(',')]
282         if enabled:
283             if self._assigned_value is None:
284                 self._assigned_value = list()
285         for val in enabled:
286             if val not in self._allowed_values:
287                 # We silently ignore invalid options on import for now
288                 continue
289             self._assigned_value.append(val)
290
291
292 class Pick(Option):
293
294     def __init__(self, name, description, allowed, default_value):
295         super(Pick, self).__init__(name, description)
296         self._allowed_values = list(allowed)
297         if default_value not in self._allowed_values:
298             raise ValueError('The default value is not in the allowed list')
299         self._default_value = default_value
300
301     def set_value(self, value):
302         if value not in self._allowed_values:
303             raise ValueError(
304                 'Value "%s" not allowed [%s]' % (value, self._allowed_values))
305         self._assigned_value = value
306
307     def get_allowed(self):
308         return self._allowed_values
309
310     def export_value(self):
311         return self._str_export_value()
312
313     def import_value(self, value):
314         self._str_import_value(value)
315
316
317 class Condition(Pick):
318
319     def __init__(self, name, description, default_value=False):
320         super(Condition, self).__init__(name, description,
321                                         [True, False], default_value)
322
323     def import_value(self, value):
324         self._assigned_value = value == 'True'