-
Notifications
You must be signed in to change notification settings - Fork 0
First pass of minimal Python API #8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
eb181c5
First pass at minimal Python API for publish / read
dixonjoel 1900805
Merge remote-tracking branch 'origin/main' into users/jdixon/python-a…
dixonjoel f17963d
Add publish_and_read example as a first pass at using the data store
dixonjoel 952b11c
Make publish_and_read of a boolean scalar work
dixonjoel 51c10da
Add commented out unit test for publish and read of booleans
dixonjoel 10671e0
Fix linter errors
dixonjoel 43a93d0
Suppress sphinx import warnings
dixonjoel 80aef23
Suppress sphinx import warnings
dixonjoel 47272b2
Add a boolean test
dixonjoel 4f9af73
Fix unit tests - Python 3.9 doesn't like DataStoreClient | None as a …
dixonjoel c8c73f1
Change read signature to use a TypeVar.
dixonjoel 96b149c
Add test to read a boolean
dixonjoel 50dc25c
Fix linter errors
dixonjoel c8304d5
Fix test name
dixonjoel 66bc48b
Check type at runtime with isinstance instead of cast
dixonjoel b8e01ae
Remove unneeded mock setup.
dixonjoel File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,6 @@ | ||
| #VS Code | ||
| .vscode/ | ||
|
|
||
| # Byte-compiled / optimized / DLL files | ||
| __pycache__/ | ||
|
|
||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1,5 @@ | ||
| """Public API for accessing the NI Data Store Service.""" | ||
|
|
||
| from ni.datastore.client import Client | ||
|
|
||
| __all__ = ["Client"] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,126 @@ | ||
| """Datastore client for publishing and reading data.""" | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| from collections.abc import Iterable | ||
| from typing import Type, TypeVar, cast | ||
|
|
||
| import numpy as np | ||
| from ni.datamonikers.v1.client import MonikerClient | ||
| from ni.datamonikers.v1.data_moniker_pb2 import Moniker | ||
| from ni.measurements.data.v1.client import DataStoreClient | ||
| from ni.measurements.data.v1.data_store_pb2 import ( | ||
| ErrorInformation, | ||
| Outcome, | ||
| PublishedMeasurement, | ||
| ) | ||
| from ni.measurements.data.v1.data_store_service_pb2 import PublishMeasurementRequest | ||
| from ni.measurements.metadata.v1.client import MetadataStoreClient | ||
| from ni.protobuf.types.precision_timestamp_conversion import ( | ||
| bintime_datetime_to_protobuf, | ||
| ) | ||
| from ni.protobuf.types.waveform_conversion import float64_analog_waveform_to_protobuf | ||
| from nitypes.bintime import DateTime | ||
dixonjoel marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| from nitypes.waveform import AnalogWaveform | ||
|
|
||
| TRead = TypeVar("TRead") | ||
| TWrite = TypeVar("TWrite") | ||
|
|
||
|
|
||
| class Client: | ||
| """Datastore client for publishing and reading data.""" | ||
|
|
||
| __slots__ = ("_data_store_client", "_metadata_store_client", "_moniker_client") | ||
|
|
||
| _data_store_client: DataStoreClient | ||
| _metadata_store_client: MetadataStoreClient | ||
| _moniker_client: MonikerClient | ||
|
|
||
| def __init__( | ||
| self, | ||
| data_store_client: DataStoreClient | None = None, | ||
| metadata_store_client: MetadataStoreClient | None = None, | ||
| moniker_client: MonikerClient | None = None, | ||
| ) -> None: | ||
| """Initialize the Client.""" | ||
| self._data_store_client = data_store_client or DataStoreClient() | ||
| self._metadata_store_client = metadata_store_client or MetadataStoreClient() | ||
| self._moniker_client = moniker_client or MonikerClient(service_location="dummy") | ||
|
|
||
| def publish_measurement_data( | ||
| self, | ||
| step_id: str, | ||
| name: str, | ||
| notes: str, | ||
| timestamp: DateTime, | ||
dixonjoel marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| data: object, # More strongly typed Union[bool, AnalogWaveform] can be used if needed | ||
dixonjoel marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| outcome: Outcome.ValueType, | ||
| error_info: ErrorInformation, | ||
| hardware_item_ids: Iterable[str] = tuple(), | ||
| software_item_ids: Iterable[str] = tuple(), | ||
| test_adapter_ids: Iterable[str] = tuple(), | ||
| ) -> PublishedMeasurement: | ||
| """Publish measurement data to the datastore.""" | ||
| publish_request = PublishMeasurementRequest( | ||
| step_id=step_id, | ||
| measurement_name=name, | ||
| notes=notes, | ||
| timestamp=bintime_datetime_to_protobuf(timestamp), | ||
| outcome=outcome, | ||
| error_information=error_info, | ||
| hardware_item_ids=hardware_item_ids, | ||
| software_item_ids=software_item_ids, | ||
| test_adapter_ids=test_adapter_ids, | ||
| ) | ||
|
|
||
| if isinstance(data, bool): | ||
dixonjoel marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| publish_request.scalar.bool_value = data | ||
| elif isinstance(data, AnalogWaveform): | ||
| # Assuming data is of type AnalogWaveform | ||
| analog_waveform = cast(AnalogWaveform[np.float64], data) | ||
| publish_request.double_analog_waveform.CopyFrom( | ||
| float64_analog_waveform_to_protobuf(analog_waveform) | ||
| ) | ||
|
|
||
| publish_response = self._data_store_client.publish_measurement(publish_request) | ||
| return publish_response.published_measurement | ||
|
|
||
| def read_measurement_data( | ||
| self, moniker_source: Moniker | PublishedMeasurement, expected_type: Type[TRead] | ||
| ) -> TRead: | ||
| """Read measurement data from the datastore.""" | ||
| if isinstance(moniker_source, Moniker): | ||
| moniker = moniker_source | ||
| else: | ||
| moniker = moniker_source.moniker | ||
| self._moniker_client._service_location = moniker.service_location | ||
| result = self._moniker_client.read_from_moniker(moniker) | ||
| if not isinstance(result.value, expected_type): | ||
| raise TypeError(f"Expected type {expected_type}, got {type(result.value)}") | ||
| return result.value | ||
|
|
||
| def create_step( | ||
| self, | ||
| step_name: str, | ||
| step_type: str, | ||
| notes: str, | ||
| start_time: DateTime, | ||
| end_time: DateTime, | ||
| test_result_id: str = "", | ||
| ) -> str: | ||
| """Create a test step in the datastore.""" | ||
| return "step_id" | ||
|
|
||
| def create_test_result( | ||
| self, | ||
| test_name: str, | ||
| uut_instance_id: str = "", | ||
| operator_id: str = "", | ||
| test_station_id: str = "", | ||
| test_description_id: str = "", | ||
| software_item_ids: list[str] = [], | ||
| hardware_item_ids: list[str] = [], | ||
| test_adapter_ids: list[str] = [], | ||
| ) -> str: | ||
| """Create a test result in the datastore.""" | ||
dixonjoel marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| return "test_result_id" | ||
dixonjoel marked this conversation as resolved.
Show resolved
Hide resolved
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Tests should use triple underscore as a separator. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.