Skip to content

Commit 9af630d

Browse files
author
Michael Johansen
committed
Add a converter for dt.timedelta.
Signed-off-by: Michael Johansen <[email protected]>
1 parent 5ade5a6 commit 9af630d

File tree

4 files changed

+51
-2
lines changed

4 files changed

+51
-2
lines changed

examples/all_types/define_types.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ class MyMixedEnum(enum.Enum):
7272
"int": 42,
7373
"str": "sample string",
7474
"dt_datetime": dt.datetime.now(),
75+
"dt_timedelta": dt.timedelta(weeks=2, days=5, minutes=12, milliseconds=75),
7576
# supported enum and flag types
7677
"intflags": MyIntFlags.VALUE1 | MyIntFlags.VALUE4,
7778
"intenum": MyIntEnum.VALUE20,

src/nipanel/_convert.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
BoolConverter,
1414
BytesConverter,
1515
DTDateTimeConverter,
16+
DTTimeDeltaConverter,
1617
FloatConverter,
1718
IntConverter,
1819
StrConverter,
@@ -39,6 +40,7 @@
3940
IntConverter(),
4041
StrConverter(),
4142
DTDateTimeConverter(),
43+
DTTimeDeltaConverter(),
4244
# Containers next
4345
BoolCollectionConverter(),
4446
BytesCollectionConverter(),

src/nipanel/converters/builtin.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from collections.abc import Collection
55
from typing import Type
66

7-
from google.protobuf import timestamp_pb2, wrappers_pb2
7+
from google.protobuf import duration_pb2, timestamp_pb2, wrappers_pb2
88
from ni.panels.v1 import panel_types_pb2
99

1010
from nipanel.converters import Converter
@@ -144,6 +144,30 @@ def to_python_value(self, protobuf_message: timestamp_pb2.Timestamp) -> dt.datet
144144
return protobuf_message.ToDatetime()
145145

146146

147+
class DTTimeDeltaConverter(Converter[dt.timedelta, duration_pb2.Duration]):
148+
"""A converter for datetime.timedelta types."""
149+
150+
@property
151+
def python_typename(self) -> str:
152+
"""The Python type that this converter handles."""
153+
return dt.timedelta.__name__
154+
155+
@property
156+
def protobuf_message(self) -> Type[duration_pb2.Duration]:
157+
"""The type-specific protobuf message for the Python type."""
158+
return duration_pb2.Duration
159+
160+
def to_protobuf_message(self, python_value: dt.timedelta) -> duration_pb2.Duration:
161+
"""Convert the Python dt.timedelta to a protobuf duration_pb2.Duration."""
162+
dur = self.protobuf_message()
163+
dur.FromTimedelta(python_value)
164+
return dur
165+
166+
def to_python_value(self, protobuf_message: duration_pb2.Duration) -> dt.timedelta:
167+
"""Convert the protobuf timestamp_pb2.Timestamp to a Python dt.timedelta."""
168+
return protobuf_message.ToTimedelta()
169+
170+
147171
class BoolCollectionConverter(Converter[Collection[bool], panel_types_pb2.BoolCollection]):
148172
"""A converter for a Collection of bools."""
149173

tests/unit/test_convert.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
import numpy as np
55
import pytest
6-
from google.protobuf import any_pb2, timestamp_pb2, wrappers_pb2
6+
from google.protobuf import any_pb2, duration_pb2, timestamp_pb2, wrappers_pb2
77
from google.protobuf.message import Message
88
from ni.panels.v1 import panel_types_pb2
99
from ni.protobuf.types.scalar_pb2 import ScalarData
@@ -135,6 +135,16 @@ def test___python_datetime_datetime___to_any___valid_timestamppb2_value() -> Non
135135
assert unpack_dest.ToDatetime() == expected_value
136136

137137

138+
def test___python_datetime_timedelta___to_any___valid_durationpb2_value() -> None:
139+
expected_value = dt.timedelta(days=1, seconds=1, microseconds=1)
140+
result = nipanel._convert.to_any(expected_value)
141+
unpack_dest = duration_pb2.Duration()
142+
_assert_any_and_unpack(result, unpack_dest)
143+
144+
assert isinstance(unpack_dest, duration_pb2.Duration)
145+
assert unpack_dest.ToTimedelta() == expected_value
146+
147+
138148
@pytest.mark.parametrize(
139149
"proto_type, default_value, expected_value",
140150
[
@@ -199,6 +209,18 @@ def test___timestamppb2_timestamp___from_any___valid_python_value() -> None:
199209
assert result == expected_value
200210

201211

212+
def test___durationpb2_timestamp___from_any___valid_python_value() -> None:
213+
expected_value = dt.timedelta(weeks=1, hours=1, minutes=1)
214+
pb_value = duration_pb2.Duration()
215+
pb_value.FromTimedelta(expected_value)
216+
packed_any = _pack_into_any(pb_value)
217+
218+
result = nipanel._convert.from_any(packed_any)
219+
220+
assert isinstance(result, dt.timedelta)
221+
assert result == expected_value
222+
223+
202224
@pytest.mark.parametrize(
203225
"proto_type, expected_value",
204226
[

0 commit comments

Comments
 (0)