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

Fix choices in ChoiceField to support IntEnum #8955

Merged
merged 1 commit into from Jul 13, 2023

Conversation

b7wch
Copy link
Contributor

@b7wch b7wch commented Apr 20, 2023

Description

Python support Enum in version 3.4, but changed __str__ to int.__str__ until version 3.11 to better support the replacement of existing constants use-case. https://docs.python.org/3/library/enum.html#enum.IntEnum

rest_framework support Python 3.6+, this commit will support the Enum as datatype of choices in Field.

Discussions: #8945

Copy link
Member

@auvipy auvipy left a comment

Choose a reason for hiding this comment

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

besides, this will need unit test coverage

@@ -1397,7 +1397,8 @@ def __init__(self, choices, **kwargs):
def to_internal_value(self, data):
if data == '' and self.allow_blank:
return ''

if isinstance(data, Enum) and str(data) != str(data.value):
Copy link
Member

Choose a reason for hiding this comment

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

from the test failures it seems that Enum is not defined. you might forgot to import it? or could you check what is the issue?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thank you, I have added the import statement now.

Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure why you are removing the django compatibility support codes here if isinstance(data, (IntegerChoices, TextChoices)) and str(data) !=
str(data.value):

@b7wch b7wch force-pushed the enum_choice branch 2 times, most recently from 3ca5d08 to b8926b0 Compare April 20, 2023 04:34
@b7wch b7wch requested a review from auvipy April 23, 2023 03:51
@@ -1397,7 +1398,8 @@ def __init__(self, choices, **kwargs):
def to_internal_value(self, data):
if data == '' and self.allow_blank:
return ''

if isinstance(data, Enum) and str(data) != str(data.value):
Copy link
Member

Choose a reason for hiding this comment

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

can you please add unit test coverage for the changes?

Copy link
Member

@auvipy auvipy left a comment

Choose a reason for hiding this comment

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

Since the case where the enum values need to be integers is extremely common, Django provides an IntegerChoices class. For example:

class Card(models.Model):

class Suit(models.IntegerChoices):
    DIAMOND = 1
    SPADE = 2
    HEART = 3
    CLUB = 4

suit = models.IntegerField(choices=Suit.choices)

did you check this?

https://docs.djangoproject.com/en/3.2/ref/models/fields/#enumeration-types

@b7wch
Copy link
Contributor Author

b7wch commented Apr 24, 2023

Since the case where the enum values need to be integers is extremely common, Django provides an IntegerChoices class. For example:

class Card(models.Model):

class Suit(models.IntegerChoices):
    DIAMOND = 1
    SPADE = 2
    HEART = 3
    CLUB = 4

suit = models.IntegerField(choices=Suit.choices)

did you check this?

https://docs.djangoproject.com/en/3.2/ref/models/fields/#enumeration-types

Thanks for your suggestion, I use the class Enum implemented in python standard library first, and then I found that rest_framework is suitable for Enum.
Of course models.IntegerChoices could handle this situation too, but I think support Enum natively is also necessary.

@auvipy
Copy link
Member

auvipy commented Apr 25, 2023

this a django extension and should be using what django provides first

@auvipy
Copy link
Member

auvipy commented Apr 30, 2023

please use built in django feature here

@auvipy
Copy link
Member

auvipy commented May 2, 2023

closing in favor of #8968

@auvipy auvipy closed this May 2, 2023
@auvipy auvipy reopened this May 2, 2023
@auvipy
Copy link
Member

auvipy commented May 2, 2023

@encode/django-rest-framework hello team, should we consider supporting python Enum directly beside the django built in ones?

@b7wch
Copy link
Contributor Author

b7wch commented May 9, 2023

@encode/django-rest-framework hello team, should we consider supporting python Enum directly beside the django built in ones?
closing in favor of #8968

Compare to #8968, I think my commit is more widely applicable

@auvipy
Copy link
Member

auvipy commented May 9, 2023

that is a django compat fix. If anyone want to support direct python enum, we need to rebase this PR :)

Copy link
Member

@auvipy auvipy left a comment

Choose a reason for hiding this comment

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

can you please rebase it again?

@b7wch b7wch force-pushed the enum_choice branch 3 times, most recently from 8999b29 to a4e1038 Compare July 6, 2023 07:24
@b7wch
Copy link
Contributor Author

b7wch commented Jul 6, 2023

can you please rebase it again?

@auvipy ok, I have rebased it.

@@ -1397,7 +1397,8 @@ def __init__(self, choices, **kwargs):
def to_internal_value(self, data):
if data == '' and self.allow_blank:
return ''

if isinstance(data, Enum) and str(data) != str(data.value):
Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure why you are removing the django compatibility support codes here if isinstance(data, (IntegerChoices, TextChoices)) and str(data) !=
str(data.value):

@@ -1414,11 +1411,8 @@ def to_internal_value(self, data):
def to_representation(self, value):
if value in ('', None):
return value

if isinstance(value, (IntegerChoices, TextChoices)) and str(value) != \
Copy link
Member

Choose a reason for hiding this comment

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

same goes for this. we are not going to remove django compatibility features.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I should make it clear.
if isinstance(value, (IntegerChoices, TextChoices)) and str(value) != \ in #8986 not resolve the problem, and this if judgment will never be executed with the IntegerChoices and TextChoices.
Because this problem only occurs in the python version little than 3.11 and use Enum as base class.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Add if isinstance(data, Enum) and str(data) != str(data.value): just enhances the Enum support for python version little than 3.11.
if isinstance(value, (IntegerChoices, TextChoices)) and str(value) != \ has not effect when users use IntegerChoices or TextChoices, because str(value) always equal to value.value according to 8740ff334ae3e001514c42ac1fb63a5e4cfa5cd1, but user swill still meet the problem when they use Enum, because that if judgment not solve the problem of IntEnum in different python version.

rest_framework/fields.py Show resolved Hide resolved
@@ -1875,26 +1877,26 @@ def test_edit_choices(self):
field.run_validation(2)
assert exc_info.value.detail == ['"2" is not a valid choice.']

def test_integer_choices(self):
class ChoiceCase(IntegerChoices):
def test_enum_choices(self):
Copy link
Member

Choose a reason for hiding this comment

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

It would make sense to add this new test in addition to keeping the old IntegerChoices test just to ensure we don't have regressions in future versions of Django if they decide to do something special with that class.

@auvipy
Copy link
Member

auvipy commented Jul 13, 2023

Hey Burson! you were suggested to add new tests beside keeping the old tests using django specific class.

see:

It would make sense to add this new test in addition to keeping the old IntegerChoices test just to ensure we don't have regressions in future versions of Django if they decide to do something special with that class.

@b7wch b7wch force-pushed the enum_choice branch 2 times, most recently from 6086601 to b043df8 Compare July 13, 2023 08:00
Python support Enum in version 3.4, but changed __str__ to int.__str__ until version 3.11 to better support the replacement of existing constants use-case.
[https://docs.python.org/3/library/enum.html#enum.IntEnum](https://docs.python.org/3/library/enum.html#enum.IntEnum)

rest_frame work support Python 3.6+, this commit will support the Enum in choices of Field.
@b7wch
Copy link
Contributor Author

b7wch commented Jul 13, 2023

Hey Burson! you were suggested to add new tests beside keeping the old tests using django specific class.

see:

It would make sense to add this new test in addition to keeping the old IntegerChoices test just to ensure we don't have regressions in future versions of Django if they decide to do something special with that class.

@auvipy New test has added, and keeping the old tests.

@auvipy auvipy merged commit 66d86d0 into encode:master Jul 13, 2023
6 of 7 checks passed
@auvipy
Copy link
Member

auvipy commented Jul 13, 2023

Thanks Burson! sorry for the initial over sight!

@b7wch
Copy link
Contributor Author

b7wch commented Jul 13, 2023

Thanks Asif Saif Uddin for your patient guidance and valuable insights.

math-a3k pushed a commit to math-a3k/django-rest-framework that referenced this pull request Jul 31, 2023
Python support Enum in version 3.4, but changed __str__ to int.__str__ until version 3.11 to better support the replacement of existing constants use-case.
[https://docs.python.org/3/library/enum.html#enum.IntEnum](https://docs.python.org/3/library/enum.html#enum.IntEnum)

rest_frame work support Python 3.6+, this commit will support the Enum in choices of Field.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants