On Tue, Jan 04, 2011 at 04:23:43PM +0100, Michael Hanselmann wrote:
> This is the first step for migrating them from cmdlib. A metaclass is
> used to define “__slots__” upon class creation time (not instantiation).
> 
> Signed-off-by: Michael Hanselmann <han...@google.com>
> ---
>  lib/opcodes.py                  |  655 
> ++++++++++++++++++++++++++++-----------
>  test/ganeti.cmdlib_unittest.py  |    6 +-
>  test/ganeti.opcodes_unittest.py |   39 +++
>  3 files changed, 524 insertions(+), 176 deletions(-)

> +class _AutoOpParamSlots(type):
> +  """Meta class for opcode 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: Instance attributes

Nitpick: s/instance/class/

> @@ -78,6 +79,44 @@ class TestOpcodes(unittest.TestCase):
>      else:
>        self.assertEqual("OP_%s" % summary, op.OP_ID)
>  
> +  def testParams(self):
> +    supported_by_all = set(["debug_level", "dry_run", "priority"])
> +
> +    for cls in opcodes.OP_MAPPING.values():
> +      all_slots = cls._all_slots()
> +
> +      self.assertEqual(len(set(all_slots) & supported_by_all), 3,
> +                       msg=("Opcode %s doesn't support all base"
> +                            " parameters (%r)" % (cls.OP_ID, 
> supported_by_all)))
> +
> +      # All opcodes must have OP_PARAMS
> +      self.assert_(hasattr(cls, "OP_PARAMS"),
> +                   msg="%s doesn't have OP_PARAMS" % cls.OP_ID)
> +
> +      param_names = [name for (name, _, _) in cls.GetAllParams()]
> +
> +      self.assertEqual(all_slots, param_names)
> +
> +      # Without inheritance
> +      self.assertEqual(cls.__slots__, [name for (name, _, _) in 
> cls.OP_PARAMS])
> +
> +      # This won't work if parameters are converted to a dictionary
> +      duplicates = utils.FindDuplicates(param_names)
> +      self.assertFalse(duplicates,
> +                       msg=("Found duplicate parameters %r in %s" %
> +                            (duplicates, cls.OP_ID)))
> +
> +      # Check parameter definitions
> +      for attr_name, aval, test in cls.GetAllParams():
> +        self.assert_(attr_name)
> +        self.assert_(test is None or test is ht.NoType or callable(test),
> +                     msg=("Invalid type check for %s.%s" %
> +                          (cls.OP_ID, attr_name)))
> +
> +        if callable(aval):
> +          self.assertFalse(callable(aval()),
> +                           msg="Default value returned by function is 
> callable")

One thing that is not tested and that I would like to ensure is that
even with the metaclass, __slots__ works as expected. Can you add a
self.assertRaises(setattr, …)?

In any case, LGTM, thanks!
iustin

Reply via email to