from io import BytesIO from struct import unpack, calcsize from typing import Dict, BinaryIO class Unpacker: @staticmethod def from_bytes(data: bytes): return Unpacker({}, BytesIO(data)) def __init__(self, formats: Dict[str, str], stream: BinaryIO, endianness: str = '>'): self.formats = formats self.stream = stream self.endianness = endianness def __getattribute__(self, item): try: return super(Unpacker, self).__getattribute__(item) except AttributeError: return self.unpack(item) def __getitem__(self, item): return self.unpack(item) def unpack(self, item): if item in self.formats: fmt = self.formats.get(item) else: fmt = item fmt = self.endianness + fmt size = calcsize(fmt) return unpack(fmt, self.stream.read(size))