Commit 9c709b31 authored by René Nussbaumer's avatar René Nussbaumer
Browse files

algo: Make a dict from an flat list

This is in preparation to take deeper dict constructs from the command
line. You can feed the optionslist directly constructed of type
"identkeyval" to it and it returns a fully deflated dict.

This is mainly needed for the resource model changes where we have to
modify the disk_state which is a 3 level dict:

Signed-off-by: default avatarRené Nussbaumer <>
Reviewed-by: default avatarMichael Hanselmann <>
parent ee2b99e3
......@@ -24,6 +24,7 @@
import re
import time
import itertools
from ganeti import compat
from ganeti.utils import text
......@@ -193,6 +194,57 @@ def SequenceToDict(seq, key=compat.fst):
return dict(zip(keys, seq))
def _MakeFlatToDict(data):
"""Helper function for C{FlatToDict}.
This function is recursively called
@param data: The input data as described in C{FlatToDict}, already splitted
@returns: The so far converted dict
if not compat.fst(compat.fst(data)):
assert len(data) == 1, \
"not bottom most element, found %d elements, expected 1" % len(data)
return compat.snd(compat.fst(data))
keyfn = lambda e: compat.fst(e).pop(0)
return dict([(k, _MakeFlatToDict(list(g)))
for (k, g) in itertools.groupby(sorted(data), keyfn)])
def FlatToDict(data, field_sep="/"):
"""Converts a flat structure to a fully fledged dict.
It accept a list of tuples in the form::
("foo/bar", {"key1": "data1", "key2": "data2"}),
("foo/baz", {"key3" :"data3" }),
where the first element is the key separated by C{field_sep}.
This would then return::
"foo": {
"bar": {"key1": "data1", "key2": "data2"},
"baz": {"key3" :"data3" },
@type data: list of tuple
@param data: Input list to convert
@type field_sep: str
@param field_sep: The separator for the first field of the tuple
@returns: A dict based on the input list
return _MakeFlatToDict([(keys.split(field_sep), value)
for (keys, value) in data])
class RunningTimeout(object):
"""Class to calculate remaining timeout when doing several operations.
......@@ -339,5 +339,34 @@ class TestSequenceToDict(unittest.TestCase):
[(i, ) for i in range(200)] + [(10, )])
class TestFlatToDict(unittest.TestCase):
def testNormal(self):
data = [
("lv/xenvg", {"foo": "bar", "bar": "baz"}),
("lv/xenfoo", {"foo": "bar", "baz": "blubb"}),
("san/foo", {"ip": "", "port": 1337}),
("san/blubb/blibb", 54),
reference = {
"lv": {
"xenvg": {"foo": "bar", "bar": "baz"},
"xenfoo": {"foo": "bar", "baz": "blubb"},
"san": {
"foo": {"ip": "", "port": 1337},
"blubb": {"blibb": 54},
self.assertEqual(algo.FlatToDict(data), reference)
def testUnlikeDepth(self):
data = [
("san/foo", {"ip": "", "port": 1337}),
("san/foo/blubb", 23), # Another foo entry under san
("san/blubb/blibb", 54),
self.assertRaises(AssertionError, algo.FlatToDict, data)
if __name__ == "__main__":
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment