Skip to content
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

Code quality improvements to the Measurement Plug-In Client generator #901

Merged
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
a2dc76c
fix: add improvements
Jotheeswaran-Nandagopal Sep 19, 2024
f75401b
fix: update pyproject.toml
Jotheeswaran-Nandagopal Sep 19, 2024
1ca6efe
Merge branch 'main' into users/jothees/client-generator-improvements
MounikaBattu17 Sep 19, 2024
b02ab87
Merge branch 'main' into users/jothees/client-generator-improvements
Jotheeswaran-Nandagopal Sep 19, 2024
3c917ec
fix: resolve comments
Jotheeswaran-Nandagopal Sep 19, 2024
d22789b
fix: update stubs
Jotheeswaran-Nandagopal Sep 20, 2024
826b662
doc: update comment string
Jotheeswaran-Nandagopal Sep 20, 2024
535d42a
refactor: string concatination
Jotheeswaran-Nandagopal Sep 20, 2024
06a4445
Merge branch 'main' into users/jothees/client-generator-improvements
Jotheeswaran-Nandagopal Sep 20, 2024
d74944f
fix: resolve merge conflict
Jotheeswaran-Nandagopal Sep 20, 2024
7f7de09
fix: update doc strings
Jotheeswaran-Nandagopal Sep 20, 2024
63deba0
remove: namespace in proto
Jotheeswaran-Nandagopal Sep 20, 2024
ed30b02
fix: move enum type conversion to mako
Jotheeswaran-Nandagopal Sep 20, 2024
b029d60
fix: automate stubs generation in generator tests
Jotheeswaran-Nandagopal Sep 20, 2024
2172c90
fix: update pyproject
Jotheeswaran-Nandagopal Sep 20, 2024
2fe7c72
fix: update stubs
Jotheeswaran-Nandagopal Sep 20, 2024
2b3a8ea
fix: update mypy override
Jotheeswaran-Nandagopal Sep 20, 2024
a811110
fix: update proto
Jotheeswaran-Nandagopal Sep 20, 2024
4dd2b62
fix: update exception message
Jotheeswaran-Nandagopal Sep 20, 2024
926f723
fix: update mako
Jotheeswaran-Nandagopal Sep 20, 2024
7247618
update: formatting
Jotheeswaran-Nandagopal Sep 20, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ The generated client includes four APIs: `measure`, `stream_measure`, `register_

1. Make sure the required measurement service is running before interacting with it via the client.

2. Use the client APIs from the ["Developing a Minimal Python MeasurementClient"](#developing-a-minimal-python-measurement-client) section.
2. Use the client APIs from the ["Generating a Minimal Python Measurement Client"](#generating-a-minimal-python-measurement-client) section.

1. For non-streaming measurements, use the `measure` method.

Expand Down
2 changes: 1 addition & 1 deletion packages/generator/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ The generated client includes four APIs: `measure`, `stream_measure`, `register_

1. Make sure the required measurement service is running before interacting with it via the client.

2. Use the client APIs from the ["Developing a Minimal Python MeasurementClient"](#developing-a-minimal-python-measurement-client) section.
2. Use the client APIs from the ["Generating a Minimal Python Measurement Client"](#generating-a-minimal-python-measurement-client) section.

1. For non-streaming measurements, use the `measure` method.

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
"""Utilizes command line args to create a Measurement Plug-In Client using template files."""

import pathlib
import re
from enum import Enum
from typing import Any, Dict, List, Optional, Type

Expand All @@ -27,6 +26,7 @@
get_all_registered_measurement_info,
get_selected_measurement_service_class,
to_ordered_set,
replace_enum_class_type,
resolve_output_directory,
validate_identifier,
validate_measurement_service_classes,
Expand All @@ -39,18 +39,13 @@ def _render_template(template_name: str, **template_args: Any) -> bytes:
return template.render(**template_args)


def _replace_enum_class_type(output: str) -> str:
pattern = "<enum '([^']+)'>"
return re.sub(pattern, r"\1", output)


def _create_file(
template_name: str, file_name: str, directory_out: pathlib.Path, **template_args: Any
) -> None:
output_file = directory_out / file_name

output = _render_template(template_name, **template_args).decode("utf-8")
output = _replace_enum_class_type(output)
output = replace_enum_class_type(output)
formatted_output = black.format_str(
src_contents=output,
mode=black.Mode(line_length=100),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import json
import keyword
import os
import pathlib
import re
import sys
Expand Down Expand Up @@ -154,7 +153,7 @@ def get_configuration_metadata_by_index(
deserialized_parameters = deserialize_parameters(
configuration_metadata,
metadata.measurement_signature.configuration_defaults.value,
service_class + ".Configurations",
f"{service_class}.Configurations",
)

for k, v in deserialized_parameters.items():
Expand Down Expand Up @@ -248,10 +247,8 @@ def get_configuration_parameters_with_type_and_default_values(

configuration_parameters.append(f"{parameter_name}: {parameter_type} = {default_value}")

# Use line separator and spaces to align the parameters appropriately in the generated file.
configuration_parameters_with_type_and_value = f",{os.linesep} ".join(
configuration_parameters
)
# Join the list of configuration parameters into a comma-separated string.
configuration_parameters_with_type_and_value = f", ".join(configuration_parameters)
parameter_names_as_str = ", ".join(parameter_names)

return (configuration_parameters_with_type_and_value, parameter_names_as_str)
Expand All @@ -262,7 +259,7 @@ def get_output_parameters_with_type(
built_in_import_modules: List[str],
custom_import_modules: List[str],
enum_values_by_type: Dict[Type[Enum], Dict[str, int]] = {},
) -> str:
) -> List[str]:
"""Returns the output parameters of the measurement with type."""
output_parameters_with_type = []
for metadata in output_metadata.values():
Expand All @@ -289,7 +286,7 @@ def get_output_parameters_with_type(

output_parameters_with_type.append(f"{parameter_name}: {parameter_type}")

return f"{os.linesep} ".join(output_parameters_with_type)
return output_parameters_with_type


def to_ordered_set(values: Iterable[_T]) -> AbstractSet[_T]:
Expand Down Expand Up @@ -361,6 +358,12 @@ def validate_measurement_service_classes(measurement_service_classes: List[str])
raise click.ClickException("No registered measurements.")


def replace_enum_class_type(input_string: str) -> str:
"""Replace enum class type representation with just the enum name."""
pattern = "<enum '([^']+)'>"
return re.sub(pattern, r"\1", input_string)


def _get_python_identifier(input_string: str) -> str:
valid_identifier = input_string.lower()
if not valid_identifier.isidentifier():
Expand Down Expand Up @@ -438,4 +441,4 @@ def _get_enum_class_name(name: str) -> str:
name = "".join(s.capitalize() for s in split_string)
else:
name = name[0].upper() + name[1:]
return name + "Enum"
return f"{name}Enum"
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,9 @@ class ${enum_name.__name__}(Enum):
class Outputs(NamedTuple):
"""Outputs for the ${display_name | repr} measurement plug-in."""

${output_parameters_with_type}
% for output_parameter in output_parameters_with_type:
${output_parameter}
% endfor
<% output_type = "Outputs" %>\
% endif

Expand Down Expand Up @@ -102,7 +104,7 @@ class ${class_name}:

@property
def pin_map_context(self) -> PinMapContext:
"""Get the pin map context for the measurement."""
"""The pin map context for the measurement."""
return self._pin_map_context

@pin_map_context.setter
Expand Down
6 changes: 5 additions & 1 deletion packages/generator/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,12 @@ requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"

[tool.black]
extend_exclude = '\.tox/|_pb2(_grpc)?\.(py|pyi)$'
line-length = 100

[tool.ni-python-styleguide]
extend_exclude = '.tox/,*_pb2_grpc.py,*_pb2_grpc.pyi,*_pb2.py,*_pb2.pyi'

[tool.mypy]
files = "ni_measurement_plugin_sdk_generator/,tests/"
exclude = "^tests/test_assets/"
Expand All @@ -74,4 +78,4 @@ testpaths = ["tests"]
skips = [
"B101", # assert_used
"B702", # use_of_mako_templates
]
]
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,15 @@ class EnumInEnum(Enum):
BLUE = 3


class ProtobufEnumInEnum(Enum):
"""ProtobufEnumInEnum used for enum-typed measurement configs and outputs."""

NONE = 0
PINK = 1
WHITE = 2
BLACK = 3


def test___measurement_plugin_client___measure___returns_output(
measurement_plugin_client_module: ModuleType,
) -> None:
Expand Down Expand Up @@ -54,6 +63,7 @@ def test___measurement_plugin_client___measure___returns_output(
xy_data_out=None,
enum_out=EnumInEnum.BLUE,
enum_array_out=[EnumInEnum.RED, EnumInEnum.GREEN],
protobuf_enum_out=ProtobufEnumInEnum.BLACK,
)
measurement_plugin_client = test_measurement_client_type()

Expand Down Expand Up @@ -97,6 +107,7 @@ def test___measurement_plugin_client___stream_measure___returns_output(
xy_data_out=None,
enum_out=EnumInEnum.BLUE,
enum_array_out=[EnumInEnum.RED, EnumInEnum.GREEN],
protobuf_enum_out=ProtobufEnumInEnum.BLACK,
)
measurement_plugin_client = test_measurement_client_type()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,15 @@ class EnumInEnum(Enum):
BLUE = 3


class ProtobufEnumInEnum(Enum):
"""ProtobufEnumInEnum used for enum-typed measurement configs and outputs."""

NONE = 0
PINK = 1
WHITE = 2
BLACK = 3


class Outputs(NamedTuple):
"""Outputs for the 'Non-Streaming Data Measurement (Py)' measurement plug-in."""

Expand All @@ -56,6 +65,7 @@ class Outputs(NamedTuple):
xy_data_out: DoubleXYData
enum_out: EnumInEnum
enum_array_out: List[EnumInEnum]
protobuf_enum_out: ProtobufEnumInEnum


class NonStreamingDataMeasurementClient:
Expand Down Expand Up @@ -236,6 +246,19 @@ def __init__(
field_name="Enum_Array_In",
enum_type=EnumInEnum,
),
13: ParameterMetadata(
display_name="Protobuf Enum In",
type=14,
repeated=False,
default_value=3,
annotations={
"ni/enum.values": '{"NONE": 0, "PINK": 1, "WHITE": 2, "BLACK": 3}',
"ni/type_specialization": "enum",
},
message_type="",
field_name="Protobuf_Enum_In",
enum_type=ProtobufEnumInEnum,
),
}
self._output_metadata = {
1: ParameterMetadata(
Expand Down Expand Up @@ -380,6 +403,19 @@ def __init__(
field_name="Enum_Array_Out",
enum_type=EnumInEnum,
),
14: ParameterMetadata(
display_name="Protobuf Enum out",
type=14,
repeated=False,
default_value=None,
annotations={
"ni/enum.values": '{"NONE": 0, "PINK": 1, "WHITE": 2, "BLACK": 3}',
"ni/type_specialization": "enum",
},
message_type="",
field_name="Protobuf_Enum_out",
enum_type=ProtobufEnumInEnum,
),
}
if grpc_channel is not None:
self._stub = v2_measurement_service_pb2_grpc.MeasurementServiceStub(grpc_channel)
Expand All @@ -388,7 +424,7 @@ def __init__(

@property
def pin_map_context(self) -> PinMapContext:
"""Get the pin map context for the measurement."""
"""The pin map context for the measurement."""
return self._pin_map_context

@pin_map_context.setter
Expand Down Expand Up @@ -520,6 +556,7 @@ def measure(
integer_in: int = 10,
enum_in: EnumInEnum = EnumInEnum.BLUE,
enum_array_in: List[EnumInEnum] = [EnumInEnum.RED, EnumInEnum.GREEN],
protobuf_enum_in: ProtobufEnumInEnum = ProtobufEnumInEnum.BLACK,
) -> Outputs:
"""Perform a single measurement.

Expand All @@ -539,6 +576,7 @@ def measure(
integer_in,
enum_in,
enum_array_in,
protobuf_enum_in,
)
for response in stream_measure_response:
result = response
Expand Down Expand Up @@ -572,6 +610,7 @@ def stream_measure(
integer_in: int = 10,
enum_in: EnumInEnum = EnumInEnum.BLUE,
enum_array_in: List[EnumInEnum] = [EnumInEnum.RED, EnumInEnum.GREEN],
protobuf_enum_in: ProtobufEnumInEnum = ProtobufEnumInEnum.BLACK,
) -> Generator[Outputs, None, None]:
"""Perform a streaming measurement.

Expand All @@ -592,6 +631,7 @@ def stream_measure(
integer_in,
enum_in,
enum_array_in,
protobuf_enum_in,
]
)
with self._initialization_lock:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ def __init__(

@property
def pin_map_context(self) -> PinMapContext:
"""Get the pin map context for the measurement."""
"""The pin map context for the measurement."""
return self._pin_map_context

@pin_map_context.setter
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import ni_measurement_plugin_sdk_service as nims
from ni_measurement_plugin_sdk_service._internal.stubs.ni.protobuf.types import xydata_pb2

from tests.utilities.measurements.non_streaming_data_measurement._stubs import color_pb2


service_directory = Path(__file__).resolve().parent
measurement_service = nims.MeasurementService(
Expand Down Expand Up @@ -66,6 +68,12 @@ class Color(Enum):
@measurement_service.configuration(
"Enum Array In", nims.DataType.EnumArray1D, [1, 2], enum_type=Color
)
@measurement_service.configuration(
"Protobuf Enum In",
nims.DataType.Enum,
color_pb2.ProtobufColor.BLACK,
enum_type=color_pb2.ProtobufColor,
)
@measurement_service.output("Float out", nims.DataType.Float)
@measurement_service.output("Double Array out", nims.DataType.DoubleArray1D)
@measurement_service.output("Bool out", nims.DataType.Boolean)
Expand All @@ -79,6 +87,9 @@ class Color(Enum):
@measurement_service.output("XY Data Out", nims.DataType.DoubleXYData)
@measurement_service.output("Enum Out", nims.DataType.Enum, enum_type=Color)
@measurement_service.output("Enum Array Out", nims.DataType.EnumArray1D, enum_type=Color)
@measurement_service.output(
"Protobuf Enum out", nims.DataType.Enum, enum_type=color_pb2.ProtobufColor
)
def measure(
float_input: float,
double_array_input: Iterable[float],
Expand All @@ -92,6 +103,7 @@ def measure(
integer_input: int,
enum_input: Color,
enum_array_input: Iterable[Color],
protobuf_enum_input: color_pb2.ProtobufColor.ValueType,
) -> Tuple[
float,
Iterable[float],
Expand All @@ -106,6 +118,7 @@ def measure(
xydata_pb2.DoubleXYData,
Color,
Iterable[Color],
color_pb2.ProtobufColor.ValueType,
]:
"""Perform a loopback measurement with various data types."""
float_output = float_input
Expand All @@ -121,6 +134,7 @@ def measure(
xy_data_output = xydata_pb2.DoubleXYData()
enum_output = enum_input
enum_array_output = enum_array_input
protobuf_enum_output = protobuf_enum_input

return (
float_output,
Expand All @@ -136,4 +150,5 @@ def measure(
xy_data_output,
enum_output,
enum_array_output,
protobuf_enum_output,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Stubs for non_streaming_data_measurement's color enum."""
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//---------------------------------------------------------------------
//---------------------------------------------------------------------
syntax = "proto3";

//---------------------------------------------------------------------
//---------------------------------------------------------------------
package ni.measurementlink.measurement.sample_measurement.v1;

//---------------------------------------------------------------------
//---------------------------------------------------------------------
option csharp_namespace = "NationalInstruments.MeasurementServices.Measurements";

//---------------------------------------------------------------------
//---------------------------------------------------------------------

enum ProtobufColor{
NONE = 0;
PINK = 1;
WHITE = 2;
BLACK = 3;
}
Loading