-
Notifications
You must be signed in to change notification settings - Fork 102
Fix _add_enum_value_python_name() to respect explicitly set value names #2073
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
base: master
Are you sure you want to change the base?
Changes from 3 commits
bdaa4ad
877be66
64f00ea
bf0540b
ff725c9
701c364
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -609,10 +609,11 @@ def _get_least_restrictive_codegen_method(codegen_methods): | |
| def _add_enum_value_python_name(enum_info, config): | ||
| '''Add 'python_name' for all values, removing any common prefixes and suffixes''' | ||
| for v in enum_info['values']: | ||
| v['user_set_python_name'] = 'python_name' in v | ||
| if 'python_name' not in v: | ||
| v['python_name'] = v['name'].replace('{}_VAL_'.format(config['module_name'].upper()), '') | ||
|
|
||
| # We are using an os.path function do find any common prefix. So that we don't | ||
| # We are using an os.path function to find any common prefix. So that we don't | ||
| # get 'O' in 'ON' and 'OFF' we remove characters at the end until they are '_' | ||
| names = [v['python_name'] for v in enum_info['values']] | ||
| prefix = os.path.commonprefix(names) | ||
|
|
@@ -627,13 +628,20 @@ def _add_enum_value_python_name(enum_info, config): | |
| # '_' only means the name starts with a number | ||
| if len(prefix) > 0 and prefix != '_': | ||
| for v in enum_info['values']: | ||
| if v['user_set_python_name']: | ||
| continue | ||
| assert v['python_name'].startswith(prefix), '{} does not start with {}'.format(v['name'], prefix) | ||
| v['prefix'] = prefix | ||
| v['python_name'] = v['python_name'].replace(prefix, '') | ||
|
|
||
| # Now we need to look for common suffixes | ||
| # Using the slow method of reversing a string for readability | ||
| rev_names = [''.join(reversed(v['python_name'])) for v in enum_info['values']] | ||
| # We do not include hardcoded python names when looking for common suffixes | ||
|
Member
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. Here you use
Member
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. FWIW I like the word "explicit" for this. It means (in my mind) that it's there written in metadata.
Collaborator
Author
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. I've stopped using the word hardcoded and made use of the word explicit, instead, as part of my rewrite. |
||
| rev_names = [ | ||
| ''.join(reversed(v['python_name'])) | ||
| for v in enum_info['values'] | ||
| if not v['user_set_python_name'] | ||
| ] | ||
| suffix = os.path.commonprefix(rev_names) | ||
| while len(suffix) > 0 and suffix[-1] != '_': | ||
| suffix = suffix[:-1] | ||
|
|
@@ -649,12 +657,15 @@ def _add_enum_value_python_name(enum_info, config): | |
| # '_' only means the name starts with a number | ||
| if len(suffix) > 0: | ||
| for v in enum_info['values']: | ||
| if v['user_set_python_name']: | ||
| continue | ||
| assert v['python_name'].endswith(suffix), '{} does not end with {}'.format(v['name'], suffix) | ||
| v['suffix'] = suffix | ||
| v['python_name'] = v['python_name'][:-len(suffix)] | ||
|
|
||
| # We need to check again to see if we have any values that start with a digit | ||
| # If we are not going to code generate this enum, we don't care about this | ||
| # Even hardcoded names should follow this rule | ||
| for v in enum_info['values']: | ||
| assert v['python_name'], enum_info | ||
| if enum_info['codegen_method'] != 'no' and v['python_name'][0].isdigit(): | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,5 +2,42 @@ | |
| # Any changes to the API should be made here. enums.py is code generated | ||
|
|
||
| enums_override_metadata = { | ||
| # TODO (ni-jfitzger): delete this override once python_name is corrected for each value. See https://github.com/ni/nimi-python/issues/2072 | ||
| 'ThermistorType': { | ||
| 'values': [ | ||
| { | ||
| 'documentation': { | ||
| 'description': 'Custom' | ||
| }, | ||
| 'name': 'NIDMM_VAL_TEMP_THERMISTOR_CUSTOM', | ||
| 'python_name': 'CUSTOM', | ||
|
Collaborator
Author
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. Strangely, (with the codegen helper changes) if I set
Member
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. Does that mean that if a client wants to explicitly provide the python name for a subset of enum values, we don't know what will be the expanded value here? I feel like it's worth getting to the bottom of, and having a test case for.
Collaborator
Author
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. It was almost certainly due to common suffix removal. The behavior was a little bit hard to follow, so I've rewritten my change and instead of using a boolean key for tracking whether to touch something, I'll have us do all of the processsing with a temporary key, '_python_name'. I've also added another unit test enum related to this. There's a peculiar behavior with common prefix and common suffix removal when you only have one value to calculate the prefix or suffix from. It calculates the prefix or suffix as the entire string and we then remove almost that entire string (upto and including the first/last underscore). I setting prefix and suffix to '', instead, when there's less than 2 values to calculate the commmon prefix or suffix from, but (upsetting as it is) we have one or two enums with a single enum value that actually make use of this behavior. I can still change it if you want, though. It seems like a footgun.
Collaborator
Author
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. With the latest change, we no longer need to set 'python_name': 'CUSTOM', but this behavior still seems like a footgun.
Member
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. If the behavior observed when only a subset of the enum values has Counterpoint is that bad expansion of a subset of enum values should be fairly apparent in generated code diffs. What do you think?
Collaborator
Author
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. It's easy to describe at this point. Everything up through the last underscore is trimmed. This is the same behavior we would see if the values that use You're correct that is very rare and even rarer is the case where we have an enum with only one value and the one value has multiple words and that enum is used somewhere so we don't filter it out in codegen. We only seem to have a couple of those and the current value names seem okay. I think it's fine to leave this change as is. We should be able to catch any issues in review.
Collaborator
Author
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.
Yeah, that's another option. Wouldn't be too difficult to do, though I'm not sure how easy it is to test. |
||
| 'value': 0 | ||
| }, | ||
| { | ||
| 'documentation': { | ||
| 'description': '44004' | ||
| }, | ||
| 'name': 'NIDMM_VAL_TEMP_THERMISTOR_44004', | ||
| 'python_name': 'THERMISTOR_44004', | ||
| 'value': 1 | ||
| }, | ||
| { | ||
| 'documentation': { | ||
| 'description': '44006' | ||
| }, | ||
| 'name': 'NIDMM_VAL_TEMP_THERMISTOR_44006', | ||
| 'python_name': 'THERMISTOR_44006', | ||
| 'value': 2 | ||
| }, | ||
| { | ||
| 'documentation': { | ||
| 'description': '44007' | ||
| }, | ||
| 'name': 'NIDMM_VAL_TEMP_THERMISTOR_44007', | ||
| 'python_name': 'THERMISTOR_44007', | ||
| 'value': 3 | ||
| } | ||
| ] | ||
| }, | ||
| } | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.