Revision 473ab806

b/lib/objects.py
263 263
    obj = cls(**val_str) # pylint: disable=W0142
264 264
    return obj
265 265

  
266
  @staticmethod
267
  def _ContainerToDicts(container):
268
    """Convert the elements of a container to standard python types.
269

  
270
    This method converts a container with elements derived from
271
    ConfigData to standard python types. If the container is a dict,
272
    we don't touch the keys, only the values.
273

  
274
    """
275
    if isinstance(container, dict):
276
      ret = dict([(k, v.ToDict()) for k, v in container.iteritems()])
277
    elif isinstance(container, (list, tuple, set, frozenset)):
278
      ret = [elem.ToDict() for elem in container]
279
    else:
280
      raise TypeError("Invalid type %s passed to _ContainerToDicts" %
281
                      type(container))
282
    return ret
283

  
284
  @staticmethod
285
  def _ContainerFromDicts(source, c_type, e_type):
286
    """Convert a container from standard python types.
287

  
288
    This method converts a container with standard python types to
289
    ConfigData objects. If the container is a dict, we don't touch the
290
    keys, only the values.
291

  
292
    """
293
    if not isinstance(c_type, type):
294
      raise TypeError("Container type %s passed to _ContainerFromDicts is"
295
                      " not a type" % type(c_type))
296
    if source is None:
297
      source = c_type()
298
    if c_type is dict:
299
      ret = dict([(k, e_type.FromDict(v)) for k, v in source.iteritems()])
300
    elif c_type in (list, tuple, set, frozenset):
301
      ret = c_type([e_type.FromDict(elem) for elem in source])
302
    else:
303
      raise TypeError("Invalid container type %s passed to"
304
                      " _ContainerFromDicts" % c_type)
305
    return ret
306

  
307 266
  def Copy(self):
308 267
    """Makes a deep copy of the current object and its children.
309 268

  
......
446 405
    mydict = super(ConfigData, self).ToDict()
447 406
    mydict["cluster"] = mydict["cluster"].ToDict()
448 407
    for key in "nodes", "instances", "nodegroups", "networks":
449
      mydict[key] = self._ContainerToDicts(mydict[key])
408
      mydict[key] = objectutils.ContainerToDicts(mydict[key])
450 409

  
451 410
    return mydict
452 411

  
......
457 416
    """
458 417
    obj = super(ConfigData, cls).FromDict(val)
459 418
    obj.cluster = Cluster.FromDict(obj.cluster)
460
    obj.nodes = cls._ContainerFromDicts(obj.nodes, dict, Node)
461
    obj.instances = cls._ContainerFromDicts(obj.instances, dict, Instance)
462
    obj.nodegroups = cls._ContainerFromDicts(obj.nodegroups, dict, NodeGroup)
463
    obj.networks = cls._ContainerFromDicts(obj.networks, dict, Network)
419
    obj.nodes = objectutils.ContainerFromDicts(obj.nodes, dict, Node)
420
    obj.instances = \
421
      objectutils.ContainerFromDicts(obj.instances, dict, Instance)
422
    obj.nodegroups = \
423
      objectutils.ContainerFromDicts(obj.nodegroups, dict, NodeGroup)
424
    obj.networks = objectutils.ContainerFromDicts(obj.networks, dict, Network)
464 425
    return obj
465 426

  
466 427
  def HasAnyDiskOfType(self, dev_type):
......
768 729
    for attr in ("children",):
769 730
      alist = bo.get(attr, None)
770 731
      if alist:
771
        bo[attr] = self._ContainerToDicts(alist)
732
        bo[attr] = objectutils.ContainerToDicts(alist)
772 733
    return bo
773 734

  
774 735
  @classmethod
......
778 739
    """
779 740
    obj = super(Disk, cls).FromDict(val)
780 741
    if obj.children:
781
      obj.children = cls._ContainerFromDicts(obj.children, list, Disk)
742
      obj.children = objectutils.ContainerFromDicts(obj.children, list, Disk)
782 743
    if obj.logical_id and isinstance(obj.logical_id, list):
783 744
      obj.logical_id = tuple(obj.logical_id)
784 745
    if obj.physical_id and isinstance(obj.physical_id, list):
......
1136 1097
    for attr in "nics", "disks":
1137 1098
      alist = bo.get(attr, None)
1138 1099
      if alist:
1139
        nlist = self._ContainerToDicts(alist)
1100
        nlist = objectutils.ContainerToDicts(alist)
1140 1101
      else:
1141 1102
        nlist = []
1142 1103
      bo[attr] = nlist
......
1155 1116
    if "admin_up" in val:
1156 1117
      del val["admin_up"]
1157 1118
    obj = super(Instance, cls).FromDict(val)
1158
    obj.nics = cls._ContainerFromDicts(obj.nics, list, NIC)
1159
    obj.disks = cls._ContainerFromDicts(obj.disks, list, Disk)
1119
    obj.nics = objectutils.ContainerFromDicts(obj.nics, list, NIC)
1120
    obj.disks = objectutils.ContainerFromDicts(obj.disks, list, Disk)
1160 1121
    return obj
1161 1122

  
1162 1123
  def UpgradeConfig(self):
......
1344 1305

  
1345 1306
    hv_state = data.get("hv_state", None)
1346 1307
    if hv_state is not None:
1347
      data["hv_state"] = self._ContainerToDicts(hv_state)
1308
      data["hv_state"] = objectutils.ContainerToDicts(hv_state)
1348 1309

  
1349 1310
    disk_state = data.get("disk_state", None)
1350 1311
    if disk_state is not None:
1351 1312
      data["disk_state"] = \
1352
        dict((key, self._ContainerToDicts(value))
1313
        dict((key, objectutils.ContainerToDicts(value))
1353 1314
             for (key, value) in disk_state.items())
1354 1315

  
1355 1316
    return data
......
1362 1323
    obj = super(Node, cls).FromDict(val)
1363 1324

  
1364 1325
    if obj.hv_state is not None:
1365
      obj.hv_state = cls._ContainerFromDicts(obj.hv_state, dict, NodeHvState)
1326
      obj.hv_state = \
1327
        objectutils.ContainerFromDicts(obj.hv_state, dict, NodeHvState)
1366 1328

  
1367 1329
    if obj.disk_state is not None:
1368 1330
      obj.disk_state = \
1369
        dict((key, cls._ContainerFromDicts(value, dict, NodeDiskState))
1331
        dict((key, objectutils.ContainerFromDicts(value, dict, NodeDiskState))
1370 1332
             for (key, value) in obj.disk_state.items())
1371 1333

  
1372 1334
    return obj
......
1935 1897

  
1936 1898
    """
1937 1899
    mydict = super(_QueryResponseBase, self).ToDict()
1938
    mydict["fields"] = self._ContainerToDicts(mydict["fields"])
1900
    mydict["fields"] = objectutils.ContainerToDicts(mydict["fields"])
1939 1901
    return mydict
1940 1902

  
1941 1903
  @classmethod
......
1944 1906

  
1945 1907
    """
1946 1908
    obj = super(_QueryResponseBase, cls).FromDict(val)
1947
    obj.fields = cls._ContainerFromDicts(obj.fields, list, QueryFieldDefinition)
1909
    obj.fields = \
1910
      objectutils.ContainerFromDicts(obj.fields, list, QueryFieldDefinition)
1948 1911
    return obj
1949 1912

  
1950 1913

  
b/lib/objectutils.py
21 21
"""Module for object related utils."""
22 22

  
23 23

  
24
#: Supported container types for serialization/de-serialization (must be a
25
#: tuple as it's used as a parameter for C{isinstance})
26
_SEQUENCE_TYPES = (list, tuple, set, frozenset)
27

  
28

  
24 29
class AutoSlots(type):
25 30
  """Meta base class for __slots__ definitions.
26 31

  
......
91 96

  
92 97
    """
93 98
    raise NotImplementedError
99

  
100

  
101
def ContainerToDicts(container):
102
  """Convert the elements of a container to standard Python types.
103

  
104
  This method converts a container with elements to standard Python types. If
105
  the input container is of the type C{dict}, only its values are touched.
106
  Those values, as well as all elements of input sequences, must support a
107
  C{ToDict} method returning a serialized version.
108

  
109
  @type container: dict or sequence (see L{_SEQUENCE_TYPES})
110

  
111
  """
112
  if isinstance(container, dict):
113
    ret = dict([(k, v.ToDict()) for k, v in container.items()])
114
  elif isinstance(container, _SEQUENCE_TYPES):
115
    ret = [elem.ToDict() for elem in container]
116
  else:
117
    raise TypeError("Unknown container type '%s'" % type(container))
118

  
119
  return ret
120

  
121

  
122
def ContainerFromDicts(source, c_type, e_type):
123
  """Convert a container from standard python types.
124

  
125
  This method converts a container with standard Python types to objects. If
126
  the container is a dict, we don't touch the keys, only the values.
127

  
128
  @type source: None, dict or sequence (see L{_SEQUENCE_TYPES})
129
  @param source: Input data
130
  @type c_type: type class
131
  @param c_type: Desired type for returned container
132
  @type e_type: element type class
133
  @param e_type: Item type for elements in returned container (must have a
134
    C{FromDict} class method)
135

  
136
  """
137
  if not isinstance(c_type, type):
138
    raise TypeError("Container type '%s' is not a type" % type(c_type))
139

  
140
  if source is None:
141
    source = c_type()
142

  
143
  if c_type is dict:
144
    ret = dict([(k, e_type.FromDict(v)) for k, v in source.items()])
145
  elif c_type in _SEQUENCE_TYPES:
146
    ret = c_type(map(e_type.FromDict, source))
147
  else:
148
    raise TypeError("Unknown container type '%s'" % c_type)
149

  
150
  return ret
b/test/py/ganeti.objectutils_unittest.py
46 46
    slotted = AutoSlotted()
47 47
    self.assertEqual(slotted.__slots__, AutoSlotted.SLOTS)
48 48

  
49

  
50
class TestContainerToDicts(unittest.TestCase):
51
  def testUnknownType(self):
52
    for value in [None, 19410, "xyz"]:
53
      try:
54
        objectutils.ContainerToDicts(value)
55
      except TypeError, err:
56
        self.assertTrue(str(err).startswith("Unknown container type"))
57
      else:
58
        self.fail("Exception was not raised")
59

  
60
  def testEmptyDict(self):
61
    value = {}
62
    self.assertFalse(type(value) in objectutils._SEQUENCE_TYPES)
63
    self.assertEqual(objectutils.ContainerToDicts(value), {})
64

  
65
  def testEmptySequences(self):
66
    for cls in [list, tuple, set, frozenset]:
67
      self.assertEqual(objectutils.ContainerToDicts(cls()), [])
68

  
69

  
70
class _FakeWithFromDict:
71
  def FromDict(self, _):
72
    raise NotImplemented
73

  
74

  
75
class TestContainerFromDicts(unittest.TestCase):
76
  def testUnknownType(self):
77
    for cls in [str, int, bool]:
78
      try:
79
        objectutils.ContainerFromDicts(None, cls, NotImplemented)
80
      except TypeError, err:
81
        self.assertTrue(str(err).startswith("Unknown container type"))
82
      else:
83
        self.fail("Exception was not raised")
84

  
85
      try:
86
        objectutils.ContainerFromDicts(None, cls(), NotImplemented)
87
      except TypeError, err:
88
        self.assertTrue(str(err).endswith("is not a type"))
89
      else:
90
        self.fail("Exception was not raised")
91

  
92
  def testEmptyDict(self):
93
    value = {}
94
    self.assertFalse(type(value) in objectutils._SEQUENCE_TYPES)
95
    self.assertEqual(objectutils.ContainerFromDicts(value, dict,
96
                                                    NotImplemented),
97
                     {})
98

  
99
  def testEmptySequences(self):
100
    for cls in [list, tuple, set, frozenset]:
101
      self.assertEqual(objectutils.ContainerFromDicts([], cls,
102
                                                      _FakeWithFromDict),
103
                       cls())
104

  
105

  
49 106
if __name__ == "__main__":
50 107
  testutils.GanetiTestProgram()

Also available in: Unified diff