Revision 32683096 lib/opcodes.py

b/lib/opcodes.py
40 40
from ganeti import errors
41 41
from ganeti import ht
42 42
from ganeti import objects
43
from ganeti import objectutils
43 44

  
44 45

  
45 46
# Common opcode attributes
......
342 343
                 "Storage type")
343 344

  
344 345

  
345
class _AutoOpParamSlots(type):
346
class _AutoOpParamSlots(objectutils.AutoSlots):
346 347
  """Meta class for opcode definitions.
347 348

  
348 349
  """
......
356 357
    @param attrs: Class attributes
357 358

  
358 359
    """
359
    assert "__slots__" not in attrs, \
360
      "Class '%s' defines __slots__ when it should use OP_PARAMS" % name
361 360
    assert "OP_ID" not in attrs, "Class '%s' defining OP_ID" % name
362 361

  
362
    slots = mcs._GetSlots(attrs)
363
    assert "OP_DSC_FIELD" not in attrs or attrs["OP_DSC_FIELD"] in slots, \
364
      "Class '%s' uses unknown field in OP_DSC_FIELD" % name
365

  
363 366
    attrs["OP_ID"] = _NameToId(name)
364 367

  
368
    return objectutils.AutoSlots.__new__(mcs, name, bases, attrs)
369

  
370
  @classmethod
371
  def _GetSlots(mcs, attrs):
372
    """Build the slots out of OP_PARAMS.
373

  
374
    """
365 375
    # Always set OP_PARAMS to avoid duplicates in BaseOpCode.GetAllParams
366 376
    params = attrs.setdefault("OP_PARAMS", [])
367 377

  
368 378
    # Use parameter names as slots
369
    slots = [pname for (pname, _, _, _) in params]
370

  
371
    assert "OP_DSC_FIELD" not in attrs or attrs["OP_DSC_FIELD"] in slots, \
372
      "Class '%s' uses unknown field in OP_DSC_FIELD" % name
373

  
374
    attrs["__slots__"] = slots
375

  
376
    return type.__new__(mcs, name, bases, attrs)
379
    return [pname for (pname, _, _, _) in params]
377 380

  
378 381

  
379
class BaseOpCode(object):
382
class BaseOpCode(objectutils.ValidatedSlots):
380 383
  """A simple serializable object.
381 384

  
382 385
  This object serves as a parent class for OpCode without any custom
......
387 390
  # as OP_ID is dynamically defined
388 391
  __metaclass__ = _AutoOpParamSlots
389 392

  
390
  def __init__(self, **kwargs):
391
    """Constructor for BaseOpCode.
392

  
393
    The constructor takes only keyword arguments and will set
394
    attributes on this object based on the passed arguments. As such,
395
    it means that you should not pass arguments which are not in the
396
    __slots__ attribute for this class.
397

  
398
    """
399
    slots = self._all_slots()
400
    for key in kwargs:
401
      if key not in slots:
402
        raise TypeError("Object %s doesn't support the parameter '%s'" %
403
                        (self.__class__.__name__, key))
404
      setattr(self, key, kwargs[key])
405

  
406 393
  def __getstate__(self):
407 394
    """Generic serializer.
408 395

  
......
414 401

  
415 402
    """
416 403
    state = {}
417
    for name in self._all_slots():
404
    for name in self.GetAllSlots():
418 405
      if hasattr(self, name):
419 406
        state[name] = getattr(self, name)
420 407
    return state
......
433 420
      raise ValueError("Invalid data to __setstate__: expected dict, got %s" %
434 421
                       type(state))
435 422

  
436
    for name in self._all_slots():
423
    for name in self.GetAllSlots():
437 424
      if name not in state and hasattr(self, name):
438 425
        delattr(self, name)
439 426

  
......
441 428
      setattr(self, name, state[name])
442 429

  
443 430
  @classmethod
444
  def _all_slots(cls):
445
    """Compute the list of all declared slots for a class.
446

  
447
    """
448
    slots = []
449
    for parent in cls.__mro__:
450
      slots.extend(getattr(parent, "__slots__", []))
451
    return slots
452

  
453
  @classmethod
454 431
  def GetAllParams(cls):
455 432
    """Compute list of all parameters for an opcode.
456 433

  
......
460 437
      slots.extend(getattr(parent, "OP_PARAMS", []))
461 438
    return slots
462 439

  
463
  def Validate(self, set_defaults):
440
  def Validate(self, set_defaults): # pylint: disable=W0221
464 441
    """Validate opcode parameters, optionally setting default values.
465 442

  
466 443
    @type set_defaults: bool

Also available in: Unified diff