ni.datastore 0.1.0.dev6__tar.gz → 2.0.0.dev0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. {ni_datastore-0.1.0.dev6 → ni_datastore-2.0.0.dev0}/PKG-INFO +9 -9
  2. {ni_datastore-0.1.0.dev6 → ni_datastore-2.0.0.dev0}/README.md +1 -2
  3. {ni_datastore-0.1.0.dev6 → ni_datastore-2.0.0.dev0}/pyproject.toml +13 -10
  4. {ni_datastore-0.1.0.dev6 → ni_datastore-2.0.0.dev0}/src/ni/datastore/data/__init__.py +0 -3
  5. {ni_datastore-0.1.0.dev6 → ni_datastore-2.0.0.dev0}/src/ni/datastore/data/_data_store_client.py +72 -71
  6. {ni_datastore-0.1.0.dev6 → ni_datastore-2.0.0.dev0}/src/ni/datastore/data/_grpc_conversion.py +33 -47
  7. {ni_datastore-0.1.0.dev6 → ni_datastore-2.0.0.dev0}/src/ni/datastore/data/_types/_published_condition.py +2 -15
  8. {ni_datastore-0.1.0.dev6 → ni_datastore-2.0.0.dev0}/src/ni/datastore/data/_types/_published_measurement.py +1 -14
  9. {ni_datastore-0.1.0.dev6 → ni_datastore-2.0.0.dev0}/src/ni/datastore/data/_types/_step.py +17 -17
  10. {ni_datastore-0.1.0.dev6 → ni_datastore-2.0.0.dev0}/src/ni/datastore/data/_types/_test_result.py +19 -19
  11. ni_datastore-0.1.0.dev6/src/ni/datastore/data/_types/_moniker.py +0 -69
  12. {ni_datastore-0.1.0.dev6 → ni_datastore-2.0.0.dev0}/LICENSE +0 -0
  13. {ni_datastore-0.1.0.dev6 → ni_datastore-2.0.0.dev0}/src/ni/datastore/__init__.py +0 -0
  14. {ni_datastore-0.1.0.dev6 → ni_datastore-2.0.0.dev0}/src/ni/datastore/data/_types/__init__.py +0 -0
  15. {ni_datastore-0.1.0.dev6 → ni_datastore-2.0.0.dev0}/src/ni/datastore/data/_types/_error_information.py +0 -0
  16. {ni_datastore-0.1.0.dev6 → ni_datastore-2.0.0.dev0}/src/ni/datastore/data/_types/_outcome.py +0 -0
  17. {ni_datastore-0.1.0.dev6 → ni_datastore-2.0.0.dev0}/src/ni/datastore/data/_types/py.typed +0 -0
  18. {ni_datastore-0.1.0.dev6 → ni_datastore-2.0.0.dev0}/src/ni/datastore/data/py.typed +0 -0
  19. {ni_datastore-0.1.0.dev6 → ni_datastore-2.0.0.dev0}/src/ni/datastore/metadata/__init__.py +0 -0
  20. {ni_datastore-0.1.0.dev6 → ni_datastore-2.0.0.dev0}/src/ni/datastore/metadata/_grpc_conversion.py +0 -0
  21. {ni_datastore-0.1.0.dev6 → ni_datastore-2.0.0.dev0}/src/ni/datastore/metadata/_metadata_store_client.py +0 -0
  22. {ni_datastore-0.1.0.dev6 → ni_datastore-2.0.0.dev0}/src/ni/datastore/metadata/_types/__init__.py +0 -0
  23. {ni_datastore-0.1.0.dev6 → ni_datastore-2.0.0.dev0}/src/ni/datastore/metadata/_types/_alias.py +0 -0
  24. {ni_datastore-0.1.0.dev6 → ni_datastore-2.0.0.dev0}/src/ni/datastore/metadata/_types/_alias_target_type.py +0 -0
  25. {ni_datastore-0.1.0.dev6 → ni_datastore-2.0.0.dev0}/src/ni/datastore/metadata/_types/_extension_schema.py +0 -0
  26. {ni_datastore-0.1.0.dev6 → ni_datastore-2.0.0.dev0}/src/ni/datastore/metadata/_types/_hardware_item.py +0 -0
  27. {ni_datastore-0.1.0.dev6 → ni_datastore-2.0.0.dev0}/src/ni/datastore/metadata/_types/_metadata_items.py +0 -0
  28. {ni_datastore-0.1.0.dev6 → ni_datastore-2.0.0.dev0}/src/ni/datastore/metadata/_types/_operator.py +0 -0
  29. {ni_datastore-0.1.0.dev6 → ni_datastore-2.0.0.dev0}/src/ni/datastore/metadata/_types/_software_item.py +0 -0
  30. {ni_datastore-0.1.0.dev6 → ni_datastore-2.0.0.dev0}/src/ni/datastore/metadata/_types/_test.py +0 -0
  31. {ni_datastore-0.1.0.dev6 → ni_datastore-2.0.0.dev0}/src/ni/datastore/metadata/_types/_test_adapter.py +0 -0
  32. {ni_datastore-0.1.0.dev6 → ni_datastore-2.0.0.dev0}/src/ni/datastore/metadata/_types/_test_description.py +0 -0
  33. {ni_datastore-0.1.0.dev6 → ni_datastore-2.0.0.dev0}/src/ni/datastore/metadata/_types/_test_station.py +0 -0
  34. {ni_datastore-0.1.0.dev6 → ni_datastore-2.0.0.dev0}/src/ni/datastore/metadata/_types/_uut.py +0 -0
  35. {ni_datastore-0.1.0.dev6 → ni_datastore-2.0.0.dev0}/src/ni/datastore/metadata/_types/_uut_instance.py +0 -0
  36. {ni_datastore-0.1.0.dev6 → ni_datastore-2.0.0.dev0}/src/ni/datastore/metadata/_types/py.typed +0 -0
  37. {ni_datastore-0.1.0.dev6 → ni_datastore-2.0.0.dev0}/src/ni/datastore/metadata/py.typed +0 -0
  38. {ni_datastore-0.1.0.dev6 → ni_datastore-2.0.0.dev0}/src/ni/datastore/py.typed +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: ni.datastore
3
- Version: 0.1.0.dev6
3
+ Version: 2.0.0.dev0
4
4
  Summary: APIs for publishing and retrieving data from NI Measurement Data Services
5
5
  License: MIT
6
6
  Keywords: datastore
@@ -9,7 +9,7 @@ Author-email: opensource@ni.com
9
9
  Maintainer: Johann Scholtz
10
10
  Maintainer-email: johann.scholtz@emerson.com
11
11
  Requires-Python: >=3.10,<4.0
12
- Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Development Status :: 5 - Production/Stable
13
13
  Classifier: Intended Audience :: Developers
14
14
  Classifier: Intended Audience :: Manufacturing
15
15
  Classifier: Intended Audience :: Science/Research
@@ -23,12 +23,13 @@ Classifier: Programming Language :: Python :: 3.12
23
23
  Classifier: Programming Language :: Python :: 3.13
24
24
  Classifier: Programming Language :: Python :: 3.14
25
25
  Classifier: Programming Language :: Python :: Implementation :: CPython
26
- Requires-Dist: hightime (>=0.3.0.dev0)
27
- Requires-Dist: ni-datamonikers-v1-client (>=0.1.0.dev1)
28
- Requires-Dist: ni-measurements-data-v1-client (>=0.2.0.dev4)
29
- Requires-Dist: ni-measurements-metadata-v1-client (>=0.2.0.dev2)
30
- Requires-Dist: ni-protobuf-types (>=1.0.1.dev0)
26
+ Requires-Dist: hightime (>=1.0.0)
27
+ Requires-Dist: ni-measurements-data-v1-client (>=1.1.0dev0)
28
+ Requires-Dist: ni-measurements-metadata-v1-client (>=1.0.0)
29
+ Requires-Dist: ni-protobuf-types (>=1.1.0)
31
30
  Requires-Dist: protobuf (>=4.21)
31
+ Project-URL: Documentation, https://datastorepython.readthedocs.io/en/latest/
32
+ Project-URL: Repository, https://github.com/ni/datastore-python
32
33
  Description-Content-Type: text/markdown
33
34
 
34
35
  # Table of Contents
@@ -43,8 +44,7 @@ Description-Content-Type: text/markdown
43
44
  # Measurement Data Services API for Python
44
45
 
45
46
  `datastore-python` contains Python code for writing to and reading from
46
- [NI Measurement Data Services](https://github.com/ni/datastore-service).
47
- It will include examples of how to use the Python API.
47
+ NI Measurement Data Store. It will include examples of how to use the Python API.
48
48
 
49
49
  # About
50
50
 
@@ -10,8 +10,7 @@
10
10
  # Measurement Data Services API for Python
11
11
 
12
12
  `datastore-python` contains Python code for writing to and reading from
13
- [NI Measurement Data Services](https://github.com/ni/datastore-service).
14
- It will include examples of how to use the Python API.
13
+ NI Measurement Data Store. It will include examples of how to use the Python API.
15
14
 
16
15
  # About
17
16
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "ni.datastore"
3
- version = "0.1.0.dev6"
3
+ version = "2.0.0.dev0"
4
4
  license = "MIT"
5
5
  description = "APIs for publishing and retrieving data from NI Measurement Data Services"
6
6
  authors = [{name = "NI", email = "opensource@ni.com"}]
@@ -9,10 +9,9 @@ maintainers = [
9
9
  {name = "Joel Dixon", email = "joel.dixon@emerson.com"}
10
10
  ]
11
11
  readme = "README.md"
12
- repository = "https://github.com/ni/datastore-python"
13
12
  keywords = ["datastore"]
14
13
  classifiers = [
15
- "Development Status :: 3 - Alpha",
14
+ "Development Status :: 5 - Production/Stable",
16
15
  "Intended Audience :: Developers",
17
16
  "Intended Audience :: Manufacturing",
18
17
  "Intended Audience :: Science/Research",
@@ -30,6 +29,10 @@ classifiers = [
30
29
  dynamic = ["dependencies"]
31
30
  requires-python = '>=3.10,<4.0'
32
31
 
32
+ [project.urls]
33
+ repository = "https://github.com/ni/datastore-python"
34
+ documentation = "https://datastorepython.readthedocs.io/en/latest/"
35
+
33
36
  [tool.poetry]
34
37
  packages = [{include = "ni", from = "src"}]
35
38
  requires-poetry = '>=2.1,<3.0'
@@ -37,11 +40,10 @@ requires-poetry = '>=2.1,<3.0'
37
40
  [tool.poetry.dependencies]
38
41
  python = "^3.10"
39
42
  protobuf = {version=">=4.21"}
40
- ni-datamonikers-v1-client = { version = ">=0.1.0.dev1", allow-prereleases = true }
41
- ni-measurements-data-v1-client = { version = ">=0.2.0.dev4", allow-prereleases = true }
42
- ni-measurements-metadata-v1-client = { version = ">=0.2.0.dev2", allow-prereleases = true }
43
- ni-protobuf-types = { version = ">=1.0.1.dev0", allow-prereleases = true }
44
- hightime = { version = ">=0.3.0.dev0", allow-prereleases = true }
43
+ ni-measurements-data-v1-client = { version = ">=1.1.0dev0", allow-prereleases = true }
44
+ ni-measurements-metadata-v1-client = { version = ">=1.0.0" }
45
+ ni-protobuf-types = { version = ">=1.1.0" }
46
+ hightime = { version = ">=1.0.0" }
45
47
 
46
48
  [tool.poetry.group.dev.dependencies]
47
49
  types-grpcio = ">=1.0"
@@ -51,6 +53,7 @@ plotly = ">=5.0"
51
53
  nbformat = ">=4.2.0"
52
54
  ipython = ">=7.0"
53
55
  jupyter = ">=1.0"
56
+ datastore-utilities = { path = "./utilities", develop = true }
54
57
 
55
58
  [tool.poetry.group.lint.dependencies]
56
59
  bandit = { version = ">=1.7", extras = ["toml"] }
@@ -89,7 +92,7 @@ skips = [
89
92
  ]
90
93
 
91
94
  [tool.ni-python-styleguide]
92
- extend_exclude = "docs,examples"
95
+ extend_exclude = "docs,examples,utilities"
93
96
 
94
97
  [tool.black]
95
98
  extend-exclude = 'docs/|examples/|_pb2(_grpc)?\.(py|pyi)$'
@@ -101,7 +104,7 @@ files = "."
101
104
  namespace_packages = true
102
105
  strict = true
103
106
  explicit_package_bases = true
104
- exclude = ["docs", "examples"]
107
+ exclude = ["docs", "examples", "utilities"]
105
108
 
106
109
  [tool.pyright]
107
110
  include = ["src/", "tests/"]
@@ -2,7 +2,6 @@
2
2
 
3
3
  from ni.datastore.data._data_store_client import DataStoreClient
4
4
  from ni.datastore.data._types._error_information import ErrorInformation
5
- from ni.datastore.data._types._moniker import Moniker
6
5
  from ni.datastore.data._types._outcome import Outcome
7
6
  from ni.datastore.data._types._published_condition import PublishedCondition
8
7
  from ni.datastore.data._types._published_measurement import PublishedMeasurement
@@ -12,7 +11,6 @@ from ni.datastore.data._types._test_result import TestResult
12
11
  __all__ = [
13
12
  "DataStoreClient",
14
13
  "ErrorInformation",
15
- "Moniker",
16
14
  "Outcome",
17
15
  "PublishedCondition",
18
16
  "PublishedMeasurement",
@@ -23,7 +21,6 @@ __all__ = [
23
21
  # Hide that it was not defined in this top-level package
24
22
  DataStoreClient.__module__ = __name__
25
23
  ErrorInformation.__module__ = __name__
26
- Moniker.__module__ = __name__
27
24
  Outcome.__module__ = __name__
28
25
  PublishedCondition.__module__ = __name__
29
26
  PublishedMeasurement.__module__ = __name__
@@ -8,21 +8,19 @@ from collections.abc import Iterable, Sequence
8
8
  from threading import Lock
9
9
  from types import TracebackType
10
10
  from typing import TYPE_CHECKING, Type, TypeVar, overload
11
- from urllib.parse import urlparse
12
11
 
13
12
  import hightime as ht
14
13
  from grpc import Channel
15
- from ni.datamonikers.v1.client import MonikerClient
16
14
  from ni.datastore.data._grpc_conversion import (
15
+ convert_read_condition_response_from_protobuf,
16
+ convert_read_measurement_response_from_protobuf,
17
17
  get_publish_measurement_timestamp,
18
18
  populate_publish_condition_batch_request_values,
19
19
  populate_publish_condition_request_value,
20
20
  populate_publish_measurement_batch_request_values,
21
21
  populate_publish_measurement_request_value,
22
- unpack_and_convert_from_protobuf_any,
23
22
  )
24
23
  from ni.datastore.data._types._error_information import ErrorInformation
25
- from ni.datastore.data._types._moniker import Moniker
26
24
  from ni.datastore.data._types._outcome import Outcome
27
25
  from ni.datastore.data._types._published_condition import PublishedCondition
28
26
  from ni.datastore.data._types._published_measurement import PublishedMeasurement
@@ -45,6 +43,8 @@ from ni.measurements.data.v1.data_store_service_pb2 import (
45
43
  QueryMeasurementsRequest,
46
44
  QueryStepsRequest,
47
45
  QueryTestResultsRequest,
46
+ ReadConditionValueRequest,
47
+ ReadMeasurementValueRequest,
48
48
  )
49
49
  from ni.protobuf.types.precision_timestamp_conversion import (
50
50
  hightime_datetime_to_protobuf,
@@ -72,8 +72,6 @@ class DataStoreClient:
72
72
  "_grpc_channel_pool",
73
73
  "_data_store_client",
74
74
  "_data_store_client_lock",
75
- "_moniker_clients_by_service_location",
76
- "_moniker_clients_lock",
77
75
  )
78
76
 
79
77
  _DATA_STORE_CLIENT_CLOSED_ERROR = (
@@ -86,9 +84,7 @@ class DataStoreClient:
86
84
  _grpc_channel: Channel | None
87
85
  _grpc_channel_pool: GrpcChannelPool | None
88
86
  _data_store_client: DataStoreServiceClient | None
89
- _moniker_clients_by_service_location: dict[str, MonikerClient]
90
87
  _data_store_client_lock: Lock
91
- _moniker_clients_lock: Lock
92
88
 
93
89
  def __init__(
94
90
  self,
@@ -102,9 +98,7 @@ class DataStoreClient:
102
98
  discovery_client: An optional discovery client (recommended).
103
99
 
104
100
  grpc_channel: An optional data store gRPC channel. Providing this channel will bypass
105
- discovery service resolution of the data store. (Note: Reading data from a moniker
106
- will still always use a channel corresponding to the service location specified by
107
- that moniker.)
101
+ discovery service resolution of the data store.
108
102
 
109
103
  grpc_channel_pool: An optional gRPC channel pool (recommended).
110
104
  """
@@ -113,10 +107,8 @@ class DataStoreClient:
113
107
  self._grpc_channel_pool = grpc_channel_pool
114
108
 
115
109
  self._data_store_client = None
116
- self._moniker_clients_by_service_location = {}
117
110
 
118
111
  self._data_store_client_lock = Lock()
119
- self._moniker_clients_lock = Lock()
120
112
 
121
113
  self._closed = False
122
114
 
@@ -142,11 +134,6 @@ class DataStoreClient:
142
134
  self._data_store_client.close()
143
135
  self._data_store_client = None
144
136
 
145
- with self._moniker_clients_lock:
146
- for _, moniker_client in self._moniker_clients_by_service_location.items():
147
- moniker_client.close()
148
- self._moniker_clients_by_service_location.clear()
149
-
150
137
  def publish_condition(
151
138
  self,
152
139
  name: str,
@@ -375,30 +362,72 @@ class DataStoreClient:
375
362
  return publish_response.measurement_ids
376
363
 
377
364
  @overload
378
- def read_data(
365
+ def read_condition_value(
379
366
  self,
380
- moniker_source: Moniker | PublishedMeasurement | PublishedCondition,
367
+ read_source: PublishedCondition,
381
368
  expected_type: Type[TRead],
382
369
  ) -> TRead: ...
383
370
 
384
371
  @overload
385
- def read_data(
372
+ def read_condition_value(
386
373
  self,
387
- moniker_source: Moniker | PublishedMeasurement | PublishedCondition,
374
+ read_source: PublishedCondition,
388
375
  ) -> object: ...
389
376
 
390
- def read_data(
377
+ def read_condition_value(
391
378
  self,
392
- moniker_source: Moniker | PublishedMeasurement | PublishedCondition,
379
+ read_source: PublishedCondition,
393
380
  expected_type: Type[TRead] | None = None,
394
381
  ) -> TRead | object:
395
382
  """Read data published to the data store.
396
383
 
397
384
  Args:
398
- moniker_source: The source from which to read data. Can be:
399
- - A Moniker (wrapper type) directly
400
- - A PublishedMeasurement (uses its moniker)
401
- - A PublishedCondition (uses its moniker)
385
+ read_source: The source from which to read data (PublishedCondition).
386
+
387
+ expected_type: Optional type to validate the returned data against.
388
+ If provided, a TypeError will be raised if the actual data type
389
+ doesn't match.
390
+
391
+ Returns:
392
+ The data retrieved from the data store. The return type depends on
393
+ what was originally published:
394
+ - Scalar conditions return as Vectors
395
+ - Other types are returned as originally published
396
+ If expected_type is specified, the return value is guaranteed to be
397
+ of that type.
398
+
399
+ Raises:
400
+ TypeError: If expected_type is provided and the actual data type
401
+ doesn't match.
402
+ """
403
+ read_value = self._read_condition(read_source)
404
+ if expected_type is not None and not isinstance(read_value, expected_type):
405
+ raise TypeError(f"Expected type {expected_type}, got {type(read_value)}")
406
+
407
+ return read_value
408
+
409
+ @overload
410
+ def read_measurement_value(
411
+ self,
412
+ read_source: PublishedMeasurement,
413
+ expected_type: Type[TRead],
414
+ ) -> TRead: ...
415
+
416
+ @overload
417
+ def read_measurement_value(
418
+ self,
419
+ read_source: PublishedMeasurement,
420
+ ) -> object: ...
421
+
422
+ def read_measurement_value(
423
+ self,
424
+ read_source: PublishedMeasurement,
425
+ expected_type: Type[TRead] | None = None,
426
+ ) -> TRead | object:
427
+ """Read data published to the data store.
428
+
429
+ Args:
430
+ read_source: The source from which to read data (PublishedMeasurement).
402
431
 
403
432
  expected_type: Optional type to validate the returned data against.
404
433
  If provided, a TypeError will be raised if the actual data type
@@ -413,33 +442,14 @@ class DataStoreClient:
413
442
  of that type.
414
443
 
415
444
  Raises:
416
- ValueError: If the moniker_source doesn't have a valid moniker.
417
445
  TypeError: If expected_type is provided and the actual data type
418
446
  doesn't match.
419
447
  """
420
- from ni.datamonikers.v1.data_moniker_pb2 import Moniker as MonikerProto
421
-
422
- moniker_proto: MonikerProto
423
-
424
- if isinstance(moniker_source, Moniker):
425
- moniker_proto = moniker_source.to_protobuf()
426
- elif isinstance(moniker_source, PublishedMeasurement):
427
- if moniker_source.moniker is None:
428
- raise ValueError("PublishedMeasurement must have a Moniker to read data")
429
- moniker_proto = moniker_source.moniker.to_protobuf()
430
- elif isinstance(moniker_source, PublishedCondition):
431
- if moniker_source.moniker is None:
432
- raise ValueError("PublishedCondition must have a Moniker to read data")
433
- moniker_proto = moniker_source.moniker.to_protobuf()
434
- else:
435
- raise TypeError(f"Unsupported moniker_source type: {type(moniker_source)}")
436
-
437
- moniker_client = self._get_moniker_client(moniker_proto.service_location)
438
- read_result = moniker_client.read_from_moniker(moniker_proto)
439
- converted_data = unpack_and_convert_from_protobuf_any(read_result.value)
440
- if expected_type is not None and not isinstance(converted_data, expected_type):
441
- raise TypeError(f"Expected type {expected_type}, got {type(converted_data)}")
442
- return converted_data
448
+ read_value = self._read_measurement(read_source)
449
+ if expected_type is not None and not isinstance(read_value, expected_type):
450
+ raise TypeError(f"Expected type {expected_type}, got {type(read_value)}")
451
+
452
+ return read_value
443
453
 
444
454
  def create_step(self, step: Step) -> str:
445
455
  """Create a new step in the data store.
@@ -540,7 +550,7 @@ class DataStoreClient:
540
550
 
541
551
  Returns:
542
552
  Sequence[PublishedCondition]: The list of matching conditions. Each
543
- item contains a moniker for retrieving the condition
553
+ item contains an id for retrieving the condition
544
554
  measurements, as well as the metadata associated with the
545
555
  condition.
546
556
  """
@@ -563,7 +573,7 @@ class DataStoreClient:
563
573
 
564
574
  Returns:
565
575
  Sequence[PublishedMeasurement]: The list of matching measurements.
566
- Each item contains a moniker for retrieving the measurement, as
576
+ Each item contains an id for retrieving the measurement, as
567
577
  well as the metadata associated with the measurement.
568
578
  """
569
579
  query_request = QueryMeasurementsRequest(odata_query=odata_query)
@@ -629,21 +639,12 @@ class DataStoreClient:
629
639
  grpc_channel_pool=self._grpc_channel_pool,
630
640
  )
631
641
 
632
- def _get_moniker_client(self, service_location: str) -> MonikerClient:
633
- if self._closed:
634
- raise RuntimeError(self._DATA_STORE_CLIENT_CLOSED_ERROR)
642
+ def _read_measurement(self, published_measurement: PublishedMeasurement) -> object:
643
+ request = ReadMeasurementValueRequest(measurement_id=published_measurement.id)
644
+ response = self._get_data_store_client().read_measurement_value(request)
645
+ return convert_read_measurement_response_from_protobuf(response)
635
646
 
636
- parsed_service_location = urlparse(service_location).netloc
637
- if parsed_service_location not in self._moniker_clients_by_service_location:
638
- with self._moniker_clients_lock:
639
- if parsed_service_location not in self._moniker_clients_by_service_location:
640
- self._moniker_clients_by_service_location[parsed_service_location] = (
641
- self._instantiate_moniker_client(parsed_service_location)
642
- )
643
- return self._moniker_clients_by_service_location[parsed_service_location]
644
-
645
- def _instantiate_moniker_client(self, parsed_service_location: str) -> MonikerClient:
646
- return MonikerClient(
647
- service_location=parsed_service_location,
648
- grpc_channel_pool=self._grpc_channel_pool,
649
- )
647
+ def _read_condition(self, published_condition: PublishedCondition) -> object:
648
+ request = ReadConditionValueRequest(condition_id=published_condition.id)
649
+ response = self._get_data_store_client().read_condition_value(request)
650
+ return convert_read_condition_response_from_protobuf(response)
@@ -8,12 +8,13 @@ from typing import Iterable, cast
8
8
 
9
9
  import hightime as ht
10
10
  import numpy as np
11
- from google.protobuf.any_pb2 import Any
12
11
  from ni.measurements.data.v1.data_store_service_pb2 import (
13
12
  PublishConditionBatchRequest,
14
13
  PublishConditionRequest,
15
14
  PublishMeasurementBatchRequest,
16
15
  PublishMeasurementRequest,
16
+ ReadConditionValueResponse,
17
+ ReadMeasurementValueResponse,
17
18
  )
18
19
  from ni.protobuf.types.precision_timestamp_conversion import (
19
20
  hightime_datetime_to_protobuf,
@@ -21,7 +22,6 @@ from ni.protobuf.types.precision_timestamp_conversion import (
21
22
  from ni.protobuf.types.precision_timestamp_pb2 import PrecisionTimestamp
22
23
  from ni.protobuf.types.scalar_conversion import scalar_to_protobuf
23
24
  from ni.protobuf.types.vector_conversion import vector_from_protobuf, vector_to_protobuf
24
- from ni.protobuf.types.vector_pb2 import Vector as VectorProto
25
25
  from ni.protobuf.types.waveform_conversion import (
26
26
  digital_waveform_from_protobuf,
27
27
  digital_waveform_to_protobuf,
@@ -36,19 +36,10 @@ from ni.protobuf.types.waveform_conversion import (
36
36
  int16_complex_waveform_from_protobuf,
37
37
  int16_complex_waveform_to_protobuf,
38
38
  )
39
- from ni.protobuf.types.waveform_pb2 import (
40
- DigitalWaveform as DigitalWaveformProto,
41
- DoubleAnalogWaveform,
42
- DoubleComplexWaveform,
43
- DoubleSpectrum,
44
- I16AnalogWaveform,
45
- I16ComplexWaveform,
46
- )
47
39
  from ni.protobuf.types.xydata_conversion import (
48
40
  float64_xydata_from_protobuf,
49
41
  float64_xydata_to_protobuf,
50
42
  )
51
- from ni.protobuf.types.xydata_pb2 import DoubleXYData
52
43
  from nitypes.complex import ComplexInt32DType
53
44
  from nitypes.scalar import Scalar
54
45
  from nitypes.vector import Vector
@@ -187,43 +178,38 @@ def populate_publish_measurement_batch_request_values(
187
178
  )
188
179
 
189
180
 
190
- def unpack_and_convert_from_protobuf_any(read_value: Any) -> object:
191
- """Convert from a packed pb.Any to the appropriate python object."""
192
- value_type = read_value.TypeName()
193
- if value_type == DoubleAnalogWaveform.DESCRIPTOR.full_name:
194
- double_analog_waveform = DoubleAnalogWaveform()
195
- read_value.Unpack(double_analog_waveform)
196
- return float64_analog_waveform_from_protobuf(double_analog_waveform)
197
- elif value_type == I16AnalogWaveform.DESCRIPTOR.full_name:
198
- i16_analog_waveform = I16AnalogWaveform()
199
- read_value.Unpack(i16_analog_waveform)
200
- return int16_analog_waveform_from_protobuf(i16_analog_waveform)
201
- elif value_type == DoubleComplexWaveform.DESCRIPTOR.full_name:
202
- double_complex_waveform = DoubleComplexWaveform()
203
- read_value.Unpack(double_complex_waveform)
204
- return float64_complex_waveform_from_protobuf(double_complex_waveform)
205
- elif value_type == I16ComplexWaveform.DESCRIPTOR.full_name:
206
- i16_complex_waveform = I16ComplexWaveform()
207
- read_value.Unpack(i16_complex_waveform)
208
- return int16_complex_waveform_from_protobuf(i16_complex_waveform)
209
- elif value_type == DoubleSpectrum.DESCRIPTOR.full_name:
210
- spectrum = DoubleSpectrum()
211
- read_value.Unpack(spectrum)
212
- return float64_spectrum_from_protobuf(spectrum)
213
- elif value_type == DigitalWaveformProto.DESCRIPTOR.full_name:
214
- digital_waveform = DigitalWaveformProto()
215
- read_value.Unpack(digital_waveform)
216
- return digital_waveform_from_protobuf(digital_waveform)
217
- elif value_type == DoubleXYData.DESCRIPTOR.full_name:
218
- xydata = DoubleXYData()
219
- read_value.Unpack(xydata)
220
- return float64_xydata_from_protobuf(xydata)
221
- elif value_type == VectorProto.DESCRIPTOR.full_name:
222
- vector = VectorProto()
223
- read_value.Unpack(vector)
224
- return vector_from_protobuf(vector)
181
+ def convert_read_measurement_response_from_protobuf(
182
+ response: ReadMeasurementValueResponse,
183
+ ) -> object:
184
+ """Convert the value in the ReadMeasurementValueResponse from protobuf and return it."""
185
+ read_data_type = response.WhichOneof("value")
186
+ if read_data_type == "digital_waveform":
187
+ return digital_waveform_from_protobuf(response.digital_waveform)
188
+ elif read_data_type == "double_analog_waveform":
189
+ return float64_analog_waveform_from_protobuf(response.double_analog_waveform)
190
+ elif read_data_type == "double_complex_waveform":
191
+ return float64_complex_waveform_from_protobuf(response.double_complex_waveform)
192
+ elif read_data_type == "double_spectrum":
193
+ return float64_spectrum_from_protobuf(response.double_spectrum)
194
+ elif read_data_type == "i16_analog_waveform":
195
+ return int16_analog_waveform_from_protobuf(response.i16_analog_waveform)
196
+ elif read_data_type == "i16_complex_waveform":
197
+ return int16_complex_waveform_from_protobuf(response.i16_complex_waveform)
198
+ elif read_data_type == "vector":
199
+ return vector_from_protobuf(response.vector)
200
+ elif read_data_type == "x_y_data":
201
+ return float64_xydata_from_protobuf(response.x_y_data)
202
+ else:
203
+ raise TypeError(f"Invalid read type: {read_data_type}")
204
+
205
+
206
+ def convert_read_condition_response_from_protobuf(response: ReadConditionValueResponse) -> object:
207
+ """Convert the value in the ReadConditionValueResponse from protobuf and return it."""
208
+ read_data_type = response.WhichOneof("value")
209
+ if read_data_type == "vector":
210
+ return vector_from_protobuf(response.vector)
225
211
  else:
226
- raise TypeError(f"Unsupported data type Name: {value_type}")
212
+ raise TypeError(f"Invalid read type: {read_data_type}")
227
213
 
228
214
 
229
215
  def get_publish_measurement_timestamp(
@@ -2,7 +2,6 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- from ni.datastore.data._types._moniker import Moniker
6
5
  from ni.measurements.data.v1.data_store_pb2 import (
7
6
  PublishedCondition as PublishedConditionProto,
8
7
  )
@@ -12,12 +11,11 @@ class PublishedCondition:
12
11
  """Represents a condition that has been published to the data store.
13
12
 
14
13
  A published condition contains metadata about a condition value that was
15
- published, including a moniker for data retrieval and associated metadata
14
+ published, including an id for data retrieval and associated metadata
16
15
  like condition name, type, and associated step/test result IDs.
17
16
  """
18
17
 
19
18
  __slots__ = (
20
- "moniker",
21
19
  "id",
22
20
  "name",
23
21
  "condition_type",
@@ -28,7 +26,6 @@ class PublishedCondition:
28
26
  def __init__(
29
27
  self,
30
28
  *,
31
- moniker: Moniker | None = None,
32
29
  id: str = "",
33
30
  name: str = "",
34
31
  condition_type: str = "",
@@ -38,8 +35,6 @@ class PublishedCondition:
38
35
  """Initialize a PublishedCondition instance.
39
36
 
40
37
  Args:
41
- moniker: The moniker of the condition that this value is associated
42
- with. This moniker returns a Vector when read.
43
38
  id: The unique identifier of the condition. This
44
39
  can be used to reference and find the condition in the data store.
45
40
  name: The name of the condition.
@@ -49,7 +44,6 @@ class PublishedCondition:
49
44
  test_result_id: The ID of the test result with which this condition
50
45
  is associated.
51
46
  """
52
- self.moniker = moniker
53
47
  self.id = id
54
48
  self.name = name
55
49
  self.condition_type = condition_type
@@ -60,11 +54,6 @@ class PublishedCondition:
60
54
  def from_protobuf(published_condition_proto: PublishedConditionProto) -> "PublishedCondition":
61
55
  """Create a PublishedCondition instance from a protobuf PublishedCondition message."""
62
56
  return PublishedCondition(
63
- moniker=(
64
- Moniker.from_protobuf(published_condition_proto.moniker)
65
- if published_condition_proto.HasField("moniker")
66
- else None
67
- ),
68
57
  id=published_condition_proto.id,
69
58
  name=published_condition_proto.name,
70
59
  condition_type=published_condition_proto.condition_type,
@@ -75,7 +64,6 @@ class PublishedCondition:
75
64
  def to_protobuf(self) -> PublishedConditionProto:
76
65
  """Convert this PublishedCondition instance to a protobuf PublishedCondition message."""
77
66
  return PublishedConditionProto(
78
- moniker=self.moniker.to_protobuf() if self.moniker is not None else None,
79
67
  id=self.id,
80
68
  name=self.name,
81
69
  condition_type=self.condition_type,
@@ -88,8 +76,7 @@ class PublishedCondition:
88
76
  if not isinstance(other, PublishedCondition):
89
77
  return NotImplemented
90
78
  return (
91
- self.moniker == other.moniker
92
- and self.id == other.id
79
+ self.id == other.id
93
80
  and self.name == other.name
94
81
  and self.condition_type == other.condition_type
95
82
  and self.step_id == other.step_id
@@ -6,7 +6,6 @@ from typing import Iterable, MutableSequence
6
6
 
7
7
  import hightime as ht
8
8
  from ni.datastore.data._types._error_information import ErrorInformation
9
- from ni.datastore.data._types._moniker import Moniker
10
9
  from ni.datastore.data._types._outcome import Outcome
11
10
  from ni.datastore.data._types._published_condition import PublishedCondition
12
11
  from ni.measurements.data.v1.data_store_pb2 import PublishedMeasurement as PublishedMeasurementProto
@@ -25,7 +24,6 @@ class PublishedMeasurement:
25
24
  """
26
25
 
27
26
  __slots__ = (
28
- "moniker",
29
27
  "_published_conditions",
30
28
  "id",
31
29
  "test_result_id",
@@ -66,7 +64,6 @@ class PublishedMeasurement:
66
64
  def __init__(
67
65
  self,
68
66
  *,
69
- moniker: Moniker | None = None,
70
67
  published_conditions: Iterable[PublishedCondition] | None = None,
71
68
  id: str = "",
72
69
  test_result_id: str = "",
@@ -86,8 +83,6 @@ class PublishedMeasurement:
86
83
  """Initialize a PublishedMeasurement instance.
87
84
 
88
85
  Args:
89
- moniker: The moniker of the measurement that this value is
90
- associated with.
91
86
  published_conditions: The published conditions associated with this
92
87
  measurement from the test step.
93
88
  id: The unique identifier of the measurement.
@@ -116,7 +111,6 @@ class PublishedMeasurement:
116
111
  error_information: Error or exception information in case of
117
112
  measurement failure.
118
113
  """
119
- self.moniker = moniker
120
114
  self._published_conditions: MutableSequence[PublishedCondition] = (
121
115
  list(published_conditions) if published_conditions is not None else []
122
116
  )
@@ -147,11 +141,6 @@ class PublishedMeasurement:
147
141
  ) -> "PublishedMeasurement":
148
142
  """Create a PublishedMeasurement instance from a protobuf PublishedMeasurement message."""
149
143
  return PublishedMeasurement(
150
- moniker=(
151
- Moniker.from_protobuf(published_measurement_proto.moniker)
152
- if published_measurement_proto.HasField("moniker")
153
- else None
154
- ),
155
144
  published_conditions=[
156
145
  PublishedCondition.from_protobuf(cond)
157
146
  for cond in published_measurement_proto.published_conditions
@@ -187,7 +176,6 @@ class PublishedMeasurement:
187
176
  def to_protobuf(self) -> PublishedMeasurementProto:
188
177
  """Convert this PublishedMeasurement instance to a protobuf PublishedMeasurement message."""
189
178
  return PublishedMeasurementProto(
190
- moniker=self.moniker.to_protobuf() if self.moniker is not None else None,
191
179
  published_conditions=[
192
180
  condition.to_protobuf() for condition in self.published_conditions
193
181
  ],
@@ -222,8 +210,7 @@ class PublishedMeasurement:
222
210
  if not isinstance(other, PublishedMeasurement):
223
211
  return NotImplemented
224
212
  return (
225
- self.moniker == other.moniker
226
- and self.published_conditions == other.published_conditions
213
+ self.published_conditions == other.published_conditions
227
214
  and self.id == other.id
228
215
  and self.test_result_id == other.test_result_id
229
216
  and self.step_id == other.step_id
@@ -29,11 +29,11 @@ class Step:
29
29
  """
30
30
 
31
31
  __slots__ = (
32
+ "name",
32
33
  "id",
33
34
  "parent_step_id",
34
35
  "test_result_id",
35
36
  "test_id",
36
- "name",
37
37
  "step_type",
38
38
  "notes",
39
39
  "start_date_time",
@@ -52,12 +52,12 @@ class Step:
52
52
 
53
53
  def __init__(
54
54
  self,
55
+ name: str,
55
56
  *,
56
57
  id: str = "",
57
58
  parent_step_id: str = "",
58
59
  test_result_id: str = "",
59
60
  test_id: str = "",
60
- name: str = "",
61
61
  step_type: str = "",
62
62
  notes: str = "",
63
63
  start_date_time: ht.datetime | None = None,
@@ -71,28 +71,28 @@ class Step:
71
71
  """Initialize a Step instance.
72
72
 
73
73
  Args:
74
- id: Unique identifier for the step.
75
- parent_step_id: ID of the parent step if this is a nested step.
76
- test_result_id: ID of the test result this step belongs to.
77
- test_id: ID of the test associated with this step.
78
74
  name: Human-readable name of the step.
79
- step_type: Type or category of the step.
80
- notes: Additional notes or comments about the step.
81
- start_date_time: The start date and time of the step execution.
82
- end_date_time: The end date and time of the step execution.
83
- link: Optional link to external resources for this step.
84
- extension: Additional custom metadata as key-value pairs.
85
- schema_id: ID of the extension schema for validating extensions.
86
- error_information: Error or exception information in case of
75
+ id (optional): Unique identifier for the step.
76
+ parent_step_id (optional): ID of the parent step if this is a nested step.
77
+ test_result_id (optional): ID of the test result this step belongs to.
78
+ test_id (optional): ID of the test associated with this step.
79
+ step_type (optional): Type or category of the step.
80
+ notes (optional): Additional notes or comments about the step.
81
+ start_date_time (optional): The start date and time of the step execution.
82
+ end_date_time (optional): The end date and time of the step execution.
83
+ link (optional): Optional link to external resources for this step.
84
+ extension (optional): Additional extension attributes as key-value pairs.
85
+ schema_id (optional): ID of the extension schema for validating extensions.
86
+ error_information (optional): Error or exception information in case of
87
87
  step failure.
88
- outcome: The outcome of the step (PASSED, FAILED,
88
+ outcome (optional): The outcome of the step (PASSED, FAILED,
89
89
  INDETERMINATE, or UNSPECIFIED).
90
90
  """
91
+ self.name = name
91
92
  self.id = id
92
93
  self.parent_step_id = parent_step_id
93
94
  self.test_result_id = test_result_id
94
95
  self.test_id = test_id
95
- self.name = name
96
96
  self.step_type = step_type
97
97
  self.notes = notes
98
98
  self.start_date_time = start_date_time
@@ -107,11 +107,11 @@ class Step:
107
107
  def from_protobuf(step_proto: StepProto) -> "Step":
108
108
  """Create a Step instance from a protobuf Step message."""
109
109
  step = Step(
110
+ name=step_proto.name,
110
111
  id=step_proto.id,
111
112
  parent_step_id=step_proto.parent_step_id,
112
113
  test_result_id=step_proto.test_result_id,
113
114
  test_id=step_proto.test_id,
114
- name=step_proto.name,
115
115
  step_type=step_proto.step_type,
116
116
  notes=step_proto.notes,
117
117
  start_date_time=(
@@ -29,6 +29,7 @@ class TestResult:
29
29
  """
30
30
 
31
31
  __slots__ = (
32
+ "name",
32
33
  "id",
33
34
  "uut_instance_id",
34
35
  "operator_id",
@@ -37,7 +38,6 @@ class TestResult:
37
38
  "_software_item_ids",
38
39
  "_hardware_item_ids",
39
40
  "_test_adapter_ids",
40
- "name",
41
41
  "start_date_time",
42
42
  "end_date_time",
43
43
  "outcome",
@@ -69,6 +69,7 @@ class TestResult:
69
69
 
70
70
  def __init__(
71
71
  self,
72
+ name: str,
72
73
  *,
73
74
  id: str = "",
74
75
  uut_instance_id: str = "",
@@ -78,7 +79,6 @@ class TestResult:
78
79
  software_item_ids: Iterable[str] | None = None,
79
80
  hardware_item_ids: Iterable[str] | None = None,
80
81
  test_adapter_ids: Iterable[str] | None = None,
81
- name: str = "",
82
82
  start_date_time: ht.datetime | None = None,
83
83
  end_date_time: ht.datetime | None = None,
84
84
  outcome: Outcome = Outcome.UNSPECIFIED,
@@ -90,25 +90,26 @@ class TestResult:
90
90
  """Initialize a TestResult instance.
91
91
 
92
92
  Args:
93
- id: Unique identifier for the test result.
94
- uut_instance_id: ID of the UUT instance that was tested.
95
- operator_id: ID of the operator who ran the test.
96
- test_station_id: ID of the test station used.
97
- test_description_id: ID of the test description that was executed.
98
- software_item_ids: IDs of software items used in the test.
99
- hardware_item_ids: IDs of hardware items used in the test.
100
- test_adapter_ids: IDs of test adapters used in the test.
101
93
  name: Human-readable name for the test result.
102
- start_date_time: The start date and time of the test execution.
103
- end_date_time: The end date and time of the test execution.
104
- outcome: The outcome of the test execution (PASSED, FAILED,
94
+ id (optional): Unique identifier for the test result.
95
+ uut_instance_id (optional): ID of the UUT instance that was tested.
96
+ operator_id (optional): ID of the operator who ran the test.
97
+ test_station_id (optional): ID of the test station used.
98
+ test_description_id (optional): ID of the test description that was executed.
99
+ software_item_ids (optional): IDs of software items used in the test.
100
+ hardware_item_ids (optional): IDs of hardware items used in the test.
101
+ test_adapter_ids (optional): IDs of test adapters used in the test.
102
+ start_date_time (optional): The start date and time of the test execution.
103
+ end_date_time (optional): The end date and time of the test execution.
104
+ outcome (optional): The outcome of the test execution (PASSED, FAILED,
105
105
  INDETERMINATE, or UNSPECIFIED).
106
- link: Optional link to external resources for this test result.
107
- extension: Additional custom metadata as key-value pairs.
108
- schema_id: ID of the extension schema for validating extensions.
109
- error_information: Error or exception information in case of
106
+ link (optional): Optional link to external resources for this test result.
107
+ extension (optional): Additional extension attributes as key-value pairs.
108
+ schema_id (optional): ID of the extension schema for validating extensions.
109
+ error_information (optional): Error or exception information in case of
110
110
  test result failure.
111
111
  """
112
+ self.name = name
112
113
  self.id = id
113
114
  self.uut_instance_id = uut_instance_id
114
115
  self.operator_id = operator_id
@@ -123,7 +124,6 @@ class TestResult:
123
124
  self._test_adapter_ids: MutableSequence[str] = (
124
125
  list(test_adapter_ids) if test_adapter_ids is not None else []
125
126
  )
126
- self.name = name
127
127
  self.start_date_time = start_date_time
128
128
  self.end_date_time = end_date_time
129
129
  self.outcome = outcome
@@ -136,6 +136,7 @@ class TestResult:
136
136
  def from_protobuf(test_result_proto: TestResultProto) -> "TestResult":
137
137
  """Create a TestResult instance from a protobuf TestResult message."""
138
138
  test_result = TestResult(
139
+ name=test_result_proto.name,
139
140
  id=test_result_proto.id,
140
141
  uut_instance_id=test_result_proto.uut_instance_id,
141
142
  operator_id=test_result_proto.operator_id,
@@ -144,7 +145,6 @@ class TestResult:
144
145
  software_item_ids=test_result_proto.software_item_ids,
145
146
  hardware_item_ids=test_result_proto.hardware_item_ids,
146
147
  test_adapter_ids=test_result_proto.test_adapter_ids,
147
- name=test_result_proto.name,
148
148
  start_date_time=(
149
149
  hightime_datetime_from_protobuf(test_result_proto.start_date_time)
150
150
  if test_result_proto.HasField("start_date_time")
@@ -1,69 +0,0 @@
1
- """Moniker data type for the Data Store Client."""
2
-
3
- from __future__ import annotations
4
-
5
- from ni.datamonikers.v1.data_moniker_pb2 import Moniker as MonikerProto
6
-
7
-
8
- class Moniker:
9
- """Represents a data moniker for retrieving published data.
10
-
11
- A moniker provides the necessary information to locate and retrieve data
12
- from the data store, including the service location, data source, and
13
- data instance identifiers.
14
- """
15
-
16
- __slots__ = (
17
- "service_location",
18
- "data_source",
19
- "data_instance",
20
- )
21
-
22
- def __init__(
23
- self,
24
- *,
25
- service_location: str = "",
26
- data_source: str = "",
27
- data_instance: int = 0,
28
- ) -> None:
29
- """Initialize a Moniker instance.
30
-
31
- Args:
32
- service_location: The location of the service that stores the data.
33
- data_source: The identifier for the data source.
34
- data_instance: The instance number of the data.
35
- """
36
- self.service_location = service_location
37
- self.data_source = data_source
38
- self.data_instance = data_instance
39
-
40
- @staticmethod
41
- def from_protobuf(moniker_proto: MonikerProto) -> "Moniker":
42
- """Create a Moniker instance from a protobuf Moniker message."""
43
- return Moniker(
44
- service_location=moniker_proto.service_location,
45
- data_source=moniker_proto.data_source,
46
- data_instance=moniker_proto.data_instance,
47
- )
48
-
49
- def to_protobuf(self) -> MonikerProto:
50
- """Convert this Moniker instance to a protobuf Moniker message."""
51
- return MonikerProto(
52
- service_location=self.service_location,
53
- data_source=self.data_source,
54
- data_instance=self.data_instance,
55
- )
56
-
57
- def __eq__(self, other: object) -> bool:
58
- """Determine equality."""
59
- if not isinstance(other, Moniker):
60
- return NotImplemented
61
- return (
62
- self.service_location == other.service_location
63
- and self.data_source == other.data_source
64
- and self.data_instance == other.data_instance
65
- )
66
-
67
- def __str__(self) -> str:
68
- """Return a string representation of the Moniker."""
69
- return str(self.to_protobuf())