## 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