+ This method just restores from the serialized state the attributes
+ of the current instance.
+
+ @param state: the serialized opcode data
+ @type state: C{dict}
+
+ """
+ if not isinstance(state, dict):
+ raise ValueError("Invalid data to __setstate__: expected dict, got %s" %
+ type(state))
+
+ for name in self.__slots__:
+ if name not in state:
+ delattr(self, name)
+
+ for name in state:
+ setattr(self, name, state[name])
+
+
+class OpCode(BaseOpCode):
+ """Abstract OpCode.
+
+ This is the root of the actual OpCode hierarchy. All clases derived
+ from this class should override OP_ID.
+
+ @cvar OP_ID: The ID of this opcode. This should be unique amongst all
+ children of this class.
+ @ivar dry_run: Whether the LU should be run in dry-run mode, i.e. just
+ the check steps
+
+ """
+ OP_ID = "OP_ABSTRACT"
+ __slots__ = BaseOpCode.__slots__ + ["dry_run"]
+
+ def __getstate__(self):
+ """Specialized getstate for opcodes.
+
+ This method adds to the state dictionary the OP_ID of the class,
+ so that on unload we can identify the correct class for
+ instantiating the opcode.
+
+ @rtype: C{dict}
+ @return: the state as a dictionary
+
+ """
+ data = BaseOpCode.__getstate__(self)
+ data["OP_ID"] = self.OP_ID
+ return data
+
+ @classmethod
+ def LoadOpCode(cls, data):
+ """Generic load opcode method.
+
+ The method identifies the correct opcode class from the dict-form
+ by looking for a OP_ID key, if this is not found, or its value is
+ not available in this module as a child of this class, we fail.
+
+ @type data: C{dict}
+ @param data: the serialized opcode
+
+ """
+ if not isinstance(data, dict):
+ raise ValueError("Invalid data to LoadOpCode (%s)" % type(data))
+ if "OP_ID" not in data:
+ raise ValueError("Invalid data to LoadOpcode, missing OP_ID")
+ op_id = data["OP_ID"]
+ op_class = None
+ if op_id in OP_MAPPING:
+ op_class = OP_MAPPING[op_id]
+ else:
+ raise ValueError("Invalid data to LoadOpCode: OP_ID %s unsupported" %
+ op_id)
+ op = op_class()
+ new_data = data.copy()
+ del new_data["OP_ID"]
+ op.__setstate__(new_data)
+ return op
+
+ def Summary(self):
+ """Generates a summary description of this opcode.
+
+ """
+ # all OP_ID start with OP_, we remove that
+ txt = self.OP_ID[3:]
+ field_name = getattr(self, "OP_DSC_FIELD", None)
+ if field_name:
+ field_value = getattr(self, field_name, None)
+ txt = "%s(%s)" % (txt, field_value)
+ return txt
+
+
+# cluster opcodes