ni.datastore 0.1.0.dev5__tar.gz → 0.1.0.dev6__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.dev5 → ni_datastore-0.1.0.dev6}/PKG-INFO +3 -3
  2. {ni_datastore-0.1.0.dev5 → ni_datastore-0.1.0.dev6}/pyproject.toml +6 -6
  3. {ni_datastore-0.1.0.dev5 → ni_datastore-0.1.0.dev6}/src/ni/datastore/data/_data_store_client.py +65 -52
  4. {ni_datastore-0.1.0.dev5 → ni_datastore-0.1.0.dev6}/src/ni/datastore/metadata/__init__.py +3 -0
  5. {ni_datastore-0.1.0.dev5 → ni_datastore-0.1.0.dev6}/src/ni/datastore/metadata/_metadata_store_client.py +64 -23
  6. ni_datastore-0.1.0.dev6/src/ni/datastore/metadata/_types/_metadata_items.py +155 -0
  7. {ni_datastore-0.1.0.dev5 → ni_datastore-0.1.0.dev6}/LICENSE +0 -0
  8. {ni_datastore-0.1.0.dev5 → ni_datastore-0.1.0.dev6}/README.md +0 -0
  9. {ni_datastore-0.1.0.dev5 → ni_datastore-0.1.0.dev6}/src/ni/datastore/__init__.py +0 -0
  10. {ni_datastore-0.1.0.dev5 → ni_datastore-0.1.0.dev6}/src/ni/datastore/data/__init__.py +0 -0
  11. {ni_datastore-0.1.0.dev5 → ni_datastore-0.1.0.dev6}/src/ni/datastore/data/_grpc_conversion.py +0 -0
  12. {ni_datastore-0.1.0.dev5 → ni_datastore-0.1.0.dev6}/src/ni/datastore/data/_types/__init__.py +0 -0
  13. {ni_datastore-0.1.0.dev5 → ni_datastore-0.1.0.dev6}/src/ni/datastore/data/_types/_error_information.py +0 -0
  14. {ni_datastore-0.1.0.dev5 → ni_datastore-0.1.0.dev6}/src/ni/datastore/data/_types/_moniker.py +0 -0
  15. {ni_datastore-0.1.0.dev5 → ni_datastore-0.1.0.dev6}/src/ni/datastore/data/_types/_outcome.py +0 -0
  16. {ni_datastore-0.1.0.dev5 → ni_datastore-0.1.0.dev6}/src/ni/datastore/data/_types/_published_condition.py +0 -0
  17. {ni_datastore-0.1.0.dev5 → ni_datastore-0.1.0.dev6}/src/ni/datastore/data/_types/_published_measurement.py +0 -0
  18. {ni_datastore-0.1.0.dev5 → ni_datastore-0.1.0.dev6}/src/ni/datastore/data/_types/_step.py +0 -0
  19. {ni_datastore-0.1.0.dev5 → ni_datastore-0.1.0.dev6}/src/ni/datastore/data/_types/_test_result.py +0 -0
  20. {ni_datastore-0.1.0.dev5 → ni_datastore-0.1.0.dev6}/src/ni/datastore/data/_types/py.typed +0 -0
  21. {ni_datastore-0.1.0.dev5 → ni_datastore-0.1.0.dev6}/src/ni/datastore/data/py.typed +0 -0
  22. {ni_datastore-0.1.0.dev5 → ni_datastore-0.1.0.dev6}/src/ni/datastore/metadata/_grpc_conversion.py +0 -0
  23. {ni_datastore-0.1.0.dev5 → ni_datastore-0.1.0.dev6}/src/ni/datastore/metadata/_types/__init__.py +0 -0
  24. {ni_datastore-0.1.0.dev5 → ni_datastore-0.1.0.dev6}/src/ni/datastore/metadata/_types/_alias.py +0 -0
  25. {ni_datastore-0.1.0.dev5 → ni_datastore-0.1.0.dev6}/src/ni/datastore/metadata/_types/_alias_target_type.py +0 -0
  26. {ni_datastore-0.1.0.dev5 → ni_datastore-0.1.0.dev6}/src/ni/datastore/metadata/_types/_extension_schema.py +0 -0
  27. {ni_datastore-0.1.0.dev5 → ni_datastore-0.1.0.dev6}/src/ni/datastore/metadata/_types/_hardware_item.py +0 -0
  28. {ni_datastore-0.1.0.dev5 → ni_datastore-0.1.0.dev6}/src/ni/datastore/metadata/_types/_operator.py +0 -0
  29. {ni_datastore-0.1.0.dev5 → ni_datastore-0.1.0.dev6}/src/ni/datastore/metadata/_types/_software_item.py +0 -0
  30. {ni_datastore-0.1.0.dev5 → ni_datastore-0.1.0.dev6}/src/ni/datastore/metadata/_types/_test.py +0 -0
  31. {ni_datastore-0.1.0.dev5 → ni_datastore-0.1.0.dev6}/src/ni/datastore/metadata/_types/_test_adapter.py +0 -0
  32. {ni_datastore-0.1.0.dev5 → ni_datastore-0.1.0.dev6}/src/ni/datastore/metadata/_types/_test_description.py +0 -0
  33. {ni_datastore-0.1.0.dev5 → ni_datastore-0.1.0.dev6}/src/ni/datastore/metadata/_types/_test_station.py +0 -0
  34. {ni_datastore-0.1.0.dev5 → ni_datastore-0.1.0.dev6}/src/ni/datastore/metadata/_types/_uut.py +0 -0
  35. {ni_datastore-0.1.0.dev5 → ni_datastore-0.1.0.dev6}/src/ni/datastore/metadata/_types/_uut_instance.py +0 -0
  36. {ni_datastore-0.1.0.dev5 → ni_datastore-0.1.0.dev6}/src/ni/datastore/metadata/_types/py.typed +0 -0
  37. {ni_datastore-0.1.0.dev5 → ni_datastore-0.1.0.dev6}/src/ni/datastore/metadata/py.typed +0 -0
  38. {ni_datastore-0.1.0.dev5 → ni_datastore-0.1.0.dev6}/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.dev5
3
+ Version: 0.1.0.dev6
4
4
  Summary: APIs for publishing and retrieving data from NI Measurement Data Services
5
5
  License: MIT
6
6
  Keywords: datastore
@@ -25,8 +25,8 @@ 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.2.0.dev1)
29
- Requires-Dist: ni-measurements-metadata-v1-client (>=0.2.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
30
  Requires-Dist: ni-protobuf-types (>=1.0.1.dev0)
31
31
  Requires-Dist: protobuf (>=4.21)
32
32
  Description-Content-Type: text/markdown
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "ni.datastore"
3
- version = "0.1.0.dev5"
3
+ version = "0.1.0.dev6"
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"}]
@@ -38,8 +38,8 @@ requires-poetry = '>=2.1,<3.0'
38
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.2.0.dev1", allow-prereleases = true }
42
- ni-measurements-metadata-v1-client = { version = ">=0.2.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
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
 
@@ -50,7 +50,7 @@ ipykernel = ">=6.0"
50
50
  plotly = ">=5.0"
51
51
  nbformat = ">=4.2.0"
52
52
  ipython = ">=7.0"
53
- jupyter = ">=1.0"
53
+ jupyter = ">=1.0"
54
54
 
55
55
  [tool.poetry.group.lint.dependencies]
56
56
  bandit = { version = ">=1.7", extras = ["toml"] }
@@ -92,7 +92,7 @@ skips = [
92
92
  extend_exclude = "docs,examples"
93
93
 
94
94
  [tool.black]
95
- extend-exclude = 'docs/|_pb2(_grpc)?\.(py|pyi)$'
95
+ extend-exclude = 'docs/|examples/|_pb2(_grpc)?\.(py|pyi)$'
96
96
  line-length = 100
97
97
 
98
98
  [tool.mypy]
@@ -101,7 +101,7 @@ files = "."
101
101
  namespace_packages = true
102
102
  strict = true
103
103
  explicit_package_bases = true
104
- exclude = ["docs"]
104
+ exclude = ["docs", "examples"]
105
105
 
106
106
  [tool.pyright]
107
107
  include = ["src/", "tests/"]
@@ -33,6 +33,8 @@ from ni.measurements.data.v1.client import DataStoreClient as DataStoreServiceCl
33
33
  from ni.measurements.data.v1.data_store_service_pb2 import (
34
34
  CreateStepRequest,
35
35
  CreateTestResultRequest,
36
+ GetConditionRequest,
37
+ GetMeasurementRequest,
36
38
  GetStepRequest,
37
39
  GetTestResultRequest,
38
40
  PublishConditionBatchRequest,
@@ -74,7 +76,10 @@ class DataStoreClient:
74
76
  "_moniker_clients_lock",
75
77
  )
76
78
 
77
- _DATA_STORE_CLIENT_CLOSED_ERROR = "This DataStoreClient has been closed. Create a new DataStoreClient for further interaction with the data store."
79
+ _DATA_STORE_CLIENT_CLOSED_ERROR = (
80
+ "This DataStoreClient has been closed. Create a new DataStoreClient for further "
81
+ "interaction with the data store."
82
+ )
78
83
 
79
84
  _closed: bool
80
85
  _discovery_client: DiscoveryClient | None
@@ -144,18 +149,18 @@ class DataStoreClient:
144
149
 
145
150
  def publish_condition(
146
151
  self,
147
- condition_name: str,
148
- type: str,
152
+ name: str,
153
+ condition_type: str,
149
154
  value: object,
150
155
  step_id: str,
151
- ) -> PublishedCondition:
156
+ ) -> str:
152
157
  """Publish a condition value to the data store.
153
158
 
154
159
  Args:
155
- condition_name: An identifier describing the condition value.
160
+ name: An identifier describing the condition value.
156
161
  For example, "Voltage" or "Temperature".
157
162
 
158
- type: The type of this condition. For example, "Upper Limit",
163
+ condition_type: The type of this condition. For example, "Upper Limit",
159
164
  "Environment", or "Setup".
160
165
 
161
166
  value: The single value for this condition to publish on the test
@@ -166,32 +171,28 @@ class DataStoreClient:
166
171
  value is expected to be a parsable GUID.
167
172
 
168
173
  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
174
+ str: The condition id - the unique ID of the condition for
175
+ referencing in queries
175
176
  """
176
177
  publish_request = PublishConditionRequest(
177
- condition_name=condition_name,
178
- type=type,
178
+ name=name,
179
+ condition_type=condition_type,
179
180
  step_id=step_id,
180
181
  )
181
182
  populate_publish_condition_request_value(publish_request, value)
182
183
  publish_response = self._get_data_store_client().publish_condition(publish_request)
183
- return PublishedCondition.from_protobuf(publish_response.published_condition)
184
+ return publish_response.condition_id
184
185
 
185
186
  def publish_condition_batch(
186
- self, condition_name: str, type: str, values: object, step_id: str
187
- ) -> PublishedCondition:
187
+ self, name: str, condition_type: str, values: object, step_id: str
188
+ ) -> str:
188
189
  """Publish a batch of N values for a condition to the data store.
189
190
 
190
191
  Args:
191
- condition_name: An identifier describing the condition values.
192
+ name: An identifier describing the condition values.
192
193
  For example, "Voltage" or "Temperature".
193
194
 
194
- type: The type of this condition. For example, "Upper Limit",
195
+ condition_type: The type of this condition. For example, "Upper Limit",
195
196
  "Environment", or "Setup".
196
197
 
197
198
  values: The values for this condition across all publishes on the
@@ -201,27 +202,21 @@ class DataStoreClient:
201
202
  values. This value is expected to be a parsable GUID.
202
203
 
203
204
  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
205
+ str: The condition id - the unique ID of the condition for
206
+ referencing in queries
212
207
  """
213
208
  publish_request = PublishConditionBatchRequest(
214
- condition_name=condition_name,
215
- type=type,
209
+ name=name,
210
+ condition_type=condition_type,
216
211
  step_id=step_id,
217
212
  )
218
213
  populate_publish_condition_batch_request_values(publish_request, values)
219
214
  publish_response = self._get_data_store_client().publish_condition_batch(publish_request)
220
- return PublishedCondition.from_protobuf(publish_response.published_condition)
215
+ return publish_response.condition_id
221
216
 
222
217
  def publish_measurement(
223
218
  self,
224
- measurement_name: str,
219
+ name: str,
225
220
  value: object, # More strongly typed Union[bool, AnalogWaveform] can be used if needed
226
221
  step_id: str,
227
222
  timestamp: ht.datetime | None = None,
@@ -231,11 +226,11 @@ class DataStoreClient:
231
226
  test_adapter_ids: Iterable[str] = tuple(),
232
227
  software_item_ids: Iterable[str] = tuple(),
233
228
  notes: str = "",
234
- ) -> PublishedMeasurement:
229
+ ) -> str:
235
230
  """Publish a single measurement value associated with a test step.
236
231
 
237
232
  Args:
238
- measurement_name: The name used for associating/grouping
233
+ name: The name used for associating/grouping
239
234
  conceptually alike measurements across multiple publish
240
235
  iterations. For example, "Temperature" can be used for
241
236
  associating temperature readings across multiple iterations.
@@ -279,15 +274,10 @@ class DataStoreClient:
279
274
  notes: Any notes to be associated with the captured measurement.
280
275
 
281
276
  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
277
+ str: The published measurement id.
288
278
  """
289
279
  publish_request = PublishMeasurementRequest(
290
- measurement_name=measurement_name,
280
+ name=name,
291
281
  step_id=step_id,
292
282
  outcome=outcome.to_protobuf(),
293
283
  error_information=(
@@ -303,11 +293,11 @@ class DataStoreClient:
303
293
  get_publish_measurement_timestamp(publish_request, timestamp)
304
294
  )
305
295
  publish_response = self._get_data_store_client().publish_measurement(publish_request)
306
- return PublishedMeasurement.from_protobuf(publish_response.published_measurement)
296
+ return publish_response.measurement_id
307
297
 
308
298
  def publish_measurement_batch(
309
299
  self,
310
- measurement_name: str,
300
+ name: str,
311
301
  values: object,
312
302
  step_id: str,
313
303
  timestamps: Iterable[ht.datetime] = tuple(),
@@ -317,11 +307,11 @@ class DataStoreClient:
317
307
  test_adapter_ids: Iterable[str] = tuple(),
318
308
  software_item_ids: Iterable[str] = tuple(),
319
309
  notes: str = "",
320
- ) -> Sequence[PublishedMeasurement]:
310
+ ) -> Sequence[str]:
321
311
  """Publish multiple scalar measurements at once for parametric sweeps.
322
312
 
323
313
  Args:
324
- measurement_name: The name used for associating/grouping
314
+ name: The name used for associating/grouping
325
315
  conceptually alike measurements across multiple publish
326
316
  iterations. For example, "Temperature" can be used for
327
317
  associating temperature readings across multiple iterations.
@@ -362,14 +352,13 @@ class DataStoreClient:
362
352
  notes: Any notes to be associated with the published measurements.
363
353
 
364
354
  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
355
+ Sequence[str]: The ids of the published measurement ids.
356
+ NOTE: Using a Sequence is for future flexibility.
357
+ This sequence will currently always have a single measurement id
369
358
  returned.
370
359
  """
371
360
  publish_request = PublishMeasurementBatchRequest(
372
- measurement_name=measurement_name,
361
+ name=name,
373
362
  step_id=step_id,
374
363
  timestamps=[hightime_datetime_to_protobuf(ts) for ts in timestamps],
375
364
  outcomes=[outcome.to_protobuf() for outcome in outcomes],
@@ -383,9 +372,7 @@ class DataStoreClient:
383
372
  )
384
373
  populate_publish_measurement_batch_request_values(publish_request, values)
385
374
  publish_response = self._get_data_store_client().publish_measurement_batch(publish_request)
386
- return [
387
- PublishedMeasurement.from_protobuf(pm) for pm in publish_response.published_measurements
388
- ]
375
+ return publish_response.measurement_ids
389
376
 
390
377
  @overload
391
378
  def read_data(
@@ -484,6 +471,32 @@ class DataStoreClient:
484
471
  get_response = self._get_data_store_client().get_step(get_request)
485
472
  return Step.from_protobuf(get_response.step)
486
473
 
474
+ def get_measurement(self, measurement_id: str) -> PublishedMeasurement:
475
+ """Get the measurement associated with the given identifier.
476
+
477
+ Args:
478
+ measurement_id: The identifier of the desired measurement.
479
+
480
+ Returns:
481
+ PublishedMeasurement: The metadata of the requested measurement.
482
+ """
483
+ get_request = GetMeasurementRequest(measurement_id=measurement_id)
484
+ get_response = self._get_data_store_client().get_measurement(get_request)
485
+ return PublishedMeasurement.from_protobuf(get_response.published_measurement)
486
+
487
+ def get_condition(self, condition_id: str) -> PublishedCondition:
488
+ """Get the condition associated with the given identifier.
489
+
490
+ Args:
491
+ condition_id: The identifier of the desired condition.
492
+
493
+ Returns:
494
+ PublishedCondition: The metadata of the requested condition.
495
+ """
496
+ get_request = GetConditionRequest(condition_id=condition_id)
497
+ get_response = self._get_data_store_client().get_condition(get_request)
498
+ return PublishedCondition.from_protobuf(get_response.published_condition)
499
+
487
500
  def create_test_result(self, test_result: TestResult) -> str:
488
501
  """Create a test result object for publishing measurements.
489
502
 
@@ -5,6 +5,7 @@ from ni.datastore.metadata._types._alias import Alias
5
5
  from ni.datastore.metadata._types._alias_target_type import AliasTargetType
6
6
  from ni.datastore.metadata._types._extension_schema import ExtensionSchema
7
7
  from ni.datastore.metadata._types._hardware_item import HardwareItem
8
+ from ni.datastore.metadata._types._metadata_items import MetadataItems
8
9
  from ni.datastore.metadata._types._operator import Operator
9
10
  from ni.datastore.metadata._types._software_item import SoftwareItem
10
11
  from ni.datastore.metadata._types._test import Test
@@ -19,6 +20,7 @@ __all__ = [
19
20
  "AliasTargetType",
20
21
  "ExtensionSchema",
21
22
  "HardwareItem",
23
+ "MetadataItems",
22
24
  "MetadataStoreClient",
23
25
  "Operator",
24
26
  "SoftwareItem",
@@ -35,6 +37,7 @@ Alias.__module__ = __name__
35
37
  AliasTargetType.__module__ = __name__
36
38
  ExtensionSchema.__module__ = __name__
37
39
  HardwareItem.__module__ = __name__
40
+ MetadataItems.__module__ = __name__
38
41
  MetadataStoreClient.__module__ = __name__
39
42
  Operator.__module__ = __name__
40
43
  SoftwareItem.__module__ = __name__
@@ -14,6 +14,7 @@ from grpc import Channel
14
14
  from ni.datastore.metadata._types._alias import Alias
15
15
  from ni.datastore.metadata._types._extension_schema import ExtensionSchema
16
16
  from ni.datastore.metadata._types._hardware_item import HardwareItem
17
+ from ni.datastore.metadata._types._metadata_items import MetadataItems
17
18
  from ni.datastore.metadata._types._operator import Operator
18
19
  from ni.datastore.metadata._types._software_item import SoftwareItem
19
20
  from ni.datastore.metadata._types._test import Test
@@ -28,6 +29,7 @@ from ni.measurements.metadata.v1.client import (
28
29
  )
29
30
  from ni.measurements.metadata.v1.metadata_store_service_pb2 import (
30
31
  CreateAliasRequest,
32
+ CreateFromJsonDocumentRequest,
31
33
  CreateHardwareItemRequest,
32
34
  CreateOperatorRequest,
33
35
  CreateSoftwareItemRequest,
@@ -84,7 +86,10 @@ class MetadataStoreClient:
84
86
  "_metadata_store_client_lock",
85
87
  )
86
88
 
87
- _METADATA_STORE_CLIENT_CLOSED_ERROR = "This MetadataStoreClient has been closed. Create a new MetadataStoreClient for further interaction with the metadata store."
89
+ _METADATA_STORE_CLIENT_CLOSED_ERROR = (
90
+ "This MetadataStoreClient has been closed. Create a new MetadataStoreClient for "
91
+ "further interaction with the metadata store."
92
+ )
88
93
 
89
94
  _closed: bool
90
95
  _discovery_client: DiscoveryClient | None
@@ -525,6 +530,34 @@ class MetadataStoreClient:
525
530
  list_response = self._get_metadata_store_client().list_schemas(list_request)
526
531
  return [ExtensionSchema.from_protobuf(schema) for schema in list_response.schemas]
527
532
 
533
+ def get_alias(self, alias_name: str) -> Alias:
534
+ """Get an alias and its target (the underlying metadata it represents).
535
+
536
+ Args:
537
+ alias_name: The name of the alias to retrieve.
538
+
539
+ Returns:
540
+ Alias: The alias containing the alias name, target type, and
541
+ target ID of the underlying metadata.
542
+ """
543
+ get_request = GetAliasRequest(alias_name=alias_name)
544
+ get_response = self._get_metadata_store_client().get_alias(get_request)
545
+ return Alias.from_protobuf(get_response.alias)
546
+
547
+ def query_aliases(self, odata_query: str = "") -> Sequence[Alias]:
548
+ """Perform an OData query on the registered aliases.
549
+
550
+ Args:
551
+ odata_query: An OData query string. Example: "$filter=name eq
552
+ 'Value'". $expand is not supported.
553
+
554
+ Returns:
555
+ Sequence[Alias]: The list of aliases that match the query.
556
+ """
557
+ query_request = QueryAliasesRequest(odata_query=odata_query)
558
+ query_response = self._get_metadata_store_client().query_aliases(query_request)
559
+ return [Alias.from_protobuf(alias) for alias in query_response.aliases]
560
+
528
561
  def create_alias(
529
562
  self,
530
563
  alias_name: str,
@@ -580,20 +613,6 @@ class MetadataStoreClient:
580
613
  response = self._get_metadata_store_client().create_alias(create_request)
581
614
  return Alias.from_protobuf(response.alias)
582
615
 
583
- def get_alias(self, alias_name: str) -> Alias:
584
- """Get an alias and its target (the underlying metadata it represents).
585
-
586
- Args:
587
- alias_name: The name of the alias to retrieve.
588
-
589
- Returns:
590
- Alias: The alias containing the alias name, target type, and
591
- target ID of the underlying metadata.
592
- """
593
- get_request = GetAliasRequest(alias_name=alias_name)
594
- get_response = self._get_metadata_store_client().get_alias(get_request)
595
- return Alias.from_protobuf(get_response.alias)
596
-
597
616
  def delete_alias(self, alias_name: str) -> bool:
598
617
  """Remove a registered alias.
599
618
 
@@ -608,19 +627,41 @@ class MetadataStoreClient:
608
627
  delete_response = self._get_metadata_store_client().delete_alias(delete_request)
609
628
  return delete_response.unregistered
610
629
 
611
- def query_aliases(self, odata_query: str = "") -> Sequence[Alias]:
612
- """Perform an OData query on the registered aliases.
630
+ def create_from_json_file(self, metadata_file_path: Path | str) -> MetadataItems:
631
+ """Create metadata items from a JSON file.
613
632
 
614
633
  Args:
615
- odata_query: An OData query string. Example: "$filter=name eq
616
- 'Value'". $expand is not supported.
634
+ metadata_file_path: The path to the JSON file containing metadata definitions.
617
635
 
618
636
  Returns:
619
- Sequence[Alias]: The list of aliases that match the query.
637
+ MetadataItems: A collection of metadata items created from the JSON document.
638
+
639
+ Raises:
640
+ FileNotFoundError: If the JSON file does not exist.
620
641
  """
621
- query_request = QueryAliasesRequest(odata_query=odata_query)
622
- query_response = self._get_metadata_store_client().query_aliases(query_request)
623
- return [Alias.from_protobuf(alias) for alias in query_response.aliases]
642
+ if isinstance(metadata_file_path, str):
643
+ metadata_file_path = Path(metadata_file_path)
644
+
645
+ if not metadata_file_path.exists():
646
+ raise FileNotFoundError(f"Metadata file not found: {metadata_file_path}")
647
+
648
+ metadata_contents = metadata_file_path.read_text(encoding="utf-8-sig")
649
+ return self.create_from_json(metadata_contents)
650
+
651
+ def create_from_json(self, metadata_file_contents: str) -> MetadataItems:
652
+ """Create metadata items from a JSON document.
653
+
654
+ Args:
655
+ metadata_file_contents: The JSON document content containing metadata definitions.
656
+
657
+ Returns:
658
+ MetadataItems: A collection of metadata items created from the JSON document.
659
+ """
660
+ create_request = CreateFromJsonDocumentRequest(json_document=metadata_file_contents)
661
+ create_response = self._get_metadata_store_client().create_from_json_document(
662
+ create_request
663
+ )
664
+ return MetadataItems.from_protobuf(create_response)
624
665
 
625
666
  def _get_metadata_store_client(self) -> MetadataStoreServiceClient:
626
667
  if self._closed:
@@ -0,0 +1,155 @@
1
+ """MetadataItems data type for the Data Store Client."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import Sequence
6
+
7
+ from ni.datastore.metadata._types._hardware_item import HardwareItem
8
+ from ni.datastore.metadata._types._operator import Operator
9
+ from ni.datastore.metadata._types._software_item import SoftwareItem
10
+ from ni.datastore.metadata._types._test import Test
11
+ from ni.datastore.metadata._types._test_adapter import TestAdapter
12
+ from ni.datastore.metadata._types._test_description import TestDescription
13
+ from ni.datastore.metadata._types._test_station import TestStation
14
+ from ni.datastore.metadata._types._uut import Uut
15
+ from ni.datastore.metadata._types._uut_instance import UutInstance
16
+ from ni.measurements.metadata.v1.metadata_store_service_pb2 import (
17
+ CreateFromJsonDocumentResponse,
18
+ )
19
+
20
+
21
+ class MetadataItems:
22
+ """Represents a collection of metadata items created from a JSON document.
23
+
24
+ This class contains the results of creating metadata items from a JSON document,
25
+ organizing them by type for easy access.
26
+ """
27
+
28
+ __slots__ = (
29
+ "uut_instances",
30
+ "uuts",
31
+ "operators",
32
+ "test_descriptions",
33
+ "tests",
34
+ "test_stations",
35
+ "hardware_items",
36
+ "software_items",
37
+ "test_adapters",
38
+ )
39
+
40
+ def __init__(
41
+ self,
42
+ *,
43
+ uut_instances: Sequence[UutInstance] = (),
44
+ uuts: Sequence[Uut] = (),
45
+ operators: Sequence[Operator] = (),
46
+ test_descriptions: Sequence[TestDescription] = (),
47
+ tests: Sequence[Test] = (),
48
+ test_stations: Sequence[TestStation] = (),
49
+ hardware_items: Sequence[HardwareItem] = (),
50
+ software_items: Sequence[SoftwareItem] = (),
51
+ test_adapters: Sequence[TestAdapter] = (),
52
+ ) -> None:
53
+ """Initialize a MetadataItems instance.
54
+
55
+ Args:
56
+ uut_instances: A sequence of UUT instances created from the JSON document.
57
+ uuts: A sequence of UUTs created from the JSON document.
58
+ operators: A sequence of operators created from the JSON document.
59
+ test_descriptions: A sequence of test descriptions created from the JSON document.
60
+ tests: A sequence of tests created from the JSON document.
61
+ test_stations: A sequence of test stations created from the JSON document.
62
+ hardware_items: A sequence of hardware items created from the JSON document.
63
+ software_items: A sequence of software items created from the JSON document.
64
+ test_adapters: A sequence of test adapters created from the JSON document.
65
+ """
66
+ self.uut_instances = uut_instances
67
+ self.uuts = uuts
68
+ self.operators = operators
69
+ self.test_descriptions = test_descriptions
70
+ self.tests = tests
71
+ self.test_stations = test_stations
72
+ self.hardware_items = hardware_items
73
+ self.software_items = software_items
74
+ self.test_adapters = test_adapters
75
+
76
+ @staticmethod
77
+ def from_protobuf(response: CreateFromJsonDocumentResponse) -> "MetadataItems":
78
+ """Create a MetadataItems instance from a protobuf CreateFromJsonDocumentResponse.
79
+
80
+ Args:
81
+ response: The protobuf response containing the created metadata items.
82
+
83
+ Returns:
84
+ MetadataItems: A new MetadataItems instance with all the created items.
85
+ """
86
+ return MetadataItems(
87
+ uut_instances=[
88
+ UutInstance.from_protobuf(uut_instance) for uut_instance in response.uut_instances
89
+ ],
90
+ uuts=[Uut.from_protobuf(uut) for uut in response.uuts],
91
+ operators=[Operator.from_protobuf(operator) for operator in response.operators],
92
+ test_descriptions=[
93
+ TestDescription.from_protobuf(test_description)
94
+ for test_description in response.test_descriptions
95
+ ],
96
+ tests=[Test.from_protobuf(test) for test in response.tests],
97
+ test_stations=[
98
+ TestStation.from_protobuf(test_station) for test_station in response.test_stations
99
+ ],
100
+ hardware_items=[
101
+ HardwareItem.from_protobuf(hardware_item)
102
+ for hardware_item in response.hardware_items
103
+ ],
104
+ software_items=[
105
+ SoftwareItem.from_protobuf(software_item)
106
+ for software_item in response.software_items
107
+ ],
108
+ test_adapters=[
109
+ TestAdapter.from_protobuf(test_adapter) for test_adapter in response.test_adapters
110
+ ],
111
+ )
112
+
113
+ def __eq__(self, other: object) -> bool:
114
+ """Determine equality between MetadataItems instances."""
115
+ if not isinstance(other, MetadataItems):
116
+ return False
117
+
118
+ return (
119
+ list(self.uut_instances) == list(other.uut_instances)
120
+ and list(self.uuts) == list(other.uuts)
121
+ and list(self.operators) == list(other.operators)
122
+ and list(self.test_descriptions) == list(other.test_descriptions)
123
+ and list(self.tests) == list(other.tests)
124
+ and list(self.test_stations) == list(other.test_stations)
125
+ and list(self.hardware_items) == list(other.hardware_items)
126
+ and list(self.software_items) == list(other.software_items)
127
+ and list(self.test_adapters) == list(other.test_adapters)
128
+ )
129
+
130
+ def __str__(self) -> str:
131
+ """Return a string representation of the MetadataItems."""
132
+ counts = []
133
+ if self.uut_instances:
134
+ counts.append(f"{len(self.uut_instances)} UUT instances")
135
+ if self.uuts:
136
+ counts.append(f"{len(self.uuts)} UUTs")
137
+ if self.operators:
138
+ counts.append(f"{len(self.operators)} operators")
139
+ if self.test_descriptions:
140
+ counts.append(f"{len(self.test_descriptions)} test descriptions")
141
+ if self.tests:
142
+ counts.append(f"{len(self.tests)} tests")
143
+ if self.test_stations:
144
+ counts.append(f"{len(self.test_stations)} test stations")
145
+ if self.hardware_items:
146
+ counts.append(f"{len(self.hardware_items)} hardware items")
147
+ if self.software_items:
148
+ counts.append(f"{len(self.software_items)} software items")
149
+ if self.test_adapters:
150
+ counts.append(f"{len(self.test_adapters)} test adapters")
151
+
152
+ if counts:
153
+ return f"MetadataItems({', '.join(counts)})"
154
+ else:
155
+ return "MetadataItems(empty)"