Skip to content

Commit 63cba3c

Browse files
committed
add more non strict and coerce tests, fix a few bugs
1 parent ea9ee72 commit 63cba3c

File tree

15 files changed

+364
-122
lines changed

15 files changed

+364
-122
lines changed

django_enum/fields.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -97,9 +97,13 @@ def _try_coerce(self, value: Any, force: bool = False) -> Union[Choices, Any]:
9797
value = self.enum(value)
9898
except (TypeError, ValueError):
9999
try:
100-
value = self.enum(self._coerce_to_value_type(value))
100+
value = self._coerce_to_value_type(value)
101+
value = self.enum(value)
101102
except (TypeError, ValueError) as err:
102-
if self.strict:
103+
if self.strict or not isinstance(
104+
value,
105+
type(self.enum.values[0])
106+
):
103107
raise ValueError(
104108
f"'{value}' is not a valid {self.enum.__name__} "
105109
f"required by field {self.name}."
@@ -126,7 +130,7 @@ def get_prep_value(self, value: Any) -> Any:
126130
See get_prep_value_
127131
"""
128132
if value is not None and self.enum is not None:
129-
value = self._try_coerce(value)
133+
value = self._try_coerce(value, force=True)
130134
if isinstance(value, self.enum):
131135
value = value.value
132136
return super().get_prep_value(value)
@@ -139,7 +143,7 @@ def get_db_prep_value(self, value, connection, prepared=False):
139143
See get_db_prep_value_
140144
"""
141145
if value is not None and self.enum is not None:
142-
value = self._try_coerce(value)
146+
value = self._try_coerce(value, force=True)
143147
if isinstance(value, self.enum):
144148
value = value.value
145149
return super().get_db_prep_value(

django_enum/forms.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,17 @@ class NonStrictSelect(Select):
2626
choices: Iterable[Tuple[Any, str]]
2727

2828
def render(self, *args, **kwargs):
29-
"""Before rendering if we're a non strict field and our value is """
30-
value: Any = kwargs.get('value')
31-
if value not in self.attrs.get('empty_values', []):
29+
"""
30+
Before rendering if we're a non-strict field and our value is not
31+
one of our choices, we add it as an option.
32+
"""
33+
value: Any = getattr(kwargs.get('value'), 'value', kwargs.get('value'))
34+
if (
35+
value not in self.attrs.get('empty_values', [])
36+
and value not in (
37+
choice[0] for choice in self.choices
38+
)
39+
):
3240
self.choices = list(self.choices) + [(value, str(value))]
3341
return super().render(*args, **kwargs)
3442

django_enum/tests/djenum/enums.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,12 +73,12 @@ class BigPosIntEnum(IntegerChoices):
7373
VAL0 = 0, 'Value 0'
7474
VAL1 = 1, 'Value 1'
7575
VAL2 = 2, 'Value 2'
76-
VAL3 = 2147483648, 'Value 2147483647'
76+
VAL3 = 2147483648, 'Value 2147483648'
7777

7878

7979
class BigIntEnum(IntegerChoices):
8080

8181
VAL0 = -2147483649, 'Value -2147483649'
8282
VAL1 = 1, 'Value 1'
8383
VAL2 = 2, 'Value 2'
84-
VAL3 = 2147483648, 'Value 2147483647'
84+
VAL3 = 2147483648, 'Value 2147483648'

django_enum/tests/djenum/forms.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ class EnumTesterForm(ModelForm):
2727
dj_int_enum = EnumChoiceField(DJIntEnum)
2828
dj_text_enum = EnumChoiceField(DJTextEnum)
2929
non_strict_int = EnumChoiceField(SmallPosIntEnum, strict=False)
30+
non_strict_text = EnumChoiceField(TextEnum, strict=False)
31+
no_coerce = EnumChoiceField(SmallPosIntEnum)
3032

3133
class Meta:
3234
model = EnumTester

django_enum/tests/djenum/migrations/0001_initial.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Generated by Django 3.2.14 on 2022-08-09 15:17
1+
# Generated by Django 3.2.14 on 2022-08-09 23:57
22

33
import django_enum.fields
44
from django.db import migrations, models
@@ -20,8 +20,8 @@ class Migration(migrations.Migration):
2020
('small_int', django_enum.fields.EnumSmallIntegerField(blank=True, choices=[(-32768, 'Value -32768'), (0, 'Value 0'), (1, 'Value 1'), (2, 'Value 2'), (32767, 'Value 32767')], db_index=True, default=32767)),
2121
('pos_int', django_enum.fields.EnumPositiveIntegerField(blank=True, choices=[(0, 'Value 0'), (1, 'Value 1'), (2, 'Value 2'), (2147483647, 'Value 2147483647')], db_index=True, default=2147483647)),
2222
('int', django_enum.fields.EnumIntegerField(blank=True, choices=[(-2147483648, 'Value -2147483648'), (0, 'Value 0'), (1, 'Value 1'), (2, 'Value 2'), (2147483647, 'Value 2147483647')], db_index=True, null=True)),
23-
('big_pos_int', django_enum.fields.EnumPositiveBigIntegerField(blank=True, choices=[(0, 'Value 0'), (1, 'Value 1'), (2, 'Value 2'), (2147483648, 'Value 2147483647')], db_index=True, default=None, null=True)),
24-
('big_int', django_enum.fields.EnumBigIntegerField(blank=True, choices=[(-2147483649, 'Value -2147483649'), (1, 'Value 1'), (2, 'Value 2'), (2147483648, 'Value 2147483647')], db_index=True, default=-2147483649)),
23+
('big_pos_int', django_enum.fields.EnumPositiveBigIntegerField(blank=True, choices=[(0, 'Value 0'), (1, 'Value 1'), (2, 'Value 2'), (2147483648, 'Value 2147483648')], db_index=True, default=None, null=True)),
24+
('big_int', django_enum.fields.EnumBigIntegerField(blank=True, choices=[(-2147483649, 'Value -2147483649'), (1, 'Value 1'), (2, 'Value 2'), (2147483648, 'Value 2147483648')], db_index=True, default=-2147483649)),
2525
('constant', django_enum.fields.EnumFloatField(blank=True, choices=[(3.141592653589793, 'Pi'), (2.71828, "Euler's Number"), (1.618033988749895, 'Golden Ratio')], db_index=True, default=None, null=True)),
2626
('text', django_enum.fields.EnumCharField(blank=True, choices=[('V1', 'Value1'), ('V22', 'Value2'), ('V333', 'Value3'), ('D', 'Default')], db_index=True, default=None, max_length=4, null=True)),
2727
('int_choice', models.IntegerField(blank=True, choices=[(1, 'One'), (2, 'Two'), (3, 'Three')], default=1)),

django_enum/tests/djenum/views.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,30 @@
11
from django.urls import reverse
22
from django.views.generic import DetailView, ListView
33
from django.views.generic.edit import CreateView, DeleteView, UpdateView
4+
from django_enum.tests.djenum import enums as dj_enums
45
from django_enum.tests.djenum.forms import EnumTesterForm
56
from django_enum.tests.djenum.models import EnumTester
67

78

89
class URLMixin:
910

1011
NAMESPACE = 'django_enum_tests_djenum'
12+
enums = dj_enums
1113

1214
def get_context_data(self, **kwargs):
1315
ctx = super().get_context_data(**kwargs)
16+
ctx.update({
17+
'Constants': self.enums.Constants,
18+
'SmallPosIntEnum': self.enums.SmallPosIntEnum,
19+
'SmallIntEnum': self.enums.SmallIntEnum,
20+
'PosIntEnum': self.enums.PosIntEnum,
21+
'IntEnum': self.enums.IntEnum,
22+
'BigPosIntEnum': self.enums.BigPosIntEnum,
23+
'BigIntEnum': self.enums.BigIntEnum,
24+
'TextEnum': self.enums.TextEnum,
25+
'DJIntEnum': self.enums.DJIntEnum,
26+
'DJTextEnum': self.enums.DJTextEnum,
27+
})
1428
try:
1529
ctx['update_path'] = reverse(
1630
f'{self.NAMESPACE}:enum-update',

django_enum/tests/enum_prop/enums.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,15 +74,15 @@ class BigPosIntEnum(IntegerChoices):
7474
VAL0 = 0, 'Value 0'
7575
VAL1 = 1, 'Value 1'
7676
VAL2 = 2, 'Value 2'
77-
VAL3 = 2147483648, 'Value 2147483647'
77+
VAL3 = 2147483648, 'Value 2147483648'
7878

7979

8080
class BigIntEnum(IntegerChoices, s('pos'), p('help')):
8181

8282
VAL0 = -2147483649, 'Value -2147483649', BigPosIntEnum.VAL0, _('One less than the least regular integer.')
8383
VAL1 = 1, 'Value 1', BigPosIntEnum.VAL1, _('Something in the middle.')
8484
VAL2 = 2, 'Value 2', BigPosIntEnum.VAL2, _('Something in the middle.')
85-
VAL3 = 2147483648, 'Value 2147483647', BigPosIntEnum.VAL3, _('One more than the greatest regular integer.')
85+
VAL3 = 2147483648, 'Value 2147483648', BigPosIntEnum.VAL3, _('One more than the greatest regular integer.')
8686

8787

8888
class PrecedenceTest(

django_enum/tests/enum_prop/forms.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ class EnumTesterForm(ModelForm):
2929
dj_int_enum = EnumChoiceField(DJIntEnum)
3030
dj_text_enum = EnumChoiceField(DJTextEnum)
3131
non_strict_int = EnumChoiceField(SmallPosIntEnum, strict=False)
32+
non_strict_text = EnumChoiceField(TextEnum, strict=False)
33+
no_coerce = EnumChoiceField(SmallPosIntEnum)
3234

3335
class Meta:
3436
model = EnumTester

django_enum/tests/enum_prop/migrations/0001_initial.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Generated by Django 3.2.14 on 2022-08-09 15:45
1+
# Generated by Django 3.2.14 on 2022-08-09 23:57
22

33
import django_enum.fields
44
from django.db import migrations, models
@@ -20,8 +20,8 @@ class Migration(migrations.Migration):
2020
('small_int', django_enum.fields.EnumSmallIntegerField(blank=True, choices=[(-32768, 'Value -32768'), (0, 'Value 0'), (1, 'Value 1'), (2, 'Value 2'), (32767, 'Value 32767')], db_index=True, default=32767)),
2121
('pos_int', django_enum.fields.EnumPositiveIntegerField(blank=True, choices=[(0, 'Value 0'), (1, 'Value 1'), (2, 'Value 2'), (2147483647, 'Value 2147483647')], db_index=True, default=2147483647)),
2222
('int', django_enum.fields.EnumIntegerField(blank=True, choices=[(-2147483648, 'Value -2147483648'), (0, 'Value 0'), (1, 'Value 1'), (2, 'Value 2'), (2147483647, 'Value 2147483647')], db_index=True, null=True)),
23-
('big_pos_int', django_enum.fields.EnumPositiveBigIntegerField(blank=True, choices=[(0, 'Value 0'), (1, 'Value 1'), (2, 'Value 2'), (2147483648, 'Value 2147483647')], db_index=True, default=None, null=True)),
24-
('big_int', django_enum.fields.EnumBigIntegerField(blank=True, choices=[(-2147483649, 'Value -2147483649'), (1, 'Value 1'), (2, 'Value 2'), (2147483648, 'Value 2147483647')], db_index=True, default=-2147483649)),
23+
('big_pos_int', django_enum.fields.EnumPositiveBigIntegerField(blank=True, choices=[(0, 'Value 0'), (1, 'Value 1'), (2, 'Value 2'), (2147483648, 'Value 2147483648')], db_index=True, default=None, null=True)),
24+
('big_int', django_enum.fields.EnumBigIntegerField(blank=True, choices=[(-2147483649, 'Value -2147483649'), (1, 'Value 1'), (2, 'Value 2'), (2147483648, 'Value 2147483648')], db_index=True, default=-2147483649)),
2525
('constant', django_enum.fields.EnumFloatField(blank=True, choices=[(3.141592653589793, 'Pi'), (2.71828, "Euler's Number"), (1.618033988749895, 'Golden Ratio')], db_index=True, default=None, null=True)),
2626
('text', django_enum.fields.EnumCharField(blank=True, choices=[('V1', 'Value1'), ('V22', 'Value2'), ('V333', 'Value3'), ('D', 'Default')], db_index=True, default=None, max_length=4, null=True)),
2727
('int_choice', models.IntegerField(blank=True, choices=[(1, 'One'), (2, 'Two'), (3, 'Three')], default=1)),
@@ -56,8 +56,8 @@ class Migration(migrations.Migration):
5656
('small_int', django_enum.fields.EnumSmallIntegerField(blank=True, choices=[(-32768, 'Value -32768'), (0, 'Value 0'), (1, 'Value 1'), (2, 'Value 2'), (32767, 'Value 32767')], db_index=True, default=32767)),
5757
('pos_int', django_enum.fields.EnumPositiveIntegerField(blank=True, choices=[(0, 'Value 0'), (1, 'Value 1'), (2, 'Value 2'), (2147483647, 'Value 2147483647')], db_index=True, default=2147483647)),
5858
('int', django_enum.fields.EnumIntegerField(blank=True, choices=[(-2147483648, 'Value -2147483648'), (0, 'Value 0'), (1, 'Value 1'), (2, 'Value 2'), (2147483647, 'Value 2147483647')], db_index=True, null=True)),
59-
('big_pos_int', django_enum.fields.EnumPositiveBigIntegerField(blank=True, choices=[(0, 'Value 0'), (1, 'Value 1'), (2, 'Value 2'), (2147483648, 'Value 2147483647')], db_index=True, default=None, null=True)),
60-
('big_int', django_enum.fields.EnumBigIntegerField(blank=True, choices=[(-2147483649, 'Value -2147483649'), (1, 'Value 1'), (2, 'Value 2'), (2147483648, 'Value 2147483647')], db_index=True, default=-2147483649)),
59+
('big_pos_int', django_enum.fields.EnumPositiveBigIntegerField(blank=True, choices=[(0, 'Value 0'), (1, 'Value 1'), (2, 'Value 2'), (2147483648, 'Value 2147483648')], db_index=True, default=None, null=True)),
60+
('big_int', django_enum.fields.EnumBigIntegerField(blank=True, choices=[(-2147483649, 'Value -2147483649'), (1, 'Value 1'), (2, 'Value 2'), (2147483648, 'Value 2147483648')], db_index=True, default=-2147483649)),
6161
('constant', django_enum.fields.EnumFloatField(blank=True, choices=[(3.141592653589793, 'Pi'), (2.71828, "Euler's Number"), (1.618033988749895, 'Golden Ratio')], db_index=True, default=None, null=True)),
6262
('text', django_enum.fields.EnumCharField(blank=True, choices=[('V1', 'Value1'), ('V22', 'Value2'), ('V333', 'Value3'), ('D', 'Default')], db_index=True, default=None, max_length=4, null=True)),
6363
('int_choice', models.IntegerField(blank=True, choices=[(1, 'One'), (2, 'Two'), (3, 'Three')], default=1)),
@@ -83,8 +83,8 @@ class Migration(migrations.Migration):
8383
('small_int', models.SmallIntegerField(blank=True, choices=[(-32768, 'Value -32768'), (0, 'Value 0'), (1, 'Value 1'), (2, 'Value 2'), (32767, 'Value 32767')], db_index=True, default=32767)),
8484
('pos_int', models.PositiveIntegerField(blank=True, choices=[(0, 'Value 0'), (1, 'Value 1'), (2, 'Value 2'), (2147483647, 'Value 2147483647')], db_index=True, default=2147483647)),
8585
('int', models.IntegerField(blank=True, choices=[(-2147483648, 'Value -2147483648'), (0, 'Value 0'), (1, 'Value 1'), (2, 'Value 2'), (2147483647, 'Value 2147483647')], db_index=True, null=True)),
86-
('big_pos_int', models.PositiveBigIntegerField(blank=True, choices=[(0, 'Value 0'), (1, 'Value 1'), (2, 'Value 2'), (2147483648, 'Value 2147483647')], db_index=True, default=None, null=True)),
87-
('big_int', models.BigIntegerField(blank=True, choices=[(-2147483649, 'Value -2147483649'), (1, 'Value 1'), (2, 'Value 2'), (2147483648, 'Value 2147483647')], db_index=True, default=-2147483649)),
86+
('big_pos_int', models.PositiveBigIntegerField(blank=True, choices=[(0, 'Value 0'), (1, 'Value 1'), (2, 'Value 2'), (2147483648, 'Value 2147483648')], db_index=True, default=None, null=True)),
87+
('big_int', models.BigIntegerField(blank=True, choices=[(-2147483649, 'Value -2147483649'), (1, 'Value 1'), (2, 'Value 2'), (2147483648, 'Value 2147483648')], db_index=True, default=-2147483649)),
8888
('constant', models.FloatField(blank=True, choices=[(3.141592653589793, 'Pi'), (2.71828, "Euler's Number"), (1.618033988749895, 'Golden Ratio')], db_index=True, default=None, null=True)),
8989
('text', models.CharField(blank=True, choices=[('V1', 'Value1'), ('V22', 'Value2'), ('V333', 'Value3'), ('D', 'Default')], db_index=True, default=None, max_length=4, null=True)),
9090
('int_choice', models.IntegerField(blank=True, choices=[(1, 'One'), (2, 'Two'), (3, 'Three')], default=1)),

django_enum/tests/enum_prop/views.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,28 +2,33 @@
22
from django.urls import reverse, reverse_lazy
33
from django_enum.filters import FilterSet as EnumFilterSet
44
from django_enum.tests.djenum import views
5+
from django_enum.tests.enum_prop import enums as prop_enums
56
from django_enum.tests.enum_prop.forms import EnumTesterForm
67
from django_enum.tests.enum_prop.models import EnumTester
78

89

910
class EnumTesterDetailView(views.EnumTesterDetailView):
1011
model = EnumTester
1112
NAMESPACE = 'django_enum_tests_enum_prop'
13+
enums = prop_enums
1214

1315

1416
class EnumTesterListView(views.EnumTesterListView):
1517
model = EnumTester
1618
NAMESPACE = 'django_enum_tests_enum_prop'
19+
enums = prop_enums
1720

1821

1922
class EnumTesterCreateView(views.EnumTesterCreateView):
2023
model = EnumTester
2124
NAMESPACE = 'django_enum_tests_enum_prop'
25+
enums = prop_enums
2226

2327

2428
class EnumTesterUpdateView(views.EnumTesterUpdateView):
2529
model = EnumTester
2630
NAMESPACE = 'django_enum_tests_enum_prop'
31+
enums = prop_enums
2732

2833
def get_success_url(self): # pragma: no cover
2934
return reverse(f'{self.NAMESPACE}:enum-update',
@@ -34,6 +39,7 @@ class EnumTesterFormView(views.EnumTesterFormView):
3439
form_class = EnumTesterForm
3540
model = EnumTester
3641
NAMESPACE = 'django_enum_tests_enum_prop'
42+
enums = prop_enums
3743

3844
def get_success_url(self): # pragma: no cover
3945
return reverse(f'{self.NAMESPACE}:enum-update',
@@ -43,24 +49,29 @@ class EnumTesterFormCreateView(views.EnumTesterFormCreateView):
4349
form_class = EnumTesterForm
4450
model = EnumTester
4551
NAMESPACE = 'django_enum_tests_enum_prop'
52+
enums = prop_enums
4653

4754

4855
class EnumTesterDeleteView(views.EnumTesterDeleteView):
4956
model = EnumTester
5057
NAMESPACE = 'django_enum_tests_enum_prop'
58+
enums = prop_enums
5159

5260

5361
class EnumTesterFormDeleteView(views.EnumTesterFormDeleteView):
5462
form_class = EnumTesterForm
5563
model = EnumTester
5664
NAMESPACE = 'django_enum_tests_enum_prop'
65+
enums = prop_enums
5766

5867
try:
5968

6069
from django_enum.tests.djenum.views import EnumTesterFilterViewSet
6170

6271
class EnumTesterFilterViewSet(EnumTesterFilterViewSet):
6372

73+
enums = prop_enums
74+
6475
class EnumTesterFilter(EnumFilterSet):
6576
class Meta:
6677
model = EnumTester

0 commit comments

Comments
 (0)