From 643673813c27c1168109ff213d0c9e2fadb05573 Mon Sep 17 00:00:00 2001 From: Marc Julien Date: Sun, 7 Sep 2025 19:27:08 -0700 Subject: [PATCH] python(feat): Add support for querying byte channels --- python/lib/sift_py/data/_deserialize.py | 17 ++++++++ python/lib/sift_py/data/_deserialize_test.py | 44 ++++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/python/lib/sift_py/data/_deserialize.py b/python/lib/sift_py/data/_deserialize.py index 5acf9f58d..f0ed8f780 100644 --- a/python/lib/sift_py/data/_deserialize.py +++ b/python/lib/sift_py/data/_deserialize.py @@ -6,6 +6,7 @@ from sift.data.v2.data_pb2 import ( BitFieldValues, BoolValues, + BytesValues, DoubleValues, EnumValues, FloatValues, @@ -34,6 +35,7 @@ class ChannelValues(Enum): INT64_VALUES = "sift.data.v2.Int64Values" UINT32_VALUES = "sift.data.v2.Uint32Values" UINT64_VALUES = "sift.data.v2.Uint64Values" + BYTES_VALUES = "sift.data.v2.BytesValues" def try_deserialize_channel_data(channel_values: Any) -> List[Tuple[Metadata, ChannelTimeSeries]]: @@ -204,5 +206,20 @@ def try_deserialize_channel_data(channel_values: Any) -> List[Tuple[Metadata, Ch parsed_data.append((md_copy, time_series)) return parsed_data + elif ChannelValues.BYTES_VALUES.value in channel_values.type_url: + bytes_values = cast(BytesValues, BytesValues.FromString(channel_values.value)) + metadata = bytes_values.metadata + + time_column = [] + bytes_value_column = [] + + for bytes_v in bytes_values.values: + time_column.append(to_timestamp_nanos(bytes_v.timestamp)) + bytes_value_column.append(bytes_v.value) + + time_series = ChannelTimeSeries( + ChannelDataType.from_pb(metadata.data_type), time_column, bytes_value_column + ) + return [(metadata, time_series)] raise SiftError(f"Received an unknown channel-type '{channel_values.type_url}'.") diff --git a/python/lib/sift_py/data/_deserialize_test.py b/python/lib/sift_py/data/_deserialize_test.py index 31f5d8bbd..59010dfda 100644 --- a/python/lib/sift_py/data/_deserialize_test.py +++ b/python/lib/sift_py/data/_deserialize_test.py @@ -2,12 +2,15 @@ from sift.common.type.v1.channel_bit_field_element_pb2 import ChannelBitFieldElement from sift.common.type.v1.channel_data_type_pb2 import ( CHANNEL_DATA_TYPE_BIT_FIELD, + CHANNEL_DATA_TYPE_BYTES, CHANNEL_DATA_TYPE_DOUBLE, ) from sift.data.v2.data_pb2 import ( BitFieldElementValues, BitFieldValue, BitFieldValues, + BytesValue, + BytesValues, DoubleValue, DoubleValues, Metadata, @@ -58,6 +61,47 @@ def test_try_deserialize_channel_data_double(): assert time_series.time_column[1] == to_timestamp_nanos(time_b) +def test_try_deserialize_channel_data_bytes(): + metadata = Metadata( + data_type=CHANNEL_DATA_TYPE_BYTES, channel=Metadata.Channel(name="bytes-channel") + ) + + time_a = "2024-07-04T18:09:08.555-07:00" + time_b = "2024-07-04T18:09:09.555-07:00" + + bytes_values = BytesValues( + metadata=metadata, + values=[ + BytesValue( + timestamp=to_timestamp_pb(time_a), + value=b"abc", + ), + BytesValue( + timestamp=to_timestamp_pb(time_b), + value=b"def", + ), + ], + ) + + raw_values = Any() + raw_values.Pack(bytes_values) + + deserialized_data = try_deserialize_channel_data(raw_values) + + assert len(deserialized_data) == 1 + + metadata, time_series = deserialized_data[0] + + assert metadata.data_type == CHANNEL_DATA_TYPE_BYTES + assert metadata.channel.name == "bytes-channel" + assert len(time_series.time_column) == 2 + assert len(time_series.value_column) == 2 + assert time_series.value_column[0] == b"abc" + assert time_series.value_column[1] == b"def" + assert time_series.time_column[0] == to_timestamp_nanos(time_a) + assert time_series.time_column[1] == to_timestamp_nanos(time_b) + + def test_try_deserialize_channel_data_bit_field_elements(): metadata = Metadata( data_type=CHANNEL_DATA_TYPE_BIT_FIELD,