Skip to content

Commit

Permalink
Merge branch 'main' into users/tynguyen/metadata_validation
Browse files Browse the repository at this point in the history
  • Loading branch information
LazeringDeath committed Jul 24, 2024
2 parents c73bb40 + aa99a84 commit 439c285
Show file tree
Hide file tree
Showing 21 changed files with 844 additions and 1,033 deletions.
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,18 @@
- [Introduction](#introduction)
- [Dependencies](#dependencies)
- [Documentation](#documentation)
- [System Configuration](#system-configuration)
- [Enable Win32 Long Paths](#enable-win32-long-paths)
- [Examples](#examples)
- [Developing Measurements: Quick Start](#developing-measurements-quick-start)
- [Installation](#installation)
- [Developing a minimal python measurement](#developing-a-minimal-python-measurement)
- [Developing a minimal Python measurement](#developing-a-minimal-python-measurement)
- [Steps to run/debug the measurement service](#steps-to-rundebug-the-measurement-service)
- [Static Registration of Python Measurements](#static-registration-of-python-measurements)
- [Create a batch file that runs a python measurement](#create-a-batch-file-that-runs-a-python-measurement)
- [Create a batch file that runs a Python measurement](#create-a-batch-file-that-runs-a-python-measurement)
- [Create Executable for Python Scripts](#create-executable-for-python-scripts)
- [Troubleshooting](#troubleshooting)
- ["File not found" or "No such file or directory" errors when copying or running a measurement service](#file-not-found-or-no-such-file-or-directory-errors-when-copying-or-running-a-measurement-service)
- [Appendix: Managing Measurement with Python](#appendix-managing-measurement-with-python)
- [Create and Manage Python Measurement using Poetry](#create-and-manage-python-measurement-using-poetry)
- [Create and Manage Python Measurement using `venv`](#create-and-manage-python-measurement-using-venv)
Expand Down
2 changes: 1 addition & 1 deletion examples/nivisa_dmm_measurement/_visa_grpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,6 @@ def get_visa_grpc_insecure_address(config: AutoConfig, discovery_client: Discove
return urlsplit(grpc_device_server_address).netloc
else:
service_location = discovery_client.resolve_service(
"visa_grpc.Visa", "ni.measurementlink.v1.grpcdeviceserver"
GRPC_SERVICE_INTERFACE_NAME, SERVICE_CLASS
)
return service_location.insecure_address
2 changes: 1 addition & 1 deletion examples/output_voltage_measurement/_visa_grpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,6 @@ def get_visa_grpc_insecure_address(config: AutoConfig, discovery_client: Discove
return urlsplit(grpc_device_server_address).netloc
else:
service_location = discovery_client.resolve_service(
"visa_grpc.Visa", "ni.measurementlink.v1.grpcdeviceserver"
GRPC_SERVICE_INTERFACE_NAME, SERVICE_CLASS
)
return service_location.insecure_address
58 changes: 29 additions & 29 deletions packages/generator/poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@
import grpc
from google.protobuf import any_pb2

from ni_measurement_plugin_sdk_service._internal.parameter import serializer
from ni_measurement_plugin_sdk_service._internal.parameter.metadata import ParameterMetadata
from ni_measurement_plugin_sdk_service._internal.parameter import decoder, encoder
from ni_measurement_plugin_sdk_service._internal.parameter.metadata import (
ParameterMetadata,
)
from ni_measurement_plugin_sdk_service._internal.stubs.ni.measurementlink.measurement.v1 import (
measurement_service_pb2 as v1_measurement_service_pb2,
measurement_service_pb2_grpc as v1_measurement_service_pb2_grpc,
Expand All @@ -23,7 +25,10 @@
measurement_service_pb2 as v2_measurement_service_pb2,
measurement_service_pb2_grpc as v2_measurement_service_pb2_grpc,
)
from ni_measurement_plugin_sdk_service.measurement.info import MeasurementInfo
from ni_measurement_plugin_sdk_service.measurement.info import (
MeasurementInfo,
ServiceInfo,
)
from ni_measurement_plugin_sdk_service.session_management import PinMapContext


Expand Down Expand Up @@ -131,9 +136,13 @@ def _get_mapping_by_parameter_name(
return mapping_by_variable_name


def _serialize_outputs(output_metadata: Dict[int, ParameterMetadata], outputs: Any) -> any_pb2.Any:
def _serialize_outputs(
output_metadata: Dict[int, ParameterMetadata], outputs: Any, service_name: str
) -> any_pb2.Any:
if isinstance(outputs, collections.abc.Sequence):
return any_pb2.Any(value=serializer.serialize_parameters(output_metadata, outputs))
return any_pb2.Any(
value=encoder.serialize_parameters(output_metadata, outputs, service_name)
)
elif outputs is None:
raise ValueError(f"Measurement function returned None")
else:
Expand Down Expand Up @@ -161,6 +170,7 @@ def __init__(
output_parameter_list: List[ParameterMetadata],
measure_function: Callable,
owner: object,
service_info: ServiceInfo,
) -> None:
"""Initialize the measurement v1 servicer."""
super().__init__()
Expand All @@ -169,6 +179,7 @@ def __init__(
self._measurement_info = measurement_info
self._measure_function = measure_function
self._owner = weakref.ref(owner) if owner is not None else None # avoid reference cycle
self._service_info = service_info

def GetMetadata( # noqa: N802 - function name should be lowercase
self, request: v1_measurement_service_pb2.GetMetadataRequest, context: grpc.ServicerContext
Expand All @@ -193,8 +204,8 @@ def GetMetadata( # noqa: N802 - function name should be lowercase
)
measurement_signature.configuration_parameters.append(configuration_parameter)

measurement_signature.configuration_defaults.value = serializer.serialize_default_values(
self._configuration_metadata
measurement_signature.configuration_defaults.value = encoder.serialize_default_values(
self._configuration_metadata, self._service_info.service_class + ".Configurations"
)

for field_number, output_metadata in self._output_metadata.items():
Expand Down Expand Up @@ -224,8 +235,10 @@ def Measure( # noqa: N802 - function name should be lowercase
self, request: v1_measurement_service_pb2.MeasureRequest, context: grpc.ServicerContext
) -> v1_measurement_service_pb2.MeasureResponse:
"""RPC API that executes the registered measurement method."""
mapping_by_id = serializer.deserialize_parameters(
self._configuration_metadata, request.configuration_parameters.value
mapping_by_id = decoder.deserialize_parameters(
self._configuration_metadata,
request.configuration_parameters.value,
self._service_info.service_class + ".Configurations",
)
mapping_by_variable_name = _get_mapping_by_parameter_name(
mapping_by_id, self._measure_function
Expand All @@ -252,9 +265,14 @@ def Measure( # noqa: N802 - function name should be lowercase
measurement_service_context.get().mark_complete()
measurement_service_context.reset(token)

def _serialize_response(self, outputs: Any) -> v1_measurement_service_pb2.MeasureResponse:
def _serialize_response(
self,
outputs: Any,
) -> v1_measurement_service_pb2.MeasureResponse:
return v1_measurement_service_pb2.MeasureResponse(
outputs=_serialize_outputs(self._output_metadata, outputs)
outputs=_serialize_outputs(
self._output_metadata, outputs, self._service_info.service_class + ".Outputs"
)
)


Expand All @@ -268,6 +286,7 @@ def __init__(
output_parameter_list: List[ParameterMetadata],
measure_function: Callable,
owner: object,
service_info: ServiceInfo,
) -> None:
"""Initialize the measurement v2 servicer."""
super().__init__()
Expand All @@ -276,6 +295,7 @@ def __init__(
self._measurement_info = measurement_info
self._measure_function = measure_function
self._owner = weakref.ref(owner) if owner is not None else None # avoid reference cycle
self._service_info = service_info

def GetMetadata( # noqa: N802 - function name should be lowercase
self, request: v2_measurement_service_pb2.GetMetadataRequest, context: grpc.ServicerContext
Expand All @@ -301,8 +321,8 @@ def GetMetadata( # noqa: N802 - function name should be lowercase
)
measurement_signature.configuration_parameters.append(configuration_parameter)

measurement_signature.configuration_defaults.value = serializer.serialize_default_values(
self._configuration_metadata
measurement_signature.configuration_defaults.value = encoder.serialize_default_values(
self._configuration_metadata, self._service_info.service_class + ".Configurations"
)

for field_number, output_metadata in self._output_metadata.items():
Expand Down Expand Up @@ -334,8 +354,10 @@ def Measure( # noqa: N802 - function name should be lowercase
self, request: v2_measurement_service_pb2.MeasureRequest, context: grpc.ServicerContext
) -> Generator[v2_measurement_service_pb2.MeasureResponse, None, None]:
"""RPC API that executes the registered measurement method."""
mapping_by_id = serializer.deserialize_parameters(
self._configuration_metadata, request.configuration_parameters.value
mapping_by_id = decoder.deserialize_parameters(
self._configuration_metadata,
request.configuration_parameters.value,
self._service_info.service_class + ".Configurations",
)
mapping_by_variable_name = _get_mapping_by_parameter_name(
mapping_by_id, self._measure_function
Expand Down Expand Up @@ -363,5 +385,7 @@ def Measure( # noqa: N802 - function name should be lowercase

def _serialize_response(self, outputs: Any) -> v2_measurement_service_pb2.MeasureResponse:
return v2_measurement_service_pb2.MeasureResponse(
outputs=_serialize_outputs(self._output_metadata, outputs)
outputs=_serialize_outputs(
self._output_metadata, outputs, self._service_info.service_class + ".Outputs"
)
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
from typing import Any

from google.protobuf.descriptor_pb2 import FieldDescriptorProto
from google.protobuf.type_pb2 import Field

_TYPE_DEFAULT_MAPPING = {
Field.TYPE_FLOAT: float(),
Field.TYPE_DOUBLE: float(),
Field.TYPE_INT32: int(),
Field.TYPE_INT64: int(),
Field.TYPE_UINT32: int(),
Field.TYPE_UINT64: int(),
Field.TYPE_BOOL: bool(),
Field.TYPE_STRING: str(),
Field.TYPE_ENUM: int(),
}

TYPE_FIELD_MAPPING = {
Field.TYPE_FLOAT: FieldDescriptorProto.TYPE_FLOAT,
Field.TYPE_DOUBLE: FieldDescriptorProto.TYPE_DOUBLE,
Field.TYPE_INT32: FieldDescriptorProto.TYPE_INT32,
Field.TYPE_INT64: FieldDescriptorProto.TYPE_INT64,
Field.TYPE_UINT32: FieldDescriptorProto.TYPE_UINT32,
Field.TYPE_UINT64: FieldDescriptorProto.TYPE_UINT64,
Field.TYPE_BOOL: FieldDescriptorProto.TYPE_BOOL,
Field.TYPE_STRING: FieldDescriptorProto.TYPE_STRING,
Field.TYPE_ENUM: FieldDescriptorProto.TYPE_ENUM,
Field.TYPE_MESSAGE: FieldDescriptorProto.TYPE_MESSAGE,
}


def get_type_default(type: Field.Kind.ValueType, repeated: bool) -> Any:
"""Get the default value for the give type."""
if repeated:
return list()
return _TYPE_DEFAULT_MAPPING.get(type)
Loading

0 comments on commit 439c285

Please sign in to comment.