def unpack_from(cls, payload, expected_segments): for num_segment in iter_range(expected_segments): try: segment_header = ReplySegmentHeader(*cls.header_struct.unpack(payload.read(cls.header_size))) except struct.error: raise Exception("No valid segment header") debug('%s (%d/%d): %s', cls.__name__, num_segment + 1, expected_segments, str(segment_header)) if expected_segments == 1: # If we just expects one segment than we can take the full payload. # This also a workaround of an internal bug (Which bug?) segment_payload_size = -1 else: segment_payload_size = segment_header.segment_length - cls.header_size # Determinate segment payload pl = payload.read(segment_payload_size) segment_payload = BytesIO(pl) debug('Read %d bytes payload segment %d', len(pl), num_segment + 1) parts = tuple(Part.unpack_from(segment_payload, expected_parts=segment_header.num_parts)) segment = cls(segment_header.function_code, parts, header=segment_header) if segment_header.segment_kind == segment_kinds.REPLY: yield segment elif segment_header.segment_kind == segment_kinds.ERROR: error = segment if error.parts[0].kind == part_kinds.ROWSAFFECTED: raise Exception("Rows affected %s" % (error.parts[0].values,)) elif error.parts[0].kind == part_kinds.ERROR: raise error.parts[0].errors[0] else: raise Exception("Invalid reply segment")
def test_unpack_unkown_part_raises_exception(): packed = BytesIO( b"\x80\x00\x0a\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x00" b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" ) with pytest.raises(InterfaceError): tuple(Part.unpack_from(packed, 1))
def test_unpack_unkown_part_raises_exception(self): packed = BytesIO( b"\x80\x00\x0a\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x00" b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" ) with pytest.raises(InterfaceError): tuple(Part.unpack_from(packed, 1))
def unpack(cls, header, payload): """ Takes unpacked header and payload of segment and create ReplySegment object. """ return cls( header[6], tuple(Part.unpack_from(payload, expected_parts=header[2])) )
def unpack_from(cls, payload, expected_segments): for num_segment in iter_range(expected_segments): try: segment_header = ReplySegmentHeader( *cls.header_struct.unpack(payload.read(cls.header_size))) except struct.error: raise Exception("No valid segment header") debug('%s (%d/%d): %s', cls.__name__, num_segment + 1, expected_segments, str(segment_header)) if expected_segments == 1: # If we just expects one segment than we can take the full payload. # This also a workaround of an internal bug (Which bug?) segment_payload_size = -1 else: segment_payload_size = segment_header.segment_length - cls.header_size # Determinate segment payload pl = payload.read(segment_payload_size) segment_payload = BytesIO(pl) debug('Read %d bytes payload segment %d', len(pl), num_segment + 1) parts = tuple( Part.unpack_from(segment_payload, expected_parts=segment_header.num_parts)) segment = cls(segment_header.function_code, parts, header=segment_header) if segment_header.segment_kind == segment_kinds.REPLY: yield segment elif segment_header.segment_kind == segment_kinds.ERROR: error = segment if error.parts[0].kind == part_kinds.ROWSAFFECTED: raise Exception("Rows affected %s" % (error.parts[0].values, )) elif error.parts[0].kind == part_kinds.ERROR: raise error.parts[0].errors[0] else: raise Exception("Invalid reply segment")
def test_unpack_multiple_dummy_parts(): packed = BytesIO( b"\x7f\x00\x0a\x00\x00\x00\x00\x00\x0a\x00\x00\x00\xc8\xff\x01" b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" b"\x00\x00\x7f\x00\x0e\x00\x00\x00\x00\x00\x0e\x00\x00\x00\xa8" b"\xff\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" b"\x00\x00\x00\x00\x7f\x00\x12\x00\x00\x00\x00\x00\x12\x00\x00" b"\x00\x68\xff\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" ) unpacked = tuple(Part.unpack_from(packed, 3)) assert len(unpacked) == 3 assert isinstance(unpacked[0], DummyPart) assert unpacked[0].zeros == 10 assert isinstance(unpacked[1], DummyPart) assert unpacked[1].zeros == 14 assert isinstance(unpacked[2], DummyPart) assert unpacked[2].zeros == 18
def test_unpack_multiple_dummy_parts(self): packed = BytesIO( b"\x7f\x00\x0a\x00\x00\x00\x00\x00\x0a\x00\x00\x00\xc8\xff\x01" b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" b"\x00\x00\x7f\x00\x0e\x00\x00\x00\x00\x00\x0e\x00\x00\x00\xa8" b"\xff\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" b"\x00\x00\x00\x00\x7f\x00\x12\x00\x00\x00\x00\x00\x12\x00\x00" b"\x00\x68\xff\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" ) unpacked = tuple(Part.unpack_from(packed, 3)) assert len(unpacked) == 3 assert isinstance(unpacked[0], DummyPart) assert unpacked[0].zeros == 10 assert isinstance(unpacked[1], DummyPart) assert unpacked[1].zeros == 14 assert isinstance(unpacked[2], DummyPart) assert unpacked[2].zeros == 18
def test_invalid_part_header_raises_exception(): packed = BytesIO( b"\xbb\xff\xaa\x00\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00" ) with pytest.raises(InterfaceError): tuple(Part.unpack_from(packed, 1))
def test_invalid_part_header_raises_exception(self): packed = BytesIO( b"\xbb\xff\xaa\x00\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00" ) with pytest.raises(InterfaceError): tuple(Part.unpack_from(packed, 1))