Skip to content

Commit 610bc05

Browse files
author
Michael Johansen
committed
Add scalar.proto, generate stubs, implement converter, and add unit tests.
Signed-off-by: Michael Johansen <[email protected]>
1 parent 541273f commit 610bc05

File tree

9 files changed

+403
-3
lines changed

9 files changed

+403
-3
lines changed

poetry.lock

Lines changed: 91 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
syntax = "proto3";
2+
3+
package ni.protobuf.types;
4+
5+
option csharp_namespace = "NationalInstruments.Protobuf.Types";
6+
option go_package = "types";
7+
option java_multiple_files = true;
8+
option java_outer_classname = "ScalarProto";
9+
option java_package = "com.ni.protobuf.types";
10+
option objc_class_prefix = "NIPT";
11+
option php_namespace = "NI\\PROTOBUF\\TYPES";
12+
option ruby_package = "NI::Protobuf::Types";
13+
14+
message ScalarData {
15+
string units = 1;
16+
17+
oneof value {
18+
double double_value = 2;
19+
int32 int32_value = 3;
20+
bool bool_value = 4;
21+
string string_value = 5;
22+
}
23+
}

pyproject.toml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ protobuf = {version=">=4.21"}
1313
ni-measurement-plugin-sdk = {version=">=2.3"}
1414
typing-extensions = ">=4.13.2"
1515
streamlit = ">=1.24"
16+
# Temporary dependency until ni-apis-python is available.
17+
nitypes = ">=0.1.0dev1"
1618

1719
[tool.poetry.group.dev.dependencies]
1820
types-grpcio = ">=1.0"
@@ -52,10 +54,10 @@ requires = ["poetry-core>=1.8.0"]
5254
build-backend = "poetry.core.masonry.api"
5355

5456
[tool.ni-python-styleguide]
55-
extend_exclude = ".tox,docs,src/ni/pythonpanel/v1"
57+
extend_exclude = ".tox,docs,src/ni/pythonpanel/v1,src/ni/protobuf/types/"
5658

5759
[tool.black]
58-
extend-exclude = '\.tox/|docs/|src/ni/pythonpanel/v1/'
60+
extend-exclude = '\.tox/|docs/|src/ni/pythonpanel/v1/|src/ni/protobuf/types/'
5961
line-length = 100
6062

6163
[tool.mypy]

src/ni/protobuf/types/scalar_pb2.py

Lines changed: 26 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
"""
2+
@generated by mypy-protobuf. Do not edit manually!
3+
isort:skip_file
4+
"""
5+
6+
import builtins
7+
import google.protobuf.descriptor
8+
import google.protobuf.message
9+
import typing
10+
11+
DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
12+
13+
@typing.final
14+
class ScalarData(google.protobuf.message.Message):
15+
DESCRIPTOR: google.protobuf.descriptor.Descriptor
16+
17+
UNITS_FIELD_NUMBER: builtins.int
18+
DOUBLE_VALUE_FIELD_NUMBER: builtins.int
19+
INT32_VALUE_FIELD_NUMBER: builtins.int
20+
BOOL_VALUE_FIELD_NUMBER: builtins.int
21+
STRING_VALUE_FIELD_NUMBER: builtins.int
22+
units: builtins.str
23+
double_value: builtins.float
24+
int32_value: builtins.int
25+
bool_value: builtins.bool
26+
string_value: builtins.str
27+
def __init__(
28+
self,
29+
*,
30+
units: builtins.str = ...,
31+
double_value: builtins.float = ...,
32+
int32_value: builtins.int = ...,
33+
bool_value: builtins.bool = ...,
34+
string_value: builtins.str = ...,
35+
) -> None: ...
36+
def HasField(self, field_name: typing.Literal["bool_value", b"bool_value", "double_value", b"double_value", "int32_value", b"int32_value", "string_value", b"string_value", "value", b"value"]) -> builtins.bool: ...
37+
def ClearField(self, field_name: typing.Literal["bool_value", b"bool_value", "double_value", b"double_value", "int32_value", b"int32_value", "string_value", b"string_value", "units", b"units", "value", b"value"]) -> None: ...
38+
def WhichOneof(self, oneof_group: typing.Literal["value", b"value"]) -> typing.Literal["double_value", "int32_value", "bool_value", "string_value"] | None: ...
39+
40+
global___ScalarData = ScalarData
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
2+
"""Client and server classes corresponding to protobuf-defined services."""
3+
import grpc
4+
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
"""
2+
@generated by mypy-protobuf. Do not edit manually!
3+
isort:skip_file
4+
"""
5+
6+
import abc
7+
import collections.abc
8+
import grpc
9+
import grpc.aio
10+
import typing
11+
12+
_T = typing.TypeVar("_T")
13+
14+
class _MaybeAsyncIterator(collections.abc.AsyncIterator[_T], collections.abc.Iterator[_T], metaclass=abc.ABCMeta): ...
15+
16+
class _ServicerContext(grpc.ServicerContext, grpc.aio.ServicerContext): # type: ignore[misc, type-arg]
17+
...
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
"""Classes to convert between measurement specific protobuf types and containers."""
2+
3+
from typing import Any, Type
4+
5+
from ni.protobuf.types import scalar_pb2
6+
from nitypes.scalar import Scalar
7+
8+
from nipanel.converters import Converter
9+
10+
11+
class ScalarConverter(Converter[Scalar[Any], scalar_pb2.ScalarData]):
12+
"""A converter for Scalar objects."""
13+
14+
@property
15+
def python_typename(self) -> str:
16+
"""The Python type that this converter handles."""
17+
return Scalar.__name__
18+
19+
@property
20+
def protobuf_message(self) -> Type[scalar_pb2.ScalarData]:
21+
"""The type-specific protobuf message for the Python type."""
22+
return scalar_pb2.ScalarData
23+
24+
def to_protobuf_message(self, python_value: Scalar[Any]) -> scalar_pb2.ScalarData:
25+
"""Convert the Python Scalar to a protobuf scalar_pb2.ScalarData."""
26+
message = self.protobuf_message()
27+
message.units = python_value.units
28+
if isinstance(python_value.value, bool):
29+
message.bool_value = python_value.value
30+
elif isinstance(python_value.value, int):
31+
message.int32_value = python_value.value
32+
elif isinstance(python_value.value, float):
33+
message.double_value = python_value.value
34+
elif isinstance(python_value.value, str):
35+
message.string_value = python_value.value
36+
else:
37+
raise TypeError(f"Unexpected type for python_value.value: {type(python_value.value)}")
38+
39+
return message
40+
41+
def to_python_value(self, protobuf_value: scalar_pb2.ScalarData) -> Scalar[Any]:
42+
"""Convert the protobuf message to a Python Scalar."""
43+
if protobuf_value.units is None:
44+
raise ValueError("protobuf.units cannot be None.")
45+
46+
pb_type = protobuf_value.WhichOneof("value")
47+
if pb_type == "bool_value":
48+
return Scalar(protobuf_value.bool_value, protobuf_value.units)
49+
elif pb_type == "int32_value":
50+
return Scalar(protobuf_value.int32_value, protobuf_value.units)
51+
elif pb_type == "double_value":
52+
return Scalar(protobuf_value.double_value, protobuf_value.units)
53+
elif pb_type == "string_value":
54+
return Scalar(protobuf_value.string_value, protobuf_value.units)
55+
else:
56+
raise ValueError(f"Unexpected value for protobuf_value.WhichOneOf: {pb_type}")

0 commit comments

Comments
 (0)