Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions examples/all_types/all_types_panel.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""A Streamlit visualization panel for the all_types.py example script."""

import datetime as dt
from enum import Enum, Flag

import streamlit as st
Expand Down Expand Up @@ -35,6 +36,13 @@
st.number_input(label=name, value=default_value, key=name, format="%.2f")
elif isinstance(default_value, str):
st.text_input(label=name, value=default_value, key=name)
elif isinstance(default_value, dt.datetime):
st.time_input(label=name, value=default_value, key=f"{name}_time")
st.date_input(label=name, value=default_value, key=f"{name}_date")
elif isinstance(default_value, dt.date):
st.date_input(label=name, value=default_value, key=name)
elif isinstance(default_value, dt.time):
st.time_input(label=name, value=default_value, key=name)

with col3:
st.write(panel.get_value(name, default_value=default_value))
2 changes: 2 additions & 0 deletions examples/all_types/define_types.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""Define types."""

import datetime as dt
import enum

import numpy as np
Expand Down Expand Up @@ -70,6 +71,7 @@ class MyMixedEnum(enum.Enum):
"float": 13.12,
"int": 42,
"str": "sample string",
"dt_datetime": dt.datetime.now(),
# supported enum and flag types
"intflags": MyIntFlags.VALUE1 | MyIntFlags.VALUE4,
"intenum": MyIntEnum.VALUE20,
Expand Down
2 changes: 2 additions & 0 deletions src/nipanel/_convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from nipanel.converters.builtin import (
BoolConverter,
BytesConverter,
DTDateTimeConverter,
FloatConverter,
IntConverter,
StrConverter,
Expand All @@ -37,6 +38,7 @@
FloatConverter(),
IntConverter(),
StrConverter(),
DTDateTimeConverter(),
# Containers next
BoolCollectionConverter(),
BytesCollectionConverter(),
Expand Down
27 changes: 26 additions & 1 deletion src/nipanel/converters/builtin.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
"""Classes to convert between builtin Python scalars and containers."""

import datetime as dt
from collections.abc import Collection
from typing import Type

from google.protobuf import wrappers_pb2
from google.protobuf import timestamp_pb2, wrappers_pb2
from ni.panels.v1 import panel_types_pb2

from nipanel.converters import Converter
Expand Down Expand Up @@ -119,6 +120,30 @@ def to_python_value(self, protobuf_message: wrappers_pb2.StringValue) -> str:
return protobuf_message.value


class DTDateTimeConverter(Converter[dt.datetime, timestamp_pb2.Timestamp]):
"""A converter for datetime.datetime types."""

@property
def python_typename(self) -> str:
"""The Python type that this converter handles."""
return dt.datetime.__name__

@property
def protobuf_message(self) -> Type[timestamp_pb2.Timestamp]:
"""The type-specific protobuf message for the Python type."""
return timestamp_pb2.Timestamp

def to_protobuf_message(self, python_value: dt.datetime) -> timestamp_pb2.Timestamp:
"""Convert the Python dt.datetime to a protobuf timestamp_pb2.Timestamp."""
ts = self.protobuf_message()
ts.FromDatetime(python_value)
return ts

def to_python_value(self, protobuf_message: timestamp_pb2.Timestamp) -> dt.datetime:
"""Convert the protobuf timestamp_pb2.Timestamp to a Python dt.datetime."""
return protobuf_message.ToDatetime()


class BoolCollectionConverter(Converter[Collection[bool], panel_types_pb2.BoolCollection]):
"""A converter for a Collection of bools."""

Expand Down
26 changes: 25 additions & 1 deletion tests/unit/test_convert.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import datetime as dt
from typing import Any, Collection, Union

import numpy as np
import pytest
from google.protobuf import any_pb2, wrappers_pb2
from google.protobuf import any_pb2, timestamp_pb2, wrappers_pb2
from google.protobuf.message import Message
from ni.panels.v1 import panel_types_pb2
from ni.protobuf.types.scalar_pb2 import ScalarData
Expand Down Expand Up @@ -53,6 +54,7 @@
(tests.types.MixinIntEnum.VALUE11, "int"),
(tests.types.MyStrEnum.VALUE1, "str"),
(tests.types.MixinStrEnum.VALUE11, "str"),
(dt.datetime.now(), "datetime"),
([False, False], "Collection.bool"),
([b"mystr", b"mystr"], "Collection.bytes"),
([456.2, 1.0], "Collection.float"),
Expand Down Expand Up @@ -123,6 +125,16 @@ def test___python_builtin_scalar___to_any___valid_wrapperpb2_value(
assert unpack_dest.value == expected_value


def test___python_datetime_datetime___to_any___valid_timestamppb2_value() -> None:
expected_value = dt.datetime.now()
result = nipanel._convert.to_any(expected_value)
unpack_dest = timestamp_pb2.Timestamp()
_assert_any_and_unpack(result, unpack_dest)

assert isinstance(unpack_dest, timestamp_pb2.Timestamp)
assert unpack_dest.ToDatetime() == expected_value


@pytest.mark.parametrize(
"proto_type, default_value, expected_value",
[
Expand Down Expand Up @@ -175,6 +187,18 @@ def test___wrapperpb2_value___from_any___valid_python_value(
assert result == expected_value


def test___timestamppb2_timestamp___from_any___valid_python_value() -> None:
expected_value = dt.datetime.now()
pb_value = timestamp_pb2.Timestamp()
pb_value.FromDatetime(expected_value)
packed_any = _pack_into_any(pb_value)

result = nipanel._convert.from_any(packed_any)

assert isinstance(result, dt.datetime)
assert result == expected_value


@pytest.mark.parametrize(
"proto_type, expected_value",
[
Expand Down
2 changes: 0 additions & 2 deletions tests/unit/test_streamlit_panel.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import enum
from datetime import datetime

import grpc
import pytest
Expand Down Expand Up @@ -312,7 +311,6 @@ def test___enum_type___set_value___gets_same_value(
@pytest.mark.parametrize(
"value_payload",
[
datetime.now(),
lambda x: x + 1,
[1, "string"],
["string", []],
Expand Down