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

Added enum support to Measurement Client #880

Merged
merged 31 commits into from
Sep 17, 2024

Conversation

MounikaBattu17
Copy link
Contributor

@MounikaBattu17 MounikaBattu17 commented Sep 10, 2024

What does this Pull Request accomplish?

Added enum support for Measurement Client
Implements Task 2827579: Extend support to enums.

Why should this Pull Request be merged?

With this implementation, Measurement Client supports measurements with enum parameters.

  • Created a new enum class using enum values from metadata annotations.
  • The new enum class name in created using parameter name suffixed with Enum in pascal case. Also, removed special characters from the class name.
    For example,
  parameter name = Enum In
  enum class name = EnumInEnum     # PascalCase(parameter name) + "Enum"
  • Stored the created enum class in enum_values_by_type_name which acts as a map to eliminate repeating enums.
    For example, Configuration Enum In and Output Enum Out will use the same Enum class, so enum_values_by_type_name will be useful to avoid creating duplicate enums for both parameters.
  • Applied enum_type while creating pools for the metadata.
  • While black formatting the rendered template, replaced this enum class pattern.
    enum_type=<enum 'EnumInEnum'>) -> enum_type= EnumInEnum

What testing has been done?

Added automated tests.
Generated and verified the client with enum params like enums, enum arrays, and sparse enums.

Copy link

github-actions bot commented Sep 10, 2024

Test Results

    30 files  ±0      30 suites  ±0   38m 42s ⏱️ - 8m 11s
   651 tests ±0     651 ✅ ±0      0 💤 ±0  0 ❌ ±0 
16 130 runs  ±0  15 060 ✅ ±0  1 070 💤 ±0  0 ❌ ±0 

Results for commit 31a11e9. ± Comparison against base commit 0462410.

♻️ This comment has been updated with latest results.

@MounikaBattu17
Copy link
Contributor Author

MounikaBattu17 commented Sep 10, 2024

We construct new enum class using enum values from metadata.annotations. Unlike enums, LabVIEW rings, doesn't pass ring values in metadata.annotations. Thus for rings, we have treated them as integers. So this is the behaviour for enums and rings

enum parameter in measurement:
image
enum parameter in python client:
u32_animal_enum_in: U32AnimalEnumInEnum = U32AnimalEnumInEnum.Gopher

ring parameter in measurement:
image
image

ring parameter in python client:
u32_color_ring_in: int = 1

So, ring values can be only be set to integers in client, we cannot use the name (RED, GREEN, BLUE) here.

Please share your thoughts on this

@bkeryan We confirmed this behaviour for LabVIEW client. Can you please share your thoughts on this behaviour for python client.

@MounikaBattu17
Copy link
Contributor Author

There is a mypy error and will be fixed soon.

@MounikaBattu17
Copy link
Contributor Author

There is a mypy error and will be fixed soon.

Fixed.

The error was on this line
new_enum_type = Enum(new_enum_type_name, enum_values) # error: Enum() expects a string literal as the first argument [misc]

seems like mypy static analysis checks for a string literal but we pass a variable.

To resolve this error, I've used enum __call__ method directly to create enums dynamically at runtime.
new_enum_type = Enum.__call__(new_enum_type_name, enum_values)

@bkeryan
Copy link
Collaborator

bkeryan commented Sep 13, 2024

There is a mypy error and will be fixed soon.

Fixed.

The error was on this line new_enum_type = Enum(new_enum_type_name, enum_values) # error: Enum() expects a string literal as the first argument [misc]

seems like mypy static analysis checks for a string literal but we pass a variable.

To resolve this error, I've used enum __call__ method directly to create enums dynamically at runtime. new_enum_type = Enum.__call__(new_enum_type_name, enum_values)

This is an indication that we are using the enum functional API wrong (as far as the Mypy authors are concerned, at least).

I don't think that calling dunder methods directly is a good solution, because dunder methods are typically implementations of Python features that have their own syntax, and in most cases you should use that syntax instead.

If we absolutely must use the enum functional API in this way, then I would prefer to use # type: ignore[misc] on the line that does this and put a comment above it saying why we have to do it this way.

Also I don't think the generated code should be doing this at all. It has static definitions of all of the enum types and it should use them.

@MounikaBattu17
Copy link
Contributor Author

If we absolutely must use the enum functional API in this way, then I would prefer to use # type: ignore[misc] on the line that does this and put a comment above it saying why we have to do it this way.

Seems like MyPy static analysis throws an error if we don't use a direct string literal for dynamic Enum creation. So I have suppressed the error instead of using dunner method like you suggested.

Syntax like,

Enum('Color', {"NONE":0, "RED": 1}) -> no mypy error

enum_name: str = "Color"
Enum(enum_name, {"NONE":0, "RED": 1}) -> throws mypy error

Also I don't think the generated code should be doing this at all. It has static definitions of all of the enum types and it should use them.

Removed and used the already available metadata.

@MounikaBattu17 MounikaBattu17 merged commit 09b40b0 into main Sep 17, 2024
17 checks passed
Comment on lines +37 to +39
def _replace_enum_class_type(output: str) -> str:
pattern = "<enum '([^']+)'>"
return re.sub(pattern, r"\1", output)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this method go into _support.py?

name = "".join(s.capitalize() for s in split_string)
else:
name = name[0].upper() + name[1:]
return name + "Enum"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prefer f-strings for better readability.

Comment on lines +65 to +68
@measurement_service.configuration("Enum In", nims.DataType.Enum, Color.BLUE, enum_type=Color)
@measurement_service.configuration(
"Enum Array In", nims.DataType.EnumArray1D, [1, 2], enum_type=Color
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be an over-ask but because we showcase "protobuf enums" in our sample measurement, should we also test the Protobuf Enum type with our client to ensure we're not missing anything on that part?

@jayaseelan-james jayaseelan-james deleted the users/mounika/client-add-enum-support branch September 20, 2024 14:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants