Skip to content

Commit 8b94686

Browse files
author
Michael Johansen
committed
Address review feedback around timing conversion.
Signed-off-by: Michael Johansen <[email protected]>
1 parent 68ab6a0 commit 8b94686

File tree

2 files changed

+67
-14
lines changed

2 files changed

+67
-14
lines changed

src/nipanel/converters/protobuf_types.py

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
"""Classes to convert between measurement specific protobuf types and containers."""
22

33
import collections.abc
4-
import datetime as dt
54
from typing import Type, Union
65

6+
import hightime as ht
77
import numpy
88
from ni.protobuf.types import scalar_pb2
99
from ni_measurement_plugin_sdk_service._internal.stubs.ni.protobuf.types.precision_timestamp_pb2 import (
@@ -15,7 +15,13 @@
1515
)
1616
from nitypes.bintime import DateTime, TimeValueTuple
1717
from nitypes.scalar import Scalar
18-
from nitypes.waveform import AnalogWaveform, ExtendedPropertyDictionary, NoneScaleMode, Timing
18+
from nitypes.waveform import (
19+
AnalogWaveform,
20+
ExtendedPropertyDictionary,
21+
NoneScaleMode,
22+
SampleIntervalMode,
23+
Timing,
24+
)
1925
from typing_extensions import TypeAlias
2026

2127
from nipanel.converters import Converter
@@ -93,14 +99,32 @@ def to_python_value(
9399
self, protobuf_value: DoubleAnalogWaveform
94100
) -> AnalogWaveform[numpy.float64]:
95101
"""Convert the protobuf DoubleAnalogWaveform to a Python AnalogWaveform."""
96-
pt_converter = PrecisionTimestampConverter()
97-
bin_datetime = pt_converter.to_python_value(protobuf_value.t0)
98-
timestamp = bin_datetime._to_datetime_datetime()
99-
sample_interval = dt.timedelta(seconds=protobuf_value.dt)
100-
timing = Timing.create_with_regular_interval(
101-
sample_interval,
102-
timestamp,
103-
)
102+
if (
103+
not protobuf_value.dt
104+
and not protobuf_value.t0.seconds
105+
and not protobuf_value.t0.fractional_seconds
106+
):
107+
# If both dt and t0 and unset, use Timing.empty.
108+
timing = Timing.empty
109+
else:
110+
# Timestamp
111+
pt_converter = PrecisionTimestampConverter()
112+
bin_datetime = pt_converter.to_python_value(protobuf_value.t0)
113+
timestamp = bin_datetime._to_datetime_datetime()
114+
115+
# Sample Interval
116+
if not protobuf_value.dt:
117+
sample_interval_mode = SampleIntervalMode.NONE
118+
sample_interval = None
119+
else:
120+
sample_interval_mode = SampleIntervalMode.REGULAR
121+
sample_interval = ht.timedelta(seconds=protobuf_value.dt)
122+
123+
timing = Timing(
124+
sample_interval_mode=sample_interval_mode,
125+
timestamp=timestamp,
126+
sample_interval=sample_interval,
127+
)
104128

105129
extended_properties = {}
106130
for key, value in protobuf_value.attributes.items():

tests/unit/test_protobuf_type_conversion.py

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
)
1313
from nitypes.bintime import DateTime
1414
from nitypes.scalar import Scalar
15-
from nitypes.waveform import AnalogWaveform, NoneScaleMode, Timing
15+
from nitypes.waveform import AnalogWaveform, NoneScaleMode, SampleIntervalMode, Timing
1616

1717
from nipanel.converters.protobuf_types import (
1818
DoubleAnalogWaveformConverter,
@@ -26,6 +26,7 @@
2626
# ========================================================
2727
def test___default_analog_waveform___convert___valid_protobuf() -> None:
2828
analog_waveform = AnalogWaveform()
29+
2930
converter = DoubleAnalogWaveformConverter()
3031
dbl_analog_waveform = converter.to_protobuf_message(analog_waveform)
3132

@@ -77,7 +78,6 @@ def test___analog_waveform_with_standard_timing___convert___valid_protobuf() ->
7778
dbl_analog_waveform = converter.to_protobuf_message(analog_waveform)
7879

7980
assert dbl_analog_waveform.dt == 1.0
80-
8181
bin_dt = DateTime(t0_dt)
8282
pt_converter = PrecisionTimestampConverter()
8383
converted_t0 = pt_converter.to_protobuf_message(bin_dt)
@@ -89,18 +89,19 @@ def test___analog_waveform_with_standard_timing___convert___valid_protobuf() ->
8989
# ========================================================
9090
def test___default_dbl_analog_wfm___convert___valid_python_object() -> None:
9191
dbl_analog_wfm = DoubleAnalogWaveform()
92+
9293
converter = DoubleAnalogWaveformConverter()
9394
analog_waveform = converter.to_python_value(dbl_analog_wfm)
9495

9596
assert not analog_waveform.extended_properties
96-
assert analog_waveform.timing.sample_interval == dt.timedelta()
97-
assert analog_waveform.timing.start_time == dt.datetime(1904, 1, 1, tzinfo=dt.timezone.utc)
97+
assert analog_waveform.timing == Timing.empty
9898
assert analog_waveform.scaled_data.size == 0
9999
assert analog_waveform.scale_mode == NoneScaleMode()
100100

101101

102102
def test___dbl_analog_wfm_with_y_data___convert___valid_python_object() -> None:
103103
dbl_analog_wfm = DoubleAnalogWaveform(y_data=[1.0, 2.0, 3.0])
104+
104105
converter = DoubleAnalogWaveformConverter()
105106
analog_waveform = converter.to_python_value(dbl_analog_wfm)
106107

@@ -113,6 +114,7 @@ def test___dbl_analog_wfm_with_attributes___convert___valid_python_object() -> N
113114
"NI_UnitDescription": WaveformAttributeValue(string_value="Volts"),
114115
}
115116
dbl_analog_wfm = DoubleAnalogWaveform(attributes=attributes)
117+
116118
converter = DoubleAnalogWaveformConverter()
117119
analog_waveform = converter.to_python_value(dbl_analog_wfm)
118120

@@ -125,11 +127,38 @@ def test___dbl_analog_wfm_with_timing___convert___valid_python_object() -> None:
125127
pt_converter = PrecisionTimestampConverter()
126128
t0_pt = pt_converter.to_protobuf_message(t0_dt)
127129
dbl_analog_wfm = DoubleAnalogWaveform(t0=t0_pt, dt=0.1, y_data=[1.0, 2.0, 3.0])
130+
128131
converter = DoubleAnalogWaveformConverter()
129132
analog_waveform = converter.to_python_value(dbl_analog_wfm)
130133

131134
assert analog_waveform.timing.start_time == t0_dt._to_datetime_datetime()
132135
assert analog_waveform.timing.sample_interval == dt.timedelta(seconds=0.1)
136+
assert analog_waveform.timing.sample_interval_mode == SampleIntervalMode.REGULAR
137+
138+
139+
def test___dbl_analog_wfm_with_timing_no_t0___convert___valid_python_object() -> None:
140+
dbl_analog_wfm = DoubleAnalogWaveform(dt=0.1, y_data=[1.0, 2.0, 3.0])
141+
142+
converter = DoubleAnalogWaveformConverter()
143+
analog_waveform = converter.to_python_value(dbl_analog_wfm)
144+
145+
assert analog_waveform.timing.start_time == dt.datetime(1904, 1, 1, tzinfo=dt.timezone.utc)
146+
assert analog_waveform.timing.sample_interval == dt.timedelta(seconds=0.1)
147+
assert analog_waveform.timing.sample_interval_mode == SampleIntervalMode.REGULAR
148+
149+
150+
def test___dbl_analog_wfm_with_timing_no_dt___convert___valid_python_object() -> None:
151+
t0_dt = DateTime(2020, 5, 5, tzinfo=dt.timezone.utc)
152+
pt_converter = PrecisionTimestampConverter()
153+
t0_pt = pt_converter.to_protobuf_message(t0_dt)
154+
dbl_analog_wfm = DoubleAnalogWaveform(t0=t0_pt, y_data=[1.0, 2.0, 3.0])
155+
156+
converter = DoubleAnalogWaveformConverter()
157+
analog_waveform = converter.to_python_value(dbl_analog_wfm)
158+
159+
assert analog_waveform.timing.start_time == t0_dt._to_datetime_datetime()
160+
assert not analog_waveform.timing.has_sample_interval
161+
assert analog_waveform.timing.sample_interval_mode == SampleIntervalMode.NONE
133162

134163

135164
# ========================================================

0 commit comments

Comments
 (0)