---
# System prepended metadata

title: ISMRMRD Python Stream Source/Sink

---

Something like this is probably what we want. First some definitions, simplified here, should include everything (`mrd_types.py`):

```python=
from enum import Enum
from typing import Union
import ismrmrd


class MessageType(Enum):
    HEADER = 3
    CLOSE = 4
    ACQUISITION = 1008
    IMAGE = 1022


Message = Union[ismrmrd.xsd.ismrmrdHeader, ismrmrd.Acquisition, ismrmrd.Image]
```

Then a source:

```python=
import struct
from typing import BinaryIO, Iterable
from mrd_types import MessageType, Message
import ismrmrd
import ismrmrd.xsd


class IsmrmrdSource():
    def __init__(self, input_reader: BinaryIO) -> None:
        super().__init__()
        self._input_reader = input_reader

    def __iter__(self) -> Iterable[Message]:
        while True:
            message_type = MessageType(struct.unpack('H', self._input_reader.read(2))[0])
            if message_type == MessageType.HEADER:
                header_size = struct.unpack('I', self._input_reader.read(4))[0]
                doc = self._input_reader.read(header_size)
                yield ismrmrd.xsd.CreateFromDocument(doc)
            elif message_type == MessageType.ACQUISITION:
                yield ismrmrd.Acquisition.deserialize_from(self._input_reader.read)
            elif message_type == MessageType.IMAGE:
                yield ismrmrd.Image.deserialize_from(self._input_reader.read)
            elif message_type == MessageType.CLOSE:
                if len(self._input_reader.read(1)) != 0:
                    raise Exception("Unexpected data after close message")
                return
            else:
                raise Exception(f"Unexpected message {message_type}")

```

And a sink:

```python=
class IsmrmrdSink():
    def __init__(self, output_writer: BinaryIO) -> None:
        super().__init__()
        self._output_writer = output_writer

    def _write_type(self, message_type: MessageType) -> None:
        self._output_writer.write(struct.pack('H', message_type.value))

    def write(self, seq: Iterable[Message]) -> None:
        for message in seq:
            if isinstance(message, ismrmrdHeader):
                self._write_type(MessageType.HEADER)
                xml_string = ismrmrd.xsd.ToXML(message, 'utf-8')
                xml_bytes = bytes(xml_string, 'utf-8')
                self._output_writer.write(struct.pack('I', len(xml_bytes)))
                self._output_writer.write(xml_bytes)
            elif isinstance(message, Acquisition):
                self._write_type(MessageType.ACQUISITION)
                message.serialize_into(self._output_writer.write)
            elif isinstance(message, Image):
                self._write_type(MessageType.IMAGE)
                message.serialize_into(self._output_writer.write)
            else:
                raise Exception(f"Unexpected message type {type(message)}")

        self._write_type(MessageType.CLOSE)
        self._output_writer.flush()
        return
```

This has not been tested, but should be the basic idea. 