ni.datastore 0.1.0.dev4__tar.gz → 0.1.0.dev5__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.dev4 → ni_datastore-0.1.0.dev5}/PKG-INFO +16 -10
  2. {ni_datastore-0.1.0.dev4 → ni_datastore-0.1.0.dev5}/README.md +10 -4
  3. {ni_datastore-0.1.0.dev4 → ni_datastore-0.1.0.dev5}/pyproject.toml +7 -8
  4. {ni_datastore-0.1.0.dev4 → ni_datastore-0.1.0.dev5}/src/ni/datastore/data/__init__.py +3 -2
  5. {ni_datastore-0.1.0.dev4 → ni_datastore-0.1.0.dev5}/src/ni/datastore/data/_data_store_client.py +302 -30
  6. ni_datastore-0.1.0.dev5/src/ni/datastore/data/_types/_error_information.py +73 -0
  7. ni_datastore-0.1.0.dev5/src/ni/datastore/data/_types/_moniker.py +69 -0
  8. ni_datastore-0.1.0.dev5/src/ni/datastore/data/_types/_outcome.py +53 -0
  9. {ni_datastore-0.1.0.dev4 → ni_datastore-0.1.0.dev5}/src/ni/datastore/data/_types/_published_condition.py +29 -11
  10. {ni_datastore-0.1.0.dev4 → ni_datastore-0.1.0.dev5}/src/ni/datastore/data/_types/_published_measurement.py +70 -33
  11. ni_datastore-0.1.0.dev5/src/ni/datastore/data/_types/_step.py +190 -0
  12. {ni_datastore-0.1.0.dev4 → ni_datastore-0.1.0.dev5}/src/ni/datastore/data/_types/_test_result.py +81 -57
  13. {ni_datastore-0.1.0.dev4 → ni_datastore-0.1.0.dev5}/src/ni/datastore/metadata/__init__.py +1 -1
  14. {ni_datastore-0.1.0.dev4 → ni_datastore-0.1.0.dev5}/src/ni/datastore/metadata/_metadata_store_client.py +241 -28
  15. {ni_datastore-0.1.0.dev4 → ni_datastore-0.1.0.dev5}/src/ni/datastore/metadata/_types/_alias.py +26 -15
  16. ni_datastore-0.1.0.dev5/src/ni/datastore/metadata/_types/_alias_target_type.py +75 -0
  17. {ni_datastore-0.1.0.dev4 → ni_datastore-0.1.0.dev5}/src/ni/datastore/metadata/_types/_extension_schema.py +17 -8
  18. {ni_datastore-0.1.0.dev4 → ni_datastore-0.1.0.dev5}/src/ni/datastore/metadata/_types/_hardware_item.py +33 -13
  19. {ni_datastore-0.1.0.dev4 → ni_datastore-0.1.0.dev5}/src/ni/datastore/metadata/_types/_operator.py +34 -19
  20. {ni_datastore-0.1.0.dev4 → ni_datastore-0.1.0.dev5}/src/ni/datastore/metadata/_types/_software_item.py +28 -13
  21. {ni_datastore-0.1.0.dev4 → ni_datastore-0.1.0.dev5}/src/ni/datastore/metadata/_types/_test.py +34 -19
  22. {ni_datastore-0.1.0.dev4 → ni_datastore-0.1.0.dev5}/src/ni/datastore/metadata/_types/_test_adapter.py +35 -13
  23. {ni_datastore-0.1.0.dev4 → ni_datastore-0.1.0.dev5}/src/ni/datastore/metadata/_types/_test_description.py +35 -19
  24. {ni_datastore-0.1.0.dev4 → ni_datastore-0.1.0.dev5}/src/ni/datastore/metadata/_types/_test_station.py +37 -19
  25. {ni_datastore-0.1.0.dev4 → ni_datastore-0.1.0.dev5}/src/ni/datastore/metadata/_types/_uut.py +33 -13
  26. {ni_datastore-0.1.0.dev4 → ni_datastore-0.1.0.dev5}/src/ni/datastore/metadata/_types/_uut_instance.py +35 -13
  27. ni_datastore-0.1.0.dev4/src/ni/datastore/data/_types/_step.py +0 -157
  28. {ni_datastore-0.1.0.dev4 → ni_datastore-0.1.0.dev5}/LICENSE +0 -0
  29. {ni_datastore-0.1.0.dev4 → ni_datastore-0.1.0.dev5}/src/ni/datastore/__init__.py +0 -0
  30. {ni_datastore-0.1.0.dev4 → ni_datastore-0.1.0.dev5}/src/ni/datastore/data/_grpc_conversion.py +0 -0
  31. {ni_datastore-0.1.0.dev4 → ni_datastore-0.1.0.dev5}/src/ni/datastore/data/_types/__init__.py +0 -0
  32. {ni_datastore-0.1.0.dev4 → ni_datastore-0.1.0.dev5}/src/ni/datastore/data/_types/py.typed +0 -0
  33. {ni_datastore-0.1.0.dev4 → ni_datastore-0.1.0.dev5}/src/ni/datastore/data/py.typed +0 -0
  34. {ni_datastore-0.1.0.dev4 → ni_datastore-0.1.0.dev5}/src/ni/datastore/metadata/_grpc_conversion.py +0 -0
  35. {ni_datastore-0.1.0.dev4 → ni_datastore-0.1.0.dev5}/src/ni/datastore/metadata/_types/__init__.py +0 -0
  36. {ni_datastore-0.1.0.dev4 → ni_datastore-0.1.0.dev5}/src/ni/datastore/metadata/_types/py.typed +0 -0
  37. {ni_datastore-0.1.0.dev4 → ni_datastore-0.1.0.dev5}/src/ni/datastore/metadata/py.typed +0 -0
  38. {ni_datastore-0.1.0.dev4 → ni_datastore-0.1.0.dev5}/src/ni/datastore/py.typed +0 -0
@@ -1,14 +1,14 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: ni.datastore
3
- Version: 0.1.0.dev4
4
- Summary: APIs for publishing and retrieving data from the NI Measurement Data Store
3
+ Version: 0.1.0.dev5
4
+ Summary: APIs for publishing and retrieving data from NI Measurement Data Services
5
5
  License: MIT
6
6
  Keywords: datastore
7
7
  Author: NI
8
8
  Author-email: opensource@ni.com
9
9
  Maintainer: Johann Scholtz
10
10
  Maintainer-email: johann.scholtz@emerson.com
11
- Requires-Python: >=3.9,<4.0
11
+ Requires-Python: >=3.10,<4.0
12
12
  Classifier: Development Status :: 3 - Alpha
13
13
  Classifier: Intended Audience :: Developers
14
14
  Classifier: Intended Audience :: Manufacturing
@@ -17,16 +17,16 @@ Classifier: License :: OSI Approved :: MIT License
17
17
  Classifier: Operating System :: Microsoft :: Windows
18
18
  Classifier: Operating System :: POSIX
19
19
  Classifier: Programming Language :: Python :: 3
20
- Classifier: Programming Language :: Python :: 3.9
21
20
  Classifier: Programming Language :: Python :: 3.10
22
21
  Classifier: Programming Language :: Python :: 3.11
23
22
  Classifier: Programming Language :: Python :: 3.12
24
23
  Classifier: Programming Language :: Python :: 3.13
24
+ Classifier: Programming Language :: Python :: 3.14
25
25
  Classifier: Programming Language :: Python :: Implementation :: CPython
26
26
  Requires-Dist: hightime (>=0.3.0.dev0)
27
27
  Requires-Dist: ni-datamonikers-v1-client (>=0.1.0.dev1)
28
- Requires-Dist: ni-measurements-data-v1-client (>=0.1.0.dev2)
29
- Requires-Dist: ni-measurements-metadata-v1-client (>=0.1.0.dev2)
28
+ Requires-Dist: ni-measurements-data-v1-client (>=0.2.0.dev1)
29
+ Requires-Dist: ni-measurements-metadata-v1-client (>=0.2.0.dev1)
30
30
  Requires-Dist: ni-protobuf-types (>=1.0.1.dev0)
31
31
  Requires-Dist: protobuf (>=4.21)
32
32
  Description-Content-Type: text/markdown
@@ -34,21 +34,23 @@ Description-Content-Type: text/markdown
34
34
  # Table of Contents
35
35
 
36
36
  - [Table of Contents](#table-of-contents)
37
+ - [Measurement Data Services API for Python](#measurement-data-services-api-for-python)
37
38
  - [About](#about)
38
39
  - [Operating System Support](#operating-system-support)
39
40
  - [Python Version Support](#python-version-support)
41
+ - [Installation](#installation)
40
42
 
41
- # Measurement Data Store API for Python
43
+ # Measurement Data Services API for Python
42
44
 
43
45
  `datastore-python` contains Python code for writing to and reading from
44
- the [NI Measurement Data Store](https://github.com/ni/datastore-service).
46
+ [NI Measurement Data Services](https://github.com/ni/datastore-service).
45
47
  It will include examples of how to use the Python API.
46
48
 
47
49
  # About
48
50
 
49
51
  `ni.datastore` is the main Python package in this repo that
50
52
  provides APIs for publishing and retrieving data from the NI
51
- Measurement Data Store
53
+ Measurement Data Services
52
54
 
53
55
  NI created and supports this package.
54
56
 
@@ -58,10 +60,14 @@ NI created and supports this package.
58
60
 
59
61
  ## Python Version Support
60
62
 
61
- `ni.datastore` supports CPython 3.9+.
63
+ `ni.datastore` supports CPython 3.10+.
62
64
 
63
65
  ## Installation
64
66
 
67
+ As a prerequisite to using the `ni.datastore` module, you must install Measurement Data Services
68
+ Software 2026 Q1 or later on your system. You can download and install this software using
69
+ [NI Package Manager](https://www.ni.com/en/support/downloads/software-products/download.package-manager.html).
70
+
65
71
  You can directly install the `ni.datastore` package using `pip` or by listing it as a
66
72
  dependency in your project's `pyproject.toml` file.
67
73
 
@@ -1,21 +1,23 @@
1
1
  # Table of Contents
2
2
 
3
3
  - [Table of Contents](#table-of-contents)
4
+ - [Measurement Data Services API for Python](#measurement-data-services-api-for-python)
4
5
  - [About](#about)
5
6
  - [Operating System Support](#operating-system-support)
6
7
  - [Python Version Support](#python-version-support)
8
+ - [Installation](#installation)
7
9
 
8
- # Measurement Data Store API for Python
10
+ # Measurement Data Services API for Python
9
11
 
10
12
  `datastore-python` contains Python code for writing to and reading from
11
- the [NI Measurement Data Store](https://github.com/ni/datastore-service).
13
+ [NI Measurement Data Services](https://github.com/ni/datastore-service).
12
14
  It will include examples of how to use the Python API.
13
15
 
14
16
  # About
15
17
 
16
18
  `ni.datastore` is the main Python package in this repo that
17
19
  provides APIs for publishing and retrieving data from the NI
18
- Measurement Data Store
20
+ Measurement Data Services
19
21
 
20
22
  NI created and supports this package.
21
23
 
@@ -25,9 +27,13 @@ NI created and supports this package.
25
27
 
26
28
  ## Python Version Support
27
29
 
28
- `ni.datastore` supports CPython 3.9+.
30
+ `ni.datastore` supports CPython 3.10+.
29
31
 
30
32
  ## Installation
31
33
 
34
+ As a prerequisite to using the `ni.datastore` module, you must install Measurement Data Services
35
+ Software 2026 Q1 or later on your system. You can download and install this software using
36
+ [NI Package Manager](https://www.ni.com/en/support/downloads/software-products/download.package-manager.html).
37
+
32
38
  You can directly install the `ni.datastore` package using `pip` or by listing it as a
33
39
  dependency in your project's `pyproject.toml` file.
@@ -1,8 +1,8 @@
1
1
  [project]
2
2
  name = "ni.datastore"
3
- version = "0.1.0.dev4"
3
+ version = "0.1.0.dev5"
4
4
  license = "MIT"
5
- description = "APIs for publishing and retrieving data from the NI Measurement Data Store"
5
+ description = "APIs for publishing and retrieving data from NI Measurement Data Services"
6
6
  authors = [{name = "NI", email = "opensource@ni.com"}]
7
7
  maintainers = [
8
8
  {name = "Johann Scholtz", email = "johann.scholtz@emerson.com"},
@@ -20,26 +20,26 @@ classifiers = [
20
20
  "Operating System :: Microsoft :: Windows",
21
21
  "Operating System :: POSIX",
22
22
  "Programming Language :: Python :: 3",
23
- "Programming Language :: Python :: 3.9",
24
23
  "Programming Language :: Python :: 3.10",
25
24
  "Programming Language :: Python :: 3.11",
26
25
  "Programming Language :: Python :: 3.12",
27
26
  "Programming Language :: Python :: 3.13",
27
+ "Programming Language :: Python :: 3.14",
28
28
  "Programming Language :: Python :: Implementation :: CPython",
29
29
  ]
30
30
  dynamic = ["dependencies"]
31
- requires-python = '>=3.9,<4.0'
31
+ requires-python = '>=3.10,<4.0'
32
32
 
33
33
  [tool.poetry]
34
34
  packages = [{include = "ni", from = "src"}]
35
35
  requires-poetry = '>=2.1,<3.0'
36
36
 
37
37
  [tool.poetry.dependencies]
38
- python = "^3.9"
38
+ python = "^3.10"
39
39
  protobuf = {version=">=4.21"}
40
40
  ni-datamonikers-v1-client = { version = ">=0.1.0.dev1", allow-prereleases = true }
41
- ni-measurements-data-v1-client = { version = ">=0.1.0.dev2", allow-prereleases = true }
42
- ni-measurements-metadata-v1-client = { version = ">=0.1.0.dev2", allow-prereleases = true }
41
+ ni-measurements-data-v1-client = { version = ">=0.2.0.dev1", allow-prereleases = true }
42
+ ni-measurements-metadata-v1-client = { version = ">=0.2.0.dev1", allow-prereleases = true }
43
43
  ni-protobuf-types = { version = ">=1.0.1.dev0", allow-prereleases = true }
44
44
  hightime = { version = ">=0.3.0.dev0", allow-prereleases = true }
45
45
 
@@ -70,7 +70,6 @@ optional = true
70
70
  [tool.poetry.group.docs.dependencies]
71
71
  # The latest Sphinx requires a recent Python version.
72
72
  Sphinx = [
73
- { version = ">=7.4", python = ">=3.9,<3.10" },
74
73
  { version = ">=8.1", python = ">=3.10,<3.11" },
75
74
  { version = ">=8.2", python = "^3.11" },
76
75
  ]
@@ -1,12 +1,13 @@
1
1
  """Public API for accessing the NI Data Store."""
2
2
 
3
- from ni.datamonikers.v1.data_moniker_pb2 import Moniker
4
3
  from ni.datastore.data._data_store_client import DataStoreClient
4
+ from ni.datastore.data._types._error_information import ErrorInformation
5
+ from ni.datastore.data._types._moniker import Moniker
6
+ from ni.datastore.data._types._outcome import Outcome
5
7
  from ni.datastore.data._types._published_condition import PublishedCondition
6
8
  from ni.datastore.data._types._published_measurement import PublishedMeasurement
7
9
  from ni.datastore.data._types._step import Step
8
10
  from ni.datastore.data._types._test_result import TestResult
9
- from ni.measurements.data.v1.data_store_pb2 import ErrorInformation, Outcome
10
11
 
11
12
  __all__ = [
12
13
  "DataStoreClient",
@@ -13,7 +13,6 @@ from urllib.parse import urlparse
13
13
  import hightime as ht
14
14
  from grpc import Channel
15
15
  from ni.datamonikers.v1.client import MonikerClient
16
- from ni.datamonikers.v1.data_moniker_pb2 import Moniker
17
16
  from ni.datastore.data._grpc_conversion import (
18
17
  get_publish_measurement_timestamp,
19
18
  populate_publish_condition_batch_request_values,
@@ -22,16 +21,15 @@ from ni.datastore.data._grpc_conversion import (
22
21
  populate_publish_measurement_request_value,
23
22
  unpack_and_convert_from_protobuf_any,
24
23
  )
24
+ from ni.datastore.data._types._error_information import ErrorInformation
25
+ from ni.datastore.data._types._moniker import Moniker
26
+ from ni.datastore.data._types._outcome import Outcome
25
27
  from ni.datastore.data._types._published_condition import PublishedCondition
26
28
  from ni.datastore.data._types._published_measurement import PublishedMeasurement
27
29
  from ni.datastore.data._types._step import Step
28
30
  from ni.datastore.data._types._test_result import TestResult
29
31
  from ni.measurementlink.discovery.v1.client import DiscoveryClient
30
32
  from ni.measurements.data.v1.client import DataStoreClient as DataStoreServiceClient
31
- from ni.measurements.data.v1.data_store_pb2 import (
32
- ErrorInformation,
33
- Outcome,
34
- )
35
33
  from ni.measurements.data.v1.data_store_service_pb2 import (
36
34
  CreateStepRequest,
37
35
  CreateTestResultRequest,
@@ -151,7 +149,30 @@ class DataStoreClient:
151
149
  value: object,
152
150
  step_id: str,
153
151
  ) -> PublishedCondition:
154
- """Publish a condition value to the data store."""
152
+ """Publish a condition value to the data store.
153
+
154
+ Args:
155
+ condition_name: An identifier describing the condition value.
156
+ For example, "Voltage" or "Temperature".
157
+
158
+ type: The type of this condition. For example, "Upper Limit",
159
+ "Environment", or "Setup".
160
+
161
+ value: The single value for this condition to publish on the test
162
+ step. This should be a scalar value that can be converted to
163
+ the appropriate protobuf scalar type.
164
+
165
+ step_id: The ID of the step associated with this condition. This
166
+ value is expected to be a parsable GUID.
167
+
168
+ Returns:
169
+ PublishedCondition: The published condition containing:
170
+ - A moniker for retrieving the condition data (returns a
171
+ Vector)
172
+ - The unique ID of the condition for referencing in queries
173
+ - Metadata including condition name, type, step ID and test
174
+ result ID
175
+ """
155
176
  publish_request = PublishConditionRequest(
156
177
  condition_name=condition_name,
157
178
  type=type,
@@ -164,7 +185,31 @@ class DataStoreClient:
164
185
  def publish_condition_batch(
165
186
  self, condition_name: str, type: str, values: object, step_id: str
166
187
  ) -> PublishedCondition:
167
- """Publish a batch of N values for a condition to the data store."""
188
+ """Publish a batch of N values for a condition to the data store.
189
+
190
+ Args:
191
+ condition_name: An identifier describing the condition values.
192
+ For example, "Voltage" or "Temperature".
193
+
194
+ type: The type of this condition. For example, "Upper Limit",
195
+ "Environment", or "Setup".
196
+
197
+ values: The values for this condition across all publishes on the
198
+ test step. This should be a Vector of N values.
199
+
200
+ step_id: The ID of the step associated with this batch of condition
201
+ values. This value is expected to be a parsable GUID.
202
+
203
+ Returns:
204
+ PublishedCondition: Represents all the values published with
205
+ this call, containing:
206
+
207
+ - A moniker for retrieving the condition data (returns a
208
+ Vector)
209
+ - The unique ID of the condition for referencing in queries
210
+ - Metadata including condition name, type, step ID and test
211
+ result ID
212
+ """
168
213
  publish_request = PublishConditionBatchRequest(
169
214
  condition_name=condition_name,
170
215
  type=type,
@@ -180,19 +225,74 @@ class DataStoreClient:
180
225
  value: object, # More strongly typed Union[bool, AnalogWaveform] can be used if needed
181
226
  step_id: str,
182
227
  timestamp: ht.datetime | None = None,
183
- outcome: Outcome.ValueType = Outcome.OUTCOME_UNSPECIFIED,
228
+ outcome: Outcome = Outcome.UNSPECIFIED,
184
229
  error_information: ErrorInformation | None = None,
185
230
  hardware_item_ids: Iterable[str] = tuple(),
186
231
  test_adapter_ids: Iterable[str] = tuple(),
187
232
  software_item_ids: Iterable[str] = tuple(),
188
233
  notes: str = "",
189
234
  ) -> PublishedMeasurement:
190
- """Publish a measurement value to the data store."""
235
+ """Publish a single measurement value associated with a test step.
236
+
237
+ Args:
238
+ measurement_name: The name used for associating/grouping
239
+ conceptually alike measurements across multiple publish
240
+ iterations. For example, "Temperature" can be used for
241
+ associating temperature readings across multiple iterations.
242
+
243
+ value: The value of the measurement being published. Supported types:
244
+
245
+ - Scalar: Single float, int, str or boolean
246
+ - Vector: Array of float, int, str or boolean values
247
+ - DoubleAnalogWaveform: Analog waveform with double precision
248
+ - DoubleXYData: XY coordinate data with double precision
249
+ - I16AnalogWaveform: Analog waveform with 16-bit integer precision
250
+ - DoubleComplexWaveform: Complex waveform with double precision
251
+ - I16ComplexWaveform: Complex waveform with 16-bit integer precision
252
+ - DoubleSpectrum: Frequency spectrum data with double precision
253
+ - DigitalWaveform: Digital waveform data
254
+
255
+ step_id: The ID of the step associated with this measurement. This
256
+ value is expected to be a parsable GUID.
257
+
258
+ timestamp: The timestamp of the measurement. If None, the current
259
+ time will be used.
260
+
261
+ outcome: The outcome of the measurement (PASSED, FAILED,
262
+ INDETERMINATE, or UNSPECIFIED).
263
+
264
+ error_information: Error or exception information in case of
265
+ measurement failure.
266
+
267
+ hardware_item_ids: The IDs of the hardware items associated with
268
+ this measurement. These values are expected to be parsable
269
+ GUIDs or aliases.
270
+
271
+ test_adapter_ids: The IDs of the test adapters associated with this
272
+ measurement. These values are expected to be parsable GUIDs or
273
+ aliases.
274
+
275
+ software_item_ids: The IDs of the software items associated with
276
+ this measurement. These values are expected to be parsable
277
+ GUIDs or aliases.
278
+
279
+ notes: Any notes to be associated with the captured measurement.
280
+
281
+ Returns:
282
+ PublishedMeasurement: The moniker of the published measurement and
283
+ its metadata, including:
284
+ - A moniker for retrieving the measurement data
285
+ - Associated conditions from the test step
286
+ - Measurement metadata (name, type, timestamps, outcome)
287
+ - Associated hardware, software, and test adapter IDs
288
+ """
191
289
  publish_request = PublishMeasurementRequest(
192
290
  measurement_name=measurement_name,
193
291
  step_id=step_id,
194
- outcome=outcome,
195
- error_information=error_information,
292
+ outcome=outcome.to_protobuf(),
293
+ error_information=(
294
+ error_information.to_protobuf() if error_information is not None else None
295
+ ),
196
296
  hardware_item_ids=hardware_item_ids,
197
297
  test_adapter_ids=test_adapter_ids,
198
298
  software_item_ids=software_item_ids,
@@ -211,22 +311,75 @@ class DataStoreClient:
211
311
  values: object,
212
312
  step_id: str,
213
313
  timestamps: Iterable[ht.datetime] = tuple(),
214
- outcomes: Iterable[Outcome.ValueType] = tuple(),
314
+ outcomes: Iterable[Outcome] = tuple(),
215
315
  error_information: Iterable[ErrorInformation] = tuple(),
216
316
  hardware_item_ids: Iterable[str] = tuple(),
217
317
  test_adapter_ids: Iterable[str] = tuple(),
218
318
  software_item_ids: Iterable[str] = tuple(),
319
+ notes: str = "",
219
320
  ) -> Sequence[PublishedMeasurement]:
220
- """Publish a batch of N values of a measurement to the data store."""
321
+ """Publish multiple scalar measurements at once for parametric sweeps.
322
+
323
+ Args:
324
+ measurement_name: The name used for associating/grouping
325
+ conceptually alike measurements across multiple publish
326
+ iterations. For example, "Temperature" can be used for
327
+ associating temperature readings across multiple iterations.
328
+
329
+ values: The values of the (scalar) measurement being published
330
+ across N iterations.
331
+
332
+ step_id: The ID of the step associated with this measurement. This
333
+ value is expected to be a parsable GUID.
334
+
335
+ timestamps: The timestamps corresponding to the N iterations of
336
+ batched measurement being published. Can be empty (no timestamp
337
+ info), single value (applied to all), or N values (one per
338
+ measurement).
339
+
340
+ outcomes: The outcomes corresponding to the N iterations of batched
341
+ measurement being published. Can be empty (no outcome info),
342
+ single value (applied to all), or N values (one per
343
+ measurement).
344
+
345
+ error_information: The error information corresponding to the N
346
+ iterations of batched measurement being published. Can be empty
347
+ (no error info), single value (applied to all), or N values
348
+ (one per measurement).
349
+
350
+ hardware_item_ids: The IDs of the hardware items associated with
351
+ this measurement. These values are expected to be parsable
352
+ GUIDs or aliases.
353
+
354
+ test_adapter_ids: The IDs of the test adapters associated with this
355
+ measurement. These values are expected to be parsable GUIDs or
356
+ aliases.
357
+
358
+ software_item_ids: The IDs of the software items associated with
359
+ this measurement. These values are expected to be parsable
360
+ GUIDs or aliases.
361
+
362
+ notes: Any notes to be associated with the published measurements.
363
+
364
+ Returns:
365
+ Sequence[PublishedMeasurement]: The monikers of the published
366
+ measurements and their corresponding metadata. NOTE: Using
367
+ a Sequence is for future flexibility. This sequence
368
+ will currently always have a single PublishedMeasurement
369
+ returned.
370
+ """
221
371
  publish_request = PublishMeasurementBatchRequest(
222
372
  measurement_name=measurement_name,
223
373
  step_id=step_id,
224
- timestamp=[hightime_datetime_to_protobuf(ts) for ts in timestamps],
225
- outcome=outcomes,
226
- error_information=error_information,
374
+ timestamps=[hightime_datetime_to_protobuf(ts) for ts in timestamps],
375
+ outcomes=[outcome.to_protobuf() for outcome in outcomes],
376
+ error_information=(
377
+ [ei.to_protobuf() for ei in (error_information or [])] if error_information else []
378
+ ),
227
379
  hardware_item_ids=hardware_item_ids,
228
380
  test_adapter_ids=test_adapter_ids,
229
381
  software_item_ids=software_item_ids,
382
+ notes=notes,
230
383
  )
231
384
  populate_publish_measurement_batch_request_values(publish_request, values)
232
385
  publish_response = self._get_data_store_client().publish_measurement_batch(publish_request)
@@ -252,51 +405,132 @@ class DataStoreClient:
252
405
  moniker_source: Moniker | PublishedMeasurement | PublishedCondition,
253
406
  expected_type: Type[TRead] | None = None,
254
407
  ) -> TRead | object:
255
- """Read data published to the data store."""
408
+ """Read data published to the data store.
409
+
410
+ Args:
411
+ moniker_source: The source from which to read data. Can be:
412
+ - A Moniker (wrapper type) directly
413
+ - A PublishedMeasurement (uses its moniker)
414
+ - A PublishedCondition (uses its moniker)
415
+
416
+ expected_type: Optional type to validate the returned data against.
417
+ If provided, a TypeError will be raised if the actual data type
418
+ doesn't match.
419
+
420
+ Returns:
421
+ The data retrieved from the data store. The return type depends on
422
+ what was originally published:
423
+ - Scalar measurements return as Vectors
424
+ - Other types are returned as originally published
425
+ If expected_type is specified, the return value is guaranteed to be
426
+ of that type.
427
+
428
+ Raises:
429
+ ValueError: If the moniker_source doesn't have a valid moniker.
430
+ TypeError: If expected_type is provided and the actual data type
431
+ doesn't match.
432
+ """
433
+ from ni.datamonikers.v1.data_moniker_pb2 import Moniker as MonikerProto
434
+
435
+ moniker_proto: MonikerProto
436
+
256
437
  if isinstance(moniker_source, Moniker):
257
- moniker = moniker_source
438
+ moniker_proto = moniker_source.to_protobuf()
258
439
  elif isinstance(moniker_source, PublishedMeasurement):
259
440
  if moniker_source.moniker is None:
260
441
  raise ValueError("PublishedMeasurement must have a Moniker to read data")
261
- moniker = moniker_source.moniker
442
+ moniker_proto = moniker_source.moniker.to_protobuf()
262
443
  elif isinstance(moniker_source, PublishedCondition):
263
444
  if moniker_source.moniker is None:
264
445
  raise ValueError("PublishedCondition must have a Moniker to read data")
265
- moniker = moniker_source.moniker
446
+ moniker_proto = moniker_source.moniker.to_protobuf()
447
+ else:
448
+ raise TypeError(f"Unsupported moniker_source type: {type(moniker_source)}")
266
449
 
267
- moniker_client = self._get_moniker_client(moniker.service_location)
268
- read_result = moniker_client.read_from_moniker(moniker)
450
+ moniker_client = self._get_moniker_client(moniker_proto.service_location)
451
+ read_result = moniker_client.read_from_moniker(moniker_proto)
269
452
  converted_data = unpack_and_convert_from_protobuf_any(read_result.value)
270
453
  if expected_type is not None and not isinstance(converted_data, expected_type):
271
454
  raise TypeError(f"Expected type {expected_type}, got {type(converted_data)}")
272
455
  return converted_data
273
456
 
274
457
  def create_step(self, step: Step) -> str:
275
- """Create a step in the data store."""
458
+ """Create a new step in the data store.
459
+
460
+ A step is owned by a test result and is a logical grouping of published
461
+ measurements and conditions. All measurements and conditions must be
462
+ associated with a step.
463
+
464
+ Args:
465
+ step: The metadata of the step to be created.
466
+
467
+ Returns:
468
+ str: The identifier of the created step.
469
+ """
276
470
  create_request = CreateStepRequest(step=step.to_protobuf())
277
471
  create_response = self._get_data_store_client().create_step(create_request)
278
472
  return create_response.step_id
279
473
 
280
474
  def get_step(self, step_id: str) -> Step:
281
- """Get a step from the data store."""
475
+ """Get the step associated with the given identifier.
476
+
477
+ Args:
478
+ step_id: The identifier of the desired step.
479
+
480
+ Returns:
481
+ Step: The metadata of the requested step.
482
+ """
282
483
  get_request = GetStepRequest(step_id=step_id)
283
484
  get_response = self._get_data_store_client().get_step(get_request)
284
485
  return Step.from_protobuf(get_response.step)
285
486
 
286
487
  def create_test_result(self, test_result: TestResult) -> str:
287
- """Create a test result in the data store."""
488
+ """Create a test result object for publishing measurements.
489
+
490
+ Once a test result is created, you can publish an arbitrary number of
491
+ measurements and conditions to a step which is owned by the test result.
492
+
493
+ Args:
494
+ test_result: The metadata of the test result to be created.
495
+
496
+ Returns:
497
+ str: The test result ID. Generated if not specified in the request.
498
+ """
288
499
  create_request = CreateTestResultRequest(test_result=test_result.to_protobuf())
289
500
  create_response = self._get_data_store_client().create_test_result(create_request)
290
501
  return create_response.test_result_id
291
502
 
292
503
  def get_test_result(self, test_result_id: str) -> TestResult:
293
- """Get a test result from the data store."""
504
+ """Get the test result associated with the given identifier.
505
+
506
+ Args:
507
+ test_result_id: The ID of the desired test result. This value is
508
+ expected to be a parsable GUID.
509
+
510
+ Returns:
511
+ TestResult: The TestResult object that corresponds to the
512
+ requested ID.
513
+ """
294
514
  get_request = GetTestResultRequest(test_result_id=test_result_id)
295
515
  get_response = self._get_data_store_client().get_test_result(get_request)
296
516
  return TestResult.from_protobuf(get_response.test_result)
297
517
 
298
518
  def query_conditions(self, odata_query: str = "") -> Sequence[PublishedCondition]:
299
- """Query conditions from the data store."""
519
+ """Query conditions using OData query syntax.
520
+
521
+ Args:
522
+ odata_query: An OData query string. Example: "$filter=name eq
523
+ 'Value'". An empty string will return all conditions. $expand,
524
+ $count, and $select are not supported. For more information,
525
+ see https://learn.microsoft.com/en-us/odata/concepts/
526
+ queryoptions-overview.
527
+
528
+ Returns:
529
+ Sequence[PublishedCondition]: The list of matching conditions. Each
530
+ item contains a moniker for retrieving the condition
531
+ measurements, as well as the metadata associated with the
532
+ condition.
533
+ """
300
534
  query_request = QueryConditionsRequest(odata_query=odata_query)
301
535
  query_response = self._get_data_store_client().query_conditions(query_request)
302
536
  return [
@@ -305,7 +539,20 @@ class DataStoreClient:
305
539
  ]
306
540
 
307
541
  def query_measurements(self, odata_query: str = "") -> Sequence[PublishedMeasurement]:
308
- """Query measurements from the data store."""
542
+ """Query measurements using OData query syntax.
543
+
544
+ Args:
545
+ odata_query: An OData query string. Example: "$filter=name eq
546
+ 'Value'". An empty string will return all measurements.
547
+ $expand, $count, and $select are not supported. For more
548
+ information, see https://learn.microsoft.com/en-us/odata/
549
+ concepts/queryoptions-overview.
550
+
551
+ Returns:
552
+ Sequence[PublishedMeasurement]: The list of matching measurements.
553
+ Each item contains a moniker for retrieving the measurement, as
554
+ well as the metadata associated with the measurement.
555
+ """
309
556
  query_request = QueryMeasurementsRequest(odata_query=odata_query)
310
557
  query_response = self._get_data_store_client().query_measurements(query_request)
311
558
  return [
@@ -314,7 +561,21 @@ class DataStoreClient:
314
561
  ]
315
562
 
316
563
  def query_test_results(self, odata_query: str = "") -> Sequence[TestResult]:
317
- """Query test results from the data store."""
564
+ """Query test results using OData query syntax.
565
+
566
+ Args:
567
+ odata_query: An OData query string. Example: "$filter=name eq
568
+ 'Value'". An empty string will return all test results.
569
+ $expand, $count, and $select are not supported. For more
570
+ information, see https://learn.microsoft.com/en-us/odata/
571
+ concepts/queryoptions-overview.
572
+
573
+ Returns:
574
+ Sequence[TestResult]: The list of matching test results. Each
575
+ item contains the metadata associated with the test result,
576
+ including test result ID, name, timestamps, and other
577
+ properties.
578
+ """
318
579
  query_request = QueryTestResultsRequest(odata_query=odata_query)
319
580
  query_response = self._get_data_store_client().query_test_results(query_request)
320
581
  return [
@@ -322,7 +583,18 @@ class DataStoreClient:
322
583
  ]
323
584
 
324
585
  def query_steps(self, odata_query: str = "") -> Sequence[Step]:
325
- """Query steps from the data store."""
586
+ """Query for steps matching the given OData query.
587
+
588
+ Args:
589
+ odata_query: An OData query string. Example: "$filter=name eq
590
+ 'Value'". An empty string will return all steps. $expand,
591
+ $count, and $select are not supported. For more information,
592
+ see https://learn.microsoft.com/en-us/odata/concepts/
593
+ queryoptions-overview.
594
+
595
+ Returns:
596
+ Sequence[Step]: The list of steps that match the query.
597
+ """
326
598
  query_request = QueryStepsRequest(odata_query=odata_query)
327
599
  query_response = self._get_data_store_client().query_steps(query_request)
328
600
  return [Step.from_protobuf(step) for step in query_response.steps]