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