msspec_python3/msspec/msspecgui/dataflowxmlserializer/dataflowxmlserializer.py

214 lines
8.3 KiB
Python
Raw Normal View History

2019-11-14 15:16:51 +01:00
import abc
from xml.dom import minidom
# from msspecgui.dataflow import Operator
from msspecgui.dataflow import IDataflowSerializer
from msspecgui.dataflow.datatypes import StringDataType
from msspecgui.dataflow.datatypes import FloatDataType
from msspecgui.dataflow.datatypes import BoolDataType
from msspecgui.dataflow.datatypes import IntDataType
class IDataTypeSerializer(object):
@abc.abstractmethod
def get_data_type(self):
"""
:return msspecgui.dataflow.IDatatype: the id of the type this seralize deals with
"""
return None
@abc.abstractmethod
def value_to_xml(self, value, xml_node):
"""
:param minidom.Element xml_node: the container node of the serialized value
"""
pass
@abc.abstractmethod
def xml_to_value(self, xml_node):
"""
:param minidom.Element xml_node: the container node of the serialized value
"""
pass
class StringSerializer(IDataTypeSerializer):
def get_data_type(self):
return StringDataType()
def value_to_xml(self, value, xml_node):
xml_node.setAttribute('value', '%s' % value)
def xml_to_value(self, xml_node):
return xml_node.GetAttribute('value')
class FloatSerializer(IDataTypeSerializer):
def get_data_type(self):
return FloatDataType()
def value_to_xml(self, value, xml_node):
xml_node.setAttribute('value', '%f' % value)
def xml_to_value(self, xml_node):
return float(xml_node.GetAttribute('value'))
class BoolSerializer(IDataTypeSerializer):
def get_data_type(self):
return BoolDataType()
def value_to_xml(self, value, xml_node):
xml_node.setAttribute('value', {False: 'false', True: 'true'}[value])
def xml_to_value(self, xml_node):
value_as_str = xml_node.GetAttribute('value')
return {'false': False, 'true': True}[value_as_str]
class IntSerializer(IDataTypeSerializer):
def get_data_type(self):
return IntDataType()
def value_to_xml(self, value, xml_node):
xml_node.setAttribute('value', '%d' % value)
def xml_to_value(self, xml_node):
return int(xml_node.GetAttribute('value'))
class DataflowSerializer(IDataflowSerializer):
FORMAT_VERSION = 1
def __init__(self):
super(DataflowSerializer, self).__init__()
self._data_type_serializers = {} #: :type self._data_type_serializers: dict[str, IDataTypeSerializer]
self._register_data_type_serializer(StringSerializer())
self._register_data_type_serializer(FloatSerializer())
self._register_data_type_serializer(BoolSerializer())
self._register_data_type_serializer(IntSerializer())
def _register_data_type_serializer(self, data_type_serializer):
"""
:param IDataTypeSerializer data_type_serializer: the datatype serialize that needs to be registered
"""
self._data_type_serializers[data_type_serializer.get_data_type().get_type_id()] = data_type_serializer
def _get_datatype_serializer(self, data_type_id):
"""
:param str data_type_id:
"""
return self._data_type_serializers[data_type_id]
def _operator_as_xml(self, operator, xml_doc):
"""creates the xml representation of the given operator
:param msspecgui.dataflow.Operator operator: the operator
:param minidom.Document xml_doc: the xml document that be used to create the xml node
:return minidom.Element: the xml representation of the operator
"""
op_xml_node = xml_doc.createElement('operator')
op_xml_node.setAttribute('nodeId', '%d' % operator.id)
op_xml_node.setAttribute('operatorTypeId', '%s' % operator.creator.get_operator_type_id())
for plug in operator.get_input_plugs():
if not plug.is_pluggable:
plug_node = xml_doc.createElement(plug.name)
data_type_id = plug.data_type.get_type_id()
# print('data_type_id = %s' % data_type_id)
data_type_serializer = self._get_datatype_serializer(data_type_id)
data_type_serializer.value_to_xml(plug.get_value(), plug_node)
op_xml_node.appendChild(plug_node)
return op_xml_node
def _create_operator_from_xml(self, op_xml_node, dataflow):
"""
:param minidom.Element op_xml_node: the xml node describing the operator and its data
:param msspec.dataflow.IDataFlow dataflow: the dataflow that contains the resulting operator
:return msspec.dataflow.Operator: the created operator
"""
operator_type_id = str(op_xml_node.getAttribute('operatorTypeId'))
operator = dataflow.create_operator(operator_type_id)
operator.id = int(op_xml_node.getAttribute('nodeId'))
dataflow.add_operator(operator)
return operator
def save_dataflow(self, dataflow, file_path):
"""
:type dataflow: msspecgui.dataflow.DataFlow
"""
xml_doc = minidom.Document()
root_xml_node = xml_doc.createElement('dataflow')
xml_doc.appendChild(root_xml_node)
# store a format version so that if the format needs changing, then it will be possible to detect and support old file formats
format_version_xml_node = xml_doc.createElement('formatVersion')
format_version_xml_node.setAttribute('value', '%d' % self.FORMAT_VERSION)
root_xml_node.appendChild(format_version_xml_node)
last_create_op_id_xml_node = xml_doc.createElement('lastCreatedOperatorId')
last_create_op_id_xml_node.setAttribute('value', '%d' % dataflow.last_created_operator_id)
root_xml_node.appendChild(last_create_op_id_xml_node)
operators_xml_node = xml_doc.createElement('operators')
root_xml_node.appendChild(operators_xml_node)
for op in dataflow.operators:
op_xml_node = self._operator_as_xml(op, xml_doc)
operators_xml_node.appendChild(op_xml_node)
wires_xml_node = xml_doc.createElement('wires')
root_xml_node.appendChild(wires_xml_node)
for wire in dataflow.wires: #: :type wire: msspec.dataflow.Wire
wire_xml_node = xml_doc.createElement('wire')
wire_xml_node.setAttribute('fromOperator', '%d' % wire.input_plug.operator.id)
wire_xml_node.setAttribute('fromAttr', wire.input_plug.name)
wire_xml_node.setAttribute('toOperator', '%d' % wire.output_plug.operator.id)
wire_xml_node.setAttribute('toAttr', wire.output_plug.name)
wires_xml_node.appendChild(wire_xml_node)
print('save_dataflow : saving to %s\n' % file_path)
with open(file_path, 'w') as f:
f.write(xml_doc.toprettyxml())
def load_dataflow(self, file_path, dataflow):
"""
:param msspecgui.dataflow.DataFlow dataflow: an empty dataflow that will be filled
"""
xml_doc = minidom.parse(file_path)
root_xml_node = xml_doc.documentElement
last_create_op_id_xml_node = root_xml_node.getElementsByTagName('lastCreatedOperatorId')[0]
last_created_operator_id = int(last_create_op_id_xml_node.getAttribute('value'))
dataflow.last_created_operator_id = last_created_operator_id
operators_xml_node = root_xml_node.getElementsByTagName('operators')[0]
for op_xml_node in operators_xml_node.getElementsByTagName('operator'):
# print('load_dataflow : creating operator')
self._create_operator_from_xml(op_xml_node, dataflow)
wires_xml_node = root_xml_node.getElementsByTagName('wires')[0]
for wire_xml_node in wires_xml_node.getElementsByTagName('wire'):
from_op_id = int(wire_xml_node.getAttribute('fromOperator'))
from_attr = wire_xml_node.getAttribute('fromAttr')
to_op_id = int(wire_xml_node.getAttribute('toOperator'))
to_attr = wire_xml_node.getAttribute('toAttr')
from_plug = dataflow.get_operator(from_op_id).get_plug(from_attr)
to_plug = dataflow.get_operator(to_op_id).get_plug(to_attr)
# print('load_dataflow : creating wire')
dataflow.create_wire(from_plug, to_plug)
return dataflow