-
-
Notifications
You must be signed in to change notification settings - Fork 125
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
Fix/489 auto enum value allowed chars #494
Fix/489 auto enum value allowed chars #494
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey fabien-michel - Here's my review!
General suggestions:
- Consider implementing a mechanism to ensure the uniqueness of sanitized enum names to avoid potential naming collisions.
- Refactor the sanitization logic into a separate, reusable function to simplify the main code block and improve code readability.
- Expand the test cases to cover a wider range of special characters and scenarios, ensuring comprehensive coverage.
- Explicitly verify in tests that the original value of the enum is preserved and correctly associated with the transformed name, maintaining the integrity of the mapping.
Thanks for using Sourcery. We offer it for free for open source projects and would be very grateful if you could help us grow. If you like it, would you consider sharing Sourcery on your favourite social media? ✨
strawberry_django/fields/types.py
Outdated
choice_name = re.sub(r"^[^a-zA-Z]|[^a-zA-Z0-9]", "_", c[0]) | ||
# use str() to trigger eventual django's gettext_lazy string | ||
choice_value = EnumValueDefinition(value=c[0], description=str(c[1])) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion (llm): The approach to sanitize choice names for GraphQL compatibility is sensible. However, consider edge cases where the sanitization might lead to name collisions. For instance, if the original choices contain both '1example' and 'example', both would be sanitized to '_example', causing a conflict. It might be beneficial to implement a mechanism to ensure uniqueness of the sanitized names.
field_type = getattr(model_field, "_strawberry_enum", None) | ||
if field_type is None: | ||
meta = model_field.model._meta | ||
|
||
enum_choices = {} | ||
for c in model_field.choices: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue (llm): The new implementation introduces additional complexity, particularly with the use of regular expressions and the iterative approach for constructing enum_choices
. While ensuring compatibility with GraphQL naming conventions is important, we might consider streamlining this process to maintain code readability and reduce cognitive load.
One suggestion is to encapsulate the naming convention logic into a separate function, which could simplify the main code block. For example:
def sanitize_enum_name(name):
# Replace chars not compatible with GraphQL naming convention
return re.sub(r"^[^a-zA-Z]|[^a-zA-Z0-9]", "_", name)
And then integrate this function into the original dictionary comprehension:
field_type = strawberry.enum(
enum.Enum(
"".join(
(
capitalize_first(to_camel_case(meta.app_label)),
str(meta.object_name),
capitalize_first(to_camel_case(model_field.name)),
"Enum",
),
),
{
sanitize_enum_name(c[0]): EnumValueDefinition(value=c[0], description=str(c[1]))
for c in model_field.choices
},
),
description=(
f"{meta.verbose_name} | {model_field.verbose_name}"
if settings["FIELD_DESCRIPTION_FROM_HELP_TEXT"]
else None
),
)
This approach keeps the code concise and maintains readability, while still achieving the goal of ensuring GraphQL naming convention compatibility.
@@ -18,15 +19,16 @@ class Choice(models.TextChoices): | |||
|
|||
A = "a", "A description" | |||
B = "b", "B description" | |||
C = "c", "C description" | |||
C = "c", gettext_lazy("C description") | |||
D = "12d-d'éléphant_🐘", "D description" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion (llm): It's great to see a test case added for the new functionality handling special characters in enum names. However, to ensure comprehensive coverage, consider adding more diverse test cases that include a wider range of special characters and scenarios. For example, strings starting with numbers, containing only special characters, or being empty.
@@ -296,6 +300,9 @@ def obj(self) -> ChoicesType: | |||
|
|||
"""C description""" | |||
c | |||
|
|||
"""D description""" | |||
_2d_d__l_phant__ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion (llm): I noticed that the test verifies the transformation of '12d-d'éléphant_🐘' to '2d_d__l_phant_', which aligns with the implementation. However, it would be beneficial to add assertions that explicitly check the underlying value of the enum (i.e., '12d-d'éléphant_🐘') is preserved and correctly associated with the transformed name. This ensures that the mapping between the GraphQL enum name and its original value remains intact.
strawberry_django/fields/types.py
Outdated
enum_choices = {} | ||
for c in model_field.choices: | ||
# replace chars not compatible with GraphQL naming convention | ||
choice_name = re.sub(r"^[^a-zA-Z]|[^a-zA-Z0-9]", "_", c[0]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion (llm): The regex used for replacing non-valid characters seems to replace any character at the start of the string that is not an alphabet and any character in the string that is not alphanumeric. This approach might not handle cases where the string starts with a valid underscore or has valid underscores in between. Consider refining the regex to avoid unnecessary replacements of valid underscores and ensure it aligns with GraphQL naming conventions more accurately.
strawberry_django/fields/types.py
Outdated
enum_choices = {} | ||
for c in model_field.choices: | ||
# replace chars not compatible with GraphQL naming convention | ||
choice_name = re.sub(r"^[^a-zA-Z]|[^a-zA-Z0-9]", "_", c[0]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue (llm): The implementation replaces invalid characters with underscores, which is a good approach. However, it might lead to potential naming collisions. For instance, '1-a' and '1_a' would both be converted to '_1_a'. It would be beneficial to add a mechanism to detect and resolve such collisions, ensuring the uniqueness of enum names.
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## main #494 +/- ##
==========================================
+ Coverage 87.95% 87.98% +0.03%
==========================================
Files 37 37
Lines 3172 3180 +8
==========================================
+ Hits 2790 2798 +8
Misses 382 382 ☔ View full report in Codecov by Sentry. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TY! :)
Use regex to replace invalid characters in auto generated enums.
This occur because django's choice values are strings and can contain any chars.
Exemple This
Choice.choices
return(("en-US", "English"),)
, and hyphen is not a valid char for GraphQL naming convention. So it would fail.The PR replace non valid chars to
_
.Types of Changes
Issues Fixed or Closed by This PR
Checklist