Revision 9c709b31
b/lib/utils/algo.py | ||
---|---|---|
24 | 24 |
|
25 | 25 |
import re |
26 | 26 |
import time |
27 |
import itertools |
|
27 | 28 |
|
28 | 29 |
from ganeti import compat |
29 | 30 |
from ganeti.utils import text |
... | ... | |
193 | 194 |
return dict(zip(keys, seq)) |
194 | 195 |
|
195 | 196 |
|
197 |
def _MakeFlatToDict(data): |
|
198 |
"""Helper function for C{FlatToDict}. |
|
199 |
|
|
200 |
This function is recursively called |
|
201 |
|
|
202 |
@param data: The input data as described in C{FlatToDict}, already splitted |
|
203 |
@returns: The so far converted dict |
|
204 |
|
|
205 |
""" |
|
206 |
if not compat.fst(compat.fst(data)): |
|
207 |
assert len(data) == 1, \ |
|
208 |
"not bottom most element, found %d elements, expected 1" % len(data) |
|
209 |
return compat.snd(compat.fst(data)) |
|
210 |
|
|
211 |
keyfn = lambda e: compat.fst(e).pop(0) |
|
212 |
return dict([(k, _MakeFlatToDict(list(g))) |
|
213 |
for (k, g) in itertools.groupby(sorted(data), keyfn)]) |
|
214 |
|
|
215 |
|
|
216 |
def FlatToDict(data, field_sep="/"): |
|
217 |
"""Converts a flat structure to a fully fledged dict. |
|
218 |
|
|
219 |
It accept a list of tuples in the form:: |
|
220 |
|
|
221 |
[ |
|
222 |
("foo/bar", {"key1": "data1", "key2": "data2"}), |
|
223 |
("foo/baz", {"key3" :"data3" }), |
|
224 |
] |
|
225 |
|
|
226 |
where the first element is the key separated by C{field_sep}. |
|
227 |
|
|
228 |
This would then return:: |
|
229 |
|
|
230 |
{ |
|
231 |
"foo": { |
|
232 |
"bar": {"key1": "data1", "key2": "data2"}, |
|
233 |
"baz": {"key3" :"data3" }, |
|
234 |
}, |
|
235 |
} |
|
236 |
|
|
237 |
@type data: list of tuple |
|
238 |
@param data: Input list to convert |
|
239 |
@type field_sep: str |
|
240 |
@param field_sep: The separator for the first field of the tuple |
|
241 |
@returns: A dict based on the input list |
|
242 |
|
|
243 |
""" |
|
244 |
return _MakeFlatToDict([(keys.split(field_sep), value) |
|
245 |
for (keys, value) in data]) |
|
246 |
|
|
247 |
|
|
196 | 248 |
class RunningTimeout(object): |
197 | 249 |
"""Class to calculate remaining timeout when doing several operations. |
198 | 250 |
|
b/test/ganeti.utils.algo_unittest.py | ||
---|---|---|
339 | 339 |
[(i, ) for i in range(200)] + [(10, )]) |
340 | 340 |
|
341 | 341 |
|
342 |
class TestFlatToDict(unittest.TestCase): |
|
343 |
def testNormal(self): |
|
344 |
data = [ |
|
345 |
("lv/xenvg", {"foo": "bar", "bar": "baz"}), |
|
346 |
("lv/xenfoo", {"foo": "bar", "baz": "blubb"}), |
|
347 |
("san/foo", {"ip": "127.0.0.1", "port": 1337}), |
|
348 |
("san/blubb/blibb", 54), |
|
349 |
] |
|
350 |
reference = { |
|
351 |
"lv": { |
|
352 |
"xenvg": {"foo": "bar", "bar": "baz"}, |
|
353 |
"xenfoo": {"foo": "bar", "baz": "blubb"}, |
|
354 |
}, |
|
355 |
"san": { |
|
356 |
"foo": {"ip": "127.0.0.1", "port": 1337}, |
|
357 |
"blubb": {"blibb": 54}, |
|
358 |
}, |
|
359 |
} |
|
360 |
self.assertEqual(algo.FlatToDict(data), reference) |
|
361 |
|
|
362 |
def testUnlikeDepth(self): |
|
363 |
data = [ |
|
364 |
("san/foo", {"ip": "127.0.0.1", "port": 1337}), |
|
365 |
("san/foo/blubb", 23), # Another foo entry under san |
|
366 |
("san/blubb/blibb", 54), |
|
367 |
] |
|
368 |
self.assertRaises(AssertionError, algo.FlatToDict, data) |
|
369 |
|
|
370 |
|
|
342 | 371 |
if __name__ == "__main__": |
343 | 372 |
testutils.GanetiTestProgram() |
Also available in: Unified diff