Skip to content

Commit 07eef45

Browse files
author
Michael Johansen
committed
Merge from main
Signed-off-by: Michael Johansen <michael.johansen@ni.com>
2 parents 9bd4f59 + 6b261b5 commit 07eef45

File tree

8 files changed

+204
-34
lines changed

8 files changed

+204
-34
lines changed

README.md

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,20 @@
1-
# nipanel-python
2-
Source for the nipanel python package
1+
# Table of Contents
2+
3+
- [Table of Contents](#table-of-contents)
4+
- [About](#about)
5+
- [Operating System Support](#operating-system-support)
6+
- [Python Version Support](#python-version-support)
7+
8+
# About
9+
10+
`nipanel` is a Python package that provides support for creating and controlling measurement and visualization panels.
11+
12+
NI created and supports this package.
13+
14+
## Operating System Support
15+
16+
`nipanel` supports Windows and Linux operating systems.
17+
18+
## Python Version Support
19+
20+
`nipanel` supports CPython 3.9+.

examples/all_types/define_types.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ class MyMixedEnum(enum.Enum):
7979
"ht_datetime": ht.datetime.now(tz=dt.timezone.utc),
8080
"bt_datetime": bt.DateTime.now(tz=dt.timezone.utc),
8181
"dt_timedelta": dt.timedelta(weeks=2, days=5, minutes=12, milliseconds=75),
82+
"ht_timedelta": ht.timedelta(days=5, seconds=25, picoseconds=88),
83+
"bt_timedelta": bt.TimeDelta(seconds=1234.56),
8284
# supported enum and flag types
8385
"intflags": MyIntFlags.VALUE1 | MyIntFlags.VALUE4,
8486
"intenum": MyIntEnum.VALUE20,

poetry.lock

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

pyproject.toml

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,32 @@
11
[project]
22
name = "nipanel"
33
version = "0.1.0-dev1"
4-
description = "NI Panel Python API"
4+
license = "MIT"
5+
description = "NI Panel client for Python"
56
authors = [{name = "NI", email = "opensource@ni.com"}]
7+
maintainers = [
8+
{name = "Mike Prosser", email = "mike.prosser@emerson.com"},
9+
{name = "Johann Scholtz", email = "johann.scholtz@emerson.com"},
10+
]
611
readme = "README.md"
12+
keywords = ["nipanel", "panels"]
13+
classifiers = [
14+
"Development Status :: 3 - Alpha",
15+
"Intended Audience :: Developers",
16+
"Intended Audience :: Manufacturing",
17+
"Intended Audience :: Science/Research",
18+
"License :: OSI Approved :: MIT License",
19+
"Operating System :: Microsoft :: Windows",
20+
"Operating System :: POSIX",
21+
"Programming Language :: Python :: 3",
22+
"Programming Language :: Python :: 3.9",
23+
"Programming Language :: Python :: 3.10",
24+
"Programming Language :: Python :: 3.11",
25+
"Programming Language :: Python :: 3.12",
26+
"Programming Language :: Python :: 3.13",
27+
"Programming Language :: Python :: Implementation :: CPython",
28+
]
29+
requires-python = ">=3.9"
730
dynamic = ["dependencies"]
831

932
[project.urls]
@@ -24,7 +47,7 @@ numpy = ">=1.22"
2447
debugpy = ">=1.8.1"
2548
ni-grpc-extensions = { version = ">=0.1.0.dev1", allow-prereleases = true }
2649
ni-measurementlink-discovery-v1-client = { version = ">=0.1.0dev0", allow-prereleases = true }
27-
ni-protobuf-types = { version = ">=0.1.0dev3", allow-prereleases = true }
50+
ni-protobuf-types = { version = ">=0.1.0dev4", allow-prereleases = true }
2851
ni-panels-v1-proto = { version = ">=0.1.0dev1", allow-prereleases = true }
2952

3053
[tool.poetry.group.dev.dependencies]

src/nipanel/_convert.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,9 @@
2222
StrConverter,
2323
)
2424
from nipanel.converters.protobuf_types import (
25-
BoolCollectionConverter,
2625
BTDateTimeConverter,
26+
BTTimeDeltaConverter,
27+
BoolCollectionConverter,
2728
BytesCollectionConverter,
2829
DigitalWaveformConverter,
2930
Double2DArrayConverter,
@@ -32,6 +33,7 @@
3233
DoubleSpectrumConverter,
3334
FloatCollectionConverter,
3435
HTDateTimeConverter,
36+
HTTimeDeltaConverter,
3537
Int16AnalogWaveformConverter,
3638
Int16ComplexWaveformConverter,
3739
IntCollectionConverter,
@@ -54,6 +56,7 @@
5456
DTTimeDeltaConverter(),
5557
# Protobuf Types
5658
BTDateTimeConverter(),
59+
BTTimeDeltaConverter(),
5760
BoolCollectionConverter(),
5861
BytesCollectionConverter(),
5962
DigitalWaveformConverter(),
@@ -63,6 +66,7 @@
6366
DoubleSpectrumConverter(),
6467
FloatCollectionConverter(),
6568
HTDateTimeConverter(),
69+
HTTimeDeltaConverter(),
6670
Int16AnalogWaveformConverter(),
6771
Int16ComplexWaveformConverter(),
6872
IntCollectionConverter(),

src/nipanel/_panel_value_accessor.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import nitypes.bintime as bt
1111
from ni.measurementlink.discovery.v1.client import DiscoveryClient
1212
from ni_grpc_extensions.channelpool import GrpcChannelPool
13-
from nitypes.time import convert_datetime
13+
from nitypes.time import convert_datetime, convert_timedelta
1414

1515
from nipanel._panel_client import _PanelClient
1616

@@ -85,11 +85,17 @@ def get_value(self, value_id: str, default_value: _T | None = None) -> _T | obje
8585
enum_type = type(default_value)
8686
return enum_type(value)
8787

88-
# The grpc converter always converts PrecisionTimestamp into bt.DateTime, so
89-
# we need to handle the case where they provide an ht.datetime default by
90-
# converting to hightime.
91-
if isinstance(default_value, ht.datetime) and isinstance(value, bt.DateTime):
92-
return convert_datetime(ht.datetime, value)
88+
# The grpc converter always converts PrecisionTimestamp into ht.datetime, so
89+
# we need to handle the case where they provide a bt.DateTime default by
90+
# converting to bintime.
91+
if isinstance(default_value, bt.DateTime) and isinstance(value, ht.datetime):
92+
return convert_datetime(bt.DateTime, value)
93+
94+
# The grpc converter always converts PrecisionDuration into ht.timedelta, so
95+
# we need to handle the case where they provide a bt.TimeDelta default by
96+
# converting to bintime.
97+
if isinstance(default_value, bt.TimeDelta) and isinstance(value, ht.timedelta):
98+
return convert_timedelta(bt.TimeDelta, value)
9399

94100
# lists are allowed to not match, since sets and tuples are converted to lists
95101
if not isinstance(value, list):

src/nipanel/converters/protobuf_types.py

Lines changed: 84 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
import numpy as np
1111
from ni.protobuf.types import (
1212
array_pb2,
13+
precision_duration_pb2,
14+
precision_duration_conversion,
1315
precision_timestamp_pb2,
1416
precision_timestamp_conversion,
1517
scalar_conversion,
@@ -379,7 +381,13 @@ def to_python_value(
379381

380382

381383
class BTDateTimeConverter(Converter[bt.DateTime, precision_timestamp_pb2.PrecisionTimestamp]):
382-
"""A converter for bintime.DateTime types."""
384+
"""A converter for bintime.DateTime types.
385+
386+
.. note:: The nipanel package will always convert PrecisionTimestamp messages to
387+
hightime.datetime objects using HTDateTimeConverter. To use bintime.DateTime
388+
values in a panel, you must pass a bintime.DateTime value for the default_value
389+
parameter of the get_value() method on the panel.
390+
"""
383391

384392
@property
385393
def python_type(self) -> type:
@@ -391,6 +399,16 @@ def protobuf_message(self) -> Type[precision_timestamp_pb2.PrecisionTimestamp]:
391399
"""The type-specific protobuf message for the Python type."""
392400
return precision_timestamp_pb2.PrecisionTimestamp
393401

402+
@property
403+
def protobuf_typename(self) -> str:
404+
"""The protobuf name for the type."""
405+
# Override the base class here because there can only be one converter that
406+
# converts PrecisionTimestamp objects. Since there are two converters that convert
407+
# to PrecisionTimestamp, we have to choose one to handle conversion from protobuf.
408+
# For the purposes of nipanel, we'll convert PrecisionTimestamp messages to
409+
# hightime.datetime. See HTDateTimeConverter.
410+
return "PrecisionTimestamp_Placeholder"
411+
394412
def to_protobuf_message(
395413
self, python_value: bt.DateTime
396414
) -> precision_timestamp_pb2.PrecisionTimestamp:
@@ -404,34 +422,60 @@ def to_python_value(
404422
return precision_timestamp_conversion.bintime_datetime_from_protobuf(protobuf_message)
405423

406424

407-
class HTDateTimeConverter(Converter[ht.datetime, precision_timestamp_pb2.PrecisionTimestamp]):
408-
"""A converter for hightime.datetime objects.
425+
class BTTimeDeltaConverter(Converter[bt.TimeDelta, precision_duration_pb2.PrecisionDuration]):
426+
"""A converter for bintime.TimeDelta types.
409427
410-
.. note:: The nipanel package will always convert PrecisionTimestamp messages to
411-
bintime.DateTime objects using BTDateTimeConverter. To use hightime.datetime
412-
values in a panel, you must pass a hightime.datetime value for the default_value
428+
.. note:: The nipanel package will always convert PrecisionDuration messages to
429+
hightime.timedelta objects using HTTimeDeltaConverter. To use bintime.TimeDelta
430+
values in a panel, you must pass a bintime.TimeDelta value for the default_value
413431
parameter of the get_value() method on the panel.
414432
"""
415433

416434
@property
417435
def python_type(self) -> type:
418436
"""The Python type that this converter handles."""
419-
return ht.datetime
437+
return bt.TimeDelta
420438

421439
@property
422-
def protobuf_message(self) -> Type[precision_timestamp_pb2.PrecisionTimestamp]:
440+
def protobuf_message(self) -> Type[precision_duration_pb2.PrecisionDuration]:
423441
"""The type-specific protobuf message for the Python type."""
424-
return precision_timestamp_pb2.PrecisionTimestamp
442+
return precision_duration_pb2.PrecisionDuration
425443

426444
@property
427445
def protobuf_typename(self) -> str:
428446
"""The protobuf name for the type."""
429447
# Override the base class here because there can only be one converter that
430-
# converts PrecisionTimestamp objects. Since there are two converters that convert
431-
# to PrecisionTimestamp, we have to choose one to handle conversion from protobuf.
432-
# For the purposes of nipanel, we'll convert PrecisionTimestamp messages to
433-
# bintime.DateTime. See BTDateTimeConverter.
434-
return "PrecisionTimestamp_Placeholder"
448+
# converts PrecisionDuration objects. Since there are two converters that convert
449+
# to PrecisionDuration, we have to choose one to handle conversion from protobuf.
450+
# For the purposes of nipanel, we'll convert PrecisionDuration messages to
451+
# hightime.timedelta. See HTTimeDeltaConverter.
452+
return "PrecisionDuration_Placeholder"
453+
454+
def to_protobuf_message(
455+
self, python_value: bt.TimeDelta
456+
) -> precision_duration_pb2.PrecisionDuration:
457+
"""Convert the Python TimeDelta to a protobuf PrecisionDuration."""
458+
return precision_duration_conversion.bintime_timedelta_to_protobuf(python_value)
459+
460+
def to_python_value(
461+
self, protobuf_message: precision_duration_pb2.PrecisionDuration
462+
) -> bt.TimeDelta:
463+
"""Convert the protobuf PrecisionDuration to a Python TimeDelta."""
464+
return precision_duration_conversion.bintime_timedelta_from_protobuf(protobuf_message)
465+
466+
467+
class HTDateTimeConverter(Converter[ht.datetime, precision_timestamp_pb2.PrecisionTimestamp]):
468+
"""A converter for hightime.datetime objects."""
469+
470+
@property
471+
def python_type(self) -> type:
472+
"""The Python type that this converter handles."""
473+
return ht.datetime
474+
475+
@property
476+
def protobuf_message(self) -> Type[precision_timestamp_pb2.PrecisionTimestamp]:
477+
"""The type-specific protobuf message for the Python type."""
478+
return precision_timestamp_pb2.PrecisionTimestamp
435479

436480
def to_protobuf_message(
437481
self, python_value: ht.datetime
@@ -446,6 +490,32 @@ def to_python_value(
446490
return precision_timestamp_conversion.hightime_datetime_from_protobuf(protobuf_message)
447491

448492

493+
class HTTimeDeltaConverter(Converter[ht.timedelta, precision_duration_pb2.PrecisionDuration]):
494+
"""A converter for hightime.timedelta objects."""
495+
496+
@property
497+
def python_type(self) -> type:
498+
"""The Python type that this converter handles."""
499+
return ht.timedelta
500+
501+
@property
502+
def protobuf_message(self) -> Type[precision_duration_pb2.PrecisionDuration]:
503+
"""The type-specific protobuf message for the Python type."""
504+
return precision_duration_pb2.PrecisionDuration
505+
506+
def to_protobuf_message(
507+
self, python_value: ht.timedelta
508+
) -> precision_duration_pb2.PrecisionDuration:
509+
"""Convert the Python timedelta to a protobuf PrecisionDuration."""
510+
return precision_duration_conversion.hightime_timedelta_to_protobuf(python_value)
511+
512+
def to_python_value(
513+
self, protobuf_message: precision_duration_pb2.PrecisionDuration
514+
) -> ht.timedelta:
515+
"""Convert the protobuf PrecisionDuration to a Python timedelta."""
516+
return precision_duration_conversion.hightime_timedelta_from_protobuf(protobuf_message)
517+
518+
449519
class ScalarConverter(Converter[Scalar[_AnyScalarType], scalar_pb2.Scalar]):
450520
"""A converter for Scalar objects."""
451521

0 commit comments

Comments
 (0)