Skip to content

Commit a3650cb

Browse files
author
Michael Johansen
committed
More review feedback and refactors.
Signed-off-by: Michael Johansen <[email protected]>
1 parent 23d81fe commit a3650cb

File tree

4 files changed

+60
-60
lines changed

4 files changed

+60
-60
lines changed

poetry.lock

Lines changed: 11 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ pyright = { version = ">=1.1.400", extras = ["nodejs"] }
3030
pytest = ">=7.2"
3131
pytest-cov = ">=4.0"
3232
pytest-mock = ">=3.0"
33+
hightime = { git = "https://github.com/ni/hightime.git" }
3334

3435
[tool.poetry.group.codegen.dependencies]
3536
grpcio-tools = [

src/nipanel/converters/protobuf_types.py

Lines changed: 47 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
from typing import Type, Union
66

77
import hightime as ht
8-
import numpy
8+
import nitypes.bintime as bt
9+
import numpy as np
910
from ni.protobuf.types import scalar_pb2
1011
from ni_measurement_plugin_sdk_service._internal.stubs.ni.protobuf.types.precision_timestamp_pb2 import (
1112
PrecisionTimestamp,
@@ -14,12 +15,12 @@
1415
DoubleAnalogWaveform,
1516
WaveformAttributeValue,
1617
)
17-
from nitypes.bintime import DateTime, TimeValueTuple
1818
from nitypes.scalar import Scalar
1919
from nitypes.time import convert_datetime
2020
from nitypes.waveform import (
2121
AnalogWaveform,
2222
ExtendedPropertyDictionary,
23+
ExtendedPropertyValue,
2324
NoneScaleMode,
2425
SampleIntervalMode,
2526
Timing,
@@ -37,9 +38,13 @@
3738
}
3839

3940

40-
class DoubleAnalogWaveformConverter(Converter[AnalogWaveform[numpy.float64], DoubleAnalogWaveform]):
41+
class DoubleAnalogWaveformConverter(Converter[AnalogWaveform[np.float64], DoubleAnalogWaveform]):
4142
"""A converter for AnalogWaveform types with scaled data (double)."""
4243

44+
def __init__(self) -> None:
45+
"""Initialize a DoubleAnalogWaveformConverter object."""
46+
self._pt_converter = PrecisionTimestampConverter()
47+
4348
@property
4449
def python_typename(self) -> str:
4550
"""The Python type that this converter handles."""
@@ -50,16 +55,13 @@ def protobuf_message(self) -> Type[DoubleAnalogWaveform]:
5055
"""The type-specific protobuf message for the Python type."""
5156
return DoubleAnalogWaveform
5257

53-
def to_protobuf_message(
54-
self, python_value: AnalogWaveform[numpy.float64]
55-
) -> DoubleAnalogWaveform:
58+
def to_protobuf_message(self, python_value: AnalogWaveform[np.float64]) -> DoubleAnalogWaveform:
5659
"""Convert the Python AnalogWaveform to a protobuf DoubleAnalogWaveform."""
5760
if python_value.timing.has_timestamp:
58-
pt_converter = PrecisionTimestampConverter()
59-
bin_datetime = DateTime(python_value.timing.start_time)
60-
precision_timestamp = pt_converter.to_protobuf_message(bin_datetime)
61+
bin_datetime = convert_datetime(bt.DateTime, python_value.timing.start_time)
62+
precision_timestamp = self._pt_converter.to_protobuf_message(bin_datetime)
6163
else:
62-
precision_timestamp = PrecisionTimestamp(seconds=0, fractional_seconds=0)
64+
precision_timestamp = None
6365

6466
if python_value.timing.has_sample_interval:
6567
time_interval = python_value.timing.sample_interval.total_seconds()
@@ -79,48 +81,41 @@ def _extended_properties_to_attributes(
7981
self,
8082
extended_properties: ExtendedPropertyDictionary,
8183
) -> collections.abc.Mapping[str, WaveformAttributeValue]:
82-
attributes = {}
83-
for key, value in extended_properties.items():
84-
attr_value = WaveformAttributeValue()
85-
if isinstance(value, bool):
86-
attr_value.bool_value = value
87-
elif isinstance(value, int):
88-
attr_value.integer_value = value
89-
elif isinstance(value, float):
90-
attr_value.double_value = value
91-
elif isinstance(value, str):
92-
attr_value.string_value = value
93-
else:
94-
raise TypeError(f"Unexpected type for extended property value {type(value)}")
95-
96-
attributes[key] = attr_value
84+
return {key: self._value_to_attribute(value) for key, value in extended_properties.items()}
85+
86+
def _value_to_attribute(self, value: ExtendedPropertyValue) -> WaveformAttributeValue:
87+
attr_value = WaveformAttributeValue()
88+
if isinstance(value, bool):
89+
attr_value.bool_value = value
90+
elif isinstance(value, int):
91+
attr_value.integer_value = value
92+
elif isinstance(value, float):
93+
attr_value.double_value = value
94+
elif isinstance(value, str):
95+
attr_value.string_value = value
96+
else:
97+
raise TypeError(f"Unexpected type for extended property value {type(value)}")
9798

98-
return attributes
99+
return attr_value
99100

100-
def to_python_value(
101-
self, protobuf_value: DoubleAnalogWaveform
102-
) -> AnalogWaveform[numpy.float64]:
101+
def to_python_value(self, protobuf_message: DoubleAnalogWaveform) -> AnalogWaveform[np.float64]:
103102
"""Convert the protobuf DoubleAnalogWaveform to a Python AnalogWaveform."""
104-
if (
105-
not protobuf_value.dt
106-
and not protobuf_value.t0.seconds
107-
and not protobuf_value.t0.fractional_seconds
108-
):
109-
# If both dt and t0 and unset, use Timing.empty.
103+
if not protobuf_message.dt and not protobuf_message.HasField("t0"):
104+
# If both dt and t0 are unset, use Timing.empty.
110105
timing = Timing.empty
111106
else:
112107
# Timestamp
113108
pt_converter = PrecisionTimestampConverter()
114-
bin_datetime = pt_converter.to_python_value(protobuf_value.t0)
109+
bin_datetime = pt_converter.to_python_value(protobuf_message.t0)
115110
timestamp = convert_datetime(dt.datetime, bin_datetime)
116111

117112
# Sample Interval
118-
if not protobuf_value.dt:
113+
if not protobuf_message.dt:
119114
sample_interval_mode = SampleIntervalMode.NONE
120115
sample_interval = None
121116
else:
122117
sample_interval_mode = SampleIntervalMode.REGULAR
123-
sample_interval = ht.timedelta(seconds=protobuf_value.dt)
118+
sample_interval = ht.timedelta(seconds=protobuf_message.dt)
124119

125120
timing = Timing(
126121
sample_interval_mode=sample_interval_mode,
@@ -129,46 +124,48 @@ def to_python_value(
129124
)
130125

131126
extended_properties = {}
132-
for key, value in protobuf_value.attributes.items():
127+
for key, value in protobuf_message.attributes.items():
133128
attr_type = value.WhichOneof("attribute")
134129
extended_properties[key] = getattr(value, str(attr_type))
135130

136-
data_list = list(protobuf_value.y_data)
131+
data_array = np.array(protobuf_message.y_data)
137132
return AnalogWaveform(
138-
sample_count=len(data_list),
139-
dtype=numpy.float64,
140-
raw_data=numpy.array(data_list),
133+
sample_count=data_array.size,
134+
dtype=np.float64,
135+
raw_data=data_array,
141136
start_index=0,
142-
capacity=len(data_list),
137+
capacity=data_array.size,
143138
extended_properties=extended_properties,
144139
copy_extended_properties=True,
145140
timing=timing,
146141
scale_mode=NoneScaleMode(),
147142
)
148143

149144

150-
class PrecisionTimestampConverter(Converter[DateTime, PrecisionTimestamp]):
145+
class PrecisionTimestampConverter(Converter[bt.DateTime, PrecisionTimestamp]):
151146
"""A converter for bintime.DateTime types."""
152147

153148
@property
154149
def python_typename(self) -> str:
155150
"""The Python type that this converter handles."""
156-
return DateTime.__name__
151+
return bt.DateTime.__name__
157152

158153
@property
159154
def protobuf_message(self) -> Type[PrecisionTimestamp]:
160155
"""The type-specific protobuf message for the Python type."""
161156
return PrecisionTimestamp
162157

163-
def to_protobuf_message(self, python_value: DateTime) -> PrecisionTimestamp:
158+
def to_protobuf_message(self, python_value: bt.DateTime) -> PrecisionTimestamp:
164159
"""Convert the Python DateTime to a protobuf PrecisionTimestamp."""
165160
seconds, fractional_seconds = python_value.to_tuple()
166161
return self.protobuf_message(seconds=seconds, fractional_seconds=fractional_seconds)
167162

168-
def to_python_value(self, protobuf_value: PrecisionTimestamp) -> DateTime:
163+
def to_python_value(self, protobuf_message: PrecisionTimestamp) -> bt.DateTime:
169164
"""Convert the protobuf PrecisionTimestamp to a Python DateTime."""
170-
time_value_tuple = TimeValueTuple(protobuf_value.seconds, protobuf_value.fractional_seconds)
171-
return DateTime.from_tuple(time_value_tuple)
165+
time_value_tuple = bt.TimeValueTuple(
166+
protobuf_message.seconds, protobuf_message.fractional_seconds
167+
)
168+
return bt.DateTime.from_tuple(time_value_tuple)
172169

173170

174171
class ScalarConverter(Converter[Scalar[_AnyScalarType], scalar_pb2.ScalarData]):

tests/unit/test_protobuf_type_conversion.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,6 @@
33
import numpy
44
import pytest
55
from ni.protobuf.types.scalar_pb2 import ScalarData
6-
from ni_measurement_plugin_sdk_service._internal.stubs.ni.protobuf.types.precision_timestamp_pb2 import (
7-
PrecisionTimestamp,
8-
)
96
from ni_measurement_plugin_sdk_service._internal.stubs.ni.protobuf.types.waveform_pb2 import (
107
DoubleAnalogWaveform,
118
WaveformAttributeValue,
@@ -32,7 +29,7 @@ def test___default_analog_waveform___convert___valid_protobuf() -> None:
3229

3330
assert not dbl_analog_waveform.attributes
3431
assert dbl_analog_waveform.dt == 0
35-
assert dbl_analog_waveform.t0 == PrecisionTimestamp(seconds=0, fractional_seconds=0)
32+
assert not dbl_analog_waveform.HasField("t0")
3633
assert list(dbl_analog_waveform.y_data) == []
3734

3835

0 commit comments

Comments
 (0)