commit 36e1c7e840711b30fc60fd44cb0e47e4ee5c1133
Merge: d9a2252 473d87a
Author: Iustin Pop <[email protected]>
Date:   Fri Feb 15 12:53:30 2013 +0100

    Merge branch 'devel-2.7'
    
    * devel-2.7:
      Rename lib/objectutils to outils.py
      Fix typo in gnt-group manpage
      Fix wrong type in a docstring of the RAPI subsystem
      Finish the remote→restricted commands rename
      Enable use of the priority option in hbal
      Add CLI-level option to override the priority
      Add functions to parse CLI-level format of priorities
      Add a function to change an OpCode's priority
      Make hbal opcode annotation more generic
      Add unit tests for RADOSBLockDevice
      Fix rbd showmapped output parsing
      Change default xen root path to /dev/xvda1
      Removes check for conflicts from NetworkDisconnect
      If _UnlockedLookupNetwork() fails raise error
      Force conflicts check in LUNetworkDisconnect
    
    Also updated objects.py with more outils renames.
    
    Signed-off-by: Iustin Pop <[email protected]>

diff --cc lib/objects.py
index 6340d8d,588ef03..fa811a6
--- a/lib/objects.py
+++ b/lib/objects.py
@@@ -406,7 -447,7 +406,7 @@@ class ConfigData(ConfigObject)
      mydict = super(ConfigData, self).ToDict()
      mydict["cluster"] = mydict["cluster"].ToDict()
      for key in "nodes", "instances", "nodegroups", "networks":
-       mydict[key] = objectutils.ContainerToDicts(mydict[key])
 -      mydict[key] = self._ContainerToDicts(mydict[key])
++      mydict[key] = outils.ContainerToDicts(mydict[key])
  
      return mydict
  
@@@ -417,12 -458,10 +417,12 @@@
      """
      obj = super(ConfigData, cls).FromDict(val)
      obj.cluster = Cluster.FromDict(obj.cluster)
-     obj.nodes = objectutils.ContainerFromDicts(obj.nodes, dict, Node)
 -    obj.nodes = cls._ContainerFromDicts(obj.nodes, dict, Node)
 -    obj.instances = cls._ContainerFromDicts(obj.instances, dict, Instance)
 -    obj.nodegroups = cls._ContainerFromDicts(obj.nodegroups, dict, NodeGroup)
 -    obj.networks = cls._ContainerFromDicts(obj.networks, dict, Network)
++    obj.nodes = outils.ContainerFromDicts(obj.nodes, dict, Node)
 +    obj.instances = \
-       objectutils.ContainerFromDicts(obj.instances, dict, Instance)
++      outils.ContainerFromDicts(obj.instances, dict, Instance)
 +    obj.nodegroups = \
-       objectutils.ContainerFromDicts(obj.nodegroups, dict, NodeGroup)
-     obj.networks = objectutils.ContainerFromDicts(obj.networks, dict, Network)
++      outils.ContainerFromDicts(obj.nodegroups, dict, NodeGroup)
++    obj.networks = outils.ContainerFromDicts(obj.networks, dict, Network)
      return obj
  
    def HasAnyDiskOfType(self, dev_type):
@@@ -732,7 -771,7 +732,7 @@@ class Disk(ConfigObject)
      for attr in ("children",):
        alist = bo.get(attr, None)
        if alist:
-         bo[attr] = objectutils.ContainerToDicts(alist)
 -        bo[attr] = self._ContainerToDicts(alist)
++        bo[attr] = outils.ContainerToDicts(alist)
      return bo
  
    @classmethod
@@@ -742,7 -781,7 +742,7 @@@
      """
      obj = super(Disk, cls).FromDict(val)
      if obj.children:
-       obj.children = objectutils.ContainerFromDicts(obj.children, list, Disk)
 -      obj.children = cls._ContainerFromDicts(obj.children, list, Disk)
++      obj.children = outils.ContainerFromDicts(obj.children, list, Disk)
      if obj.logical_id and isinstance(obj.logical_id, list):
        obj.logical_id = tuple(obj.logical_id)
      if obj.physical_id and isinstance(obj.physical_id, list):
@@@ -1100,7 -1139,7 +1100,7 @@@ class Instance(TaggableObject)
      for attr in "nics", "disks":
        alist = bo.get(attr, None)
        if alist:
-         nlist = objectutils.ContainerToDicts(alist)
 -        nlist = self._ContainerToDicts(alist)
++        nlist = outils.ContainerToDicts(alist)
        else:
          nlist = []
        bo[attr] = nlist
@@@ -1119,8 -1158,8 +1119,8 @@@
      if "admin_up" in val:
        del val["admin_up"]
      obj = super(Instance, cls).FromDict(val)
-     obj.nics = objectutils.ContainerFromDicts(obj.nics, list, NIC)
-     obj.disks = objectutils.ContainerFromDicts(obj.disks, list, Disk)
 -    obj.nics = cls._ContainerFromDicts(obj.nics, list, NIC)
 -    obj.disks = cls._ContainerFromDicts(obj.disks, list, Disk)
++    obj.nics = outils.ContainerFromDicts(obj.nics, list, NIC)
++    obj.disks = outils.ContainerFromDicts(obj.disks, list, Disk)
      return obj
  
    def UpgradeConfig(self):
@@@ -1314,12 -1353,12 +1314,12 @@@ class Node(TaggableObject)
  
      hv_state = data.get("hv_state", None)
      if hv_state is not None:
-       data["hv_state"] = objectutils.ContainerToDicts(hv_state)
 -      data["hv_state"] = self._ContainerToDicts(hv_state)
++      data["hv_state"] = outils.ContainerToDicts(hv_state)
  
      disk_state = data.get("disk_state", None)
      if disk_state is not None:
        data["disk_state"] = \
-         dict((key, objectutils.ContainerToDicts(value))
 -        dict((key, self._ContainerToDicts(value))
++        dict((key, outils.ContainerToDicts(value))
               for (key, value) in disk_state.items())
  
      return data
@@@ -1332,12 -1371,11 +1332,12 @@@
      obj = super(Node, cls).FromDict(val)
  
      if obj.hv_state is not None:
 -      obj.hv_state = cls._ContainerFromDicts(obj.hv_state, dict, NodeHvState)
 +      obj.hv_state = \
-         objectutils.ContainerFromDicts(obj.hv_state, dict, NodeHvState)
++        outils.ContainerFromDicts(obj.hv_state, dict, NodeHvState)
  
      if obj.disk_state is not None:
        obj.disk_state = \
-         dict((key, objectutils.ContainerFromDicts(value, dict, NodeDiskState))
 -        dict((key, cls._ContainerFromDicts(value, dict, NodeDiskState))
++        dict((key, outils.ContainerFromDicts(value, dict, NodeDiskState))
               for (key, value) in obj.disk_state.items())
  
      return obj
@@@ -1906,7 -1933,7 +1906,7 @@@ class _QueryResponseBase(ConfigObject)
  
      """
      mydict = super(_QueryResponseBase, self).ToDict()
-     mydict["fields"] = objectutils.ContainerToDicts(mydict["fields"])
 -    mydict["fields"] = self._ContainerToDicts(mydict["fields"])
++    mydict["fields"] = outils.ContainerToDicts(mydict["fields"])
      return mydict
  
    @classmethod
@@@ -1915,8 -1942,7 +1915,8 @@@
  
      """
      obj = super(_QueryResponseBase, cls).FromDict(val)
 -    obj.fields = cls._ContainerFromDicts(obj.fields, list, 
QueryFieldDefinition)
 +    obj.fields = \
-       objectutils.ContainerFromDicts(obj.fields, list, QueryFieldDefinition)
++      outils.ContainerFromDicts(obj.fields, list, QueryFieldDefinition)
      return obj
  
  
diff --cc lib/outils.py
index 0000000,e2742b1..f0f6558
mode 000000,100644..100644
--- a/lib/outils.py
+++ b/lib/outils.py
@@@ -1,0 -1,93 +1,150 @@@
+ #
+ #
+ 
+ # Copyright (C) 2012 Google Inc.
+ #
+ # This program is free software; you can redistribute it and/or modify
+ # it under the terms of the GNU General Public License as published by
+ # the Free Software Foundation; either version 2 of the License, or
+ # (at your option) any later version.
+ #
+ # This program is distributed in the hope that it will be useful, but
+ # WITHOUT ANY WARRANTY; without even the implied warranty of
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ # General Public License for more details.
+ #
+ # You should have received a copy of the GNU General Public License
+ # along with this program; if not, write to the Free Software
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ # 02110-1301, USA.
+ 
+ """Module for object related utils."""
+ 
+ 
++#: Supported container types for serialization/de-serialization (must be a
++#: tuple as it's used as a parameter for C{isinstance})
++_SEQUENCE_TYPES = (list, tuple, set, frozenset)
++
++
+ class AutoSlots(type):
+   """Meta base class for __slots__ definitions.
+ 
+   """
+   def __new__(mcs, name, bases, attrs):
+     """Called when a class should be created.
+ 
+     @param mcs: The meta class
+     @param name: Name of created class
+     @param bases: Base classes
+     @type attrs: dict
+     @param attrs: Class attributes
+ 
+     """
+     assert "__slots__" not in attrs, \
+       "Class '%s' defines __slots__ when it should not" % name
+ 
+     attrs["__slots__"] = mcs._GetSlots(attrs)
+ 
+     return type.__new__(mcs, name, bases, attrs)
+ 
+   @classmethod
+   def _GetSlots(mcs, attrs):
+     """Used to get the list of defined slots.
+ 
+     @param attrs: The attributes of the class
+ 
+     """
+     raise NotImplementedError
+ 
+ 
+ class ValidatedSlots(object):
+   """Sets and validates slots.
+ 
+   """
+   __slots__ = []
+ 
+   def __init__(self, **kwargs):
+     """Constructor for BaseOpCode.
+ 
+     The constructor takes only keyword arguments and will set
+     attributes on this object based on the passed arguments. As such,
+     it means that you should not pass arguments which are not in the
+     __slots__ attribute for this class.
+ 
+     """
+     slots = self.GetAllSlots()
+     for (key, value) in kwargs.items():
+       if key not in slots:
+         raise TypeError("Object %s doesn't support the parameter '%s'" %
+                         (self.__class__.__name__, key))
+       setattr(self, key, value)
+ 
+   @classmethod
+   def GetAllSlots(cls):
+     """Compute the list of all declared slots for a class.
+ 
+     """
+     slots = []
+     for parent in cls.__mro__:
+       slots.extend(getattr(parent, "__slots__", []))
+     return slots
+ 
+   def Validate(self):
+     """Validates the slots.
+ 
+     This method must be implemented by the child classes.
+ 
+     """
+     raise NotImplementedError
++
++
++def ContainerToDicts(container):
++  """Convert the elements of a container to standard Python types.
++
++  This method converts a container with elements to standard Python types. If
++  the input container is of the type C{dict}, only its values are touched.
++  Those values, as well as all elements of input sequences, must support a
++  C{ToDict} method returning a serialized version.
++
++  @type container: dict or sequence (see L{_SEQUENCE_TYPES})
++
++  """
++  if isinstance(container, dict):
++    ret = dict([(k, v.ToDict()) for k, v in container.items()])
++  elif isinstance(container, _SEQUENCE_TYPES):
++    ret = [elem.ToDict() for elem in container]
++  else:
++    raise TypeError("Unknown container type '%s'" % type(container))
++
++  return ret
++
++
++def ContainerFromDicts(source, c_type, e_type):
++  """Convert a container from standard python types.
++
++  This method converts a container with standard Python types to objects. If
++  the container is a dict, we don't touch the keys, only the values.
++
++  @type source: None, dict or sequence (see L{_SEQUENCE_TYPES})
++  @param source: Input data
++  @type c_type: type class
++  @param c_type: Desired type for returned container
++  @type e_type: element type class
++  @param e_type: Item type for elements in returned container (must have a
++    C{FromDict} class method)
++
++  """
++  if not isinstance(c_type, type):
++    raise TypeError("Container type '%s' is not a type" % type(c_type))
++
++  if source is None:
++    source = c_type()
++
++  if c_type is dict:
++    ret = dict([(k, e_type.FromDict(v)) for k, v in source.items()])
++  elif c_type in _SEQUENCE_TYPES:
++    ret = c_type(map(e_type.FromDict, source))
++  else:
++    raise TypeError("Unknown container type '%s'" % c_type)
++
++  return ret
diff --cc test/py/ganeti.outils_unittest.py
index 0000000,93f5212..22d2177
mode 000000,100755..100755
--- a/test/py/ganeti.outils_unittest.py
+++ b/test/py/ganeti.outils_unittest.py
@@@ -1,0 -1,50 +1,107 @@@
+ #!/usr/bin/python
+ #
+ 
+ # Copyright (C) 2012, 2013 Google Inc.
+ #
+ # This program is free software; you can redistribute it and/or modify
+ # it under the terms of the GNU General Public License as published by
+ # the Free Software Foundation; either version 2 of the License, or
+ # (at your option) any later version.
+ #
+ # This program is distributed in the hope that it will be useful, but
+ # WITHOUT ANY WARRANTY; without even the implied warranty of
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ # General Public License for more details.
+ #
+ # You should have received a copy of the GNU General Public License
+ # along with this program; if not, write to the Free Software
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ # 02110-1301, USA.
+ 
+ 
+ """Script for unittesting the outils module"""
+ 
+ 
+ import unittest
+ 
+ from ganeti import outils
+ 
+ import testutils
+ 
+ 
+ class SlotsAutoSlot(outils.AutoSlots):
+   @classmethod
+   def _GetSlots(mcs, attr):
+     return attr["SLOTS"]
+ 
+ 
+ class AutoSlotted(object):
+   __metaclass__ = SlotsAutoSlot
+ 
+   SLOTS = ["foo", "bar", "baz"]
+ 
+ 
+ class TestAutoSlot(unittest.TestCase):
+   def test(self):
+     slotted = AutoSlotted()
+     self.assertEqual(slotted.__slots__, AutoSlotted.SLOTS)
+ 
++
++class TestContainerToDicts(unittest.TestCase):
++  def testUnknownType(self):
++    for value in [None, 19410, "xyz"]:
++      try:
++        outils.ContainerToDicts(value)
++      except TypeError, err:
++        self.assertTrue(str(err).startswith("Unknown container type"))
++      else:
++        self.fail("Exception was not raised")
++
++  def testEmptyDict(self):
++    value = {}
++    self.assertFalse(type(value) in outils._SEQUENCE_TYPES)
++    self.assertEqual(outils.ContainerToDicts(value), {})
++
++  def testEmptySequences(self):
++    for cls in [list, tuple, set, frozenset]:
++      self.assertEqual(outils.ContainerToDicts(cls()), [])
++
++
++class _FakeWithFromDict:
++  def FromDict(self, _):
++    raise NotImplemented
++
++
++class TestContainerFromDicts(unittest.TestCase):
++  def testUnknownType(self):
++    for cls in [str, int, bool]:
++      try:
++        outils.ContainerFromDicts(None, cls, NotImplemented)
++      except TypeError, err:
++        self.assertTrue(str(err).startswith("Unknown container type"))
++      else:
++        self.fail("Exception was not raised")
++
++      try:
++        outils.ContainerFromDicts(None, cls(), NotImplemented)
++      except TypeError, err:
++        self.assertTrue(str(err).endswith("is not a type"))
++      else:
++        self.fail("Exception was not raised")
++
++  def testEmptyDict(self):
++    value = {}
++    self.assertFalse(type(value) in outils._SEQUENCE_TYPES)
++    self.assertEqual(outils.ContainerFromDicts(value, dict,
++                                                    NotImplemented),
++                     {})
++
++  def testEmptySequences(self):
++    for cls in [list, tuple, set, frozenset]:
++      self.assertEqual(outils.ContainerFromDicts([], cls,
++                                                      _FakeWithFromDict),
++                       cls())
++
++
+ if __name__ == "__main__":
+   testutils.GanetiTestProgram()

-- 
thanks,
iustin

Reply via email to