|
1 | | - |
2 | 1 | import pytest |
3 | 2 | from django.db import models |
4 | 3 | from django_enum import EnumField |
5 | 4 | from django_enum.choices import IntegerChoices |
6 | 5 | from django import VERSION as django_version |
7 | 6 |
|
| 7 | + |
8 | 8 | class MyEnum(IntegerChoices): |
9 | | - VAL1 = 1, 'Value 1' |
10 | | - VAL2 = 2, 'Value 2' |
| 9 | + VAL1 = 1, "Value 1" |
| 10 | + VAL2 = 2, "Value 2" |
| 11 | + |
11 | 12 |
|
12 | 13 | class GroupedEnum(IntegerChoices): |
13 | | - V1 = 1, 'One' |
14 | | - V2 = 2, 'Two' |
15 | | - V3 = 3, 'Three' |
| 14 | + V1 = 1, "One" |
| 15 | + V2 = 2, "Two" |
| 16 | + V3 = 3, "Three" |
| 17 | + |
16 | 18 |
|
17 | 19 | def get_choices_callable(): |
18 | | - return [(1, 'Callable 1'), (2, 'Callable 2')] |
| 20 | + return [(1, "Callable 1"), (2, "Callable 2")] |
| 21 | + |
19 | 22 |
|
20 | 23 | class EnumOverrideModel(models.Model): |
21 | 24 | # Dict choices (Django 5.0+) |
22 | | - dict_field = EnumField(MyEnum, choices={1: 'Dict 1', 2: 'Dict 2'}) |
| 25 | + dict_field = EnumField(MyEnum, choices={1: "Dict 1", 2: "Dict 2"}) |
23 | 26 |
|
24 | 27 | # Callable choices (Django 5.0+) |
25 | 28 | callable_field = EnumField(MyEnum, choices=get_choices_callable) |
26 | 29 |
|
27 | 30 | # Grouped choices |
28 | | - grouped_field = EnumField(GroupedEnum, choices=[ |
29 | | - ('Group A', [(1, 'One'), (2, 'Two')]), |
30 | | - ('Group B', [(3, 'Three')]), |
31 | | - ]) |
| 31 | + grouped_field = EnumField( |
| 32 | + GroupedEnum, |
| 33 | + choices=[ |
| 34 | + ("Group A", [(1, "One"), (2, "Two")]), |
| 35 | + ("Group B", [(3, "Three")]), |
| 36 | + ], |
| 37 | + ) |
32 | 38 |
|
33 | 39 | # Nested dict choices (Django 5.0+) |
34 | | - nested_dict_field = EnumField(MyEnum, choices={ |
35 | | - "Audio": { |
36 | | - 1: "Vinyl", |
37 | | - 2: "CD", |
| 40 | + nested_dict_field = EnumField( |
| 41 | + MyEnum, |
| 42 | + choices={ |
| 43 | + "Audio": { |
| 44 | + 1: "Vinyl", |
| 45 | + 2: "CD", |
| 46 | + }, |
| 47 | + "unknown": "Unknown", |
38 | 48 | }, |
39 | | - "unknown": "Unknown", |
40 | | - }) |
| 49 | + ) |
41 | 50 |
|
42 | 51 | class Meta: |
43 | 52 | abstract = True |
44 | | - app_label = 'tests' |
| 53 | + app_label = "tests" |
| 54 | + |
45 | 55 |
|
46 | 56 | def test_deconstruct_preserves_overrides(): |
47 | 57 | """Verify that deconstruct() preserves dictionary and callable overrides.""" |
48 | | - field = EnumOverrideModel._meta.get_field('dict_field') |
| 58 | + field = EnumOverrideModel._meta.get_field("dict_field") |
49 | 59 | name, path, args, kwargs = field.deconstruct() |
50 | | - assert kwargs['choices'] == {1: 'Dict 1', 2: 'Dict 2'} |
| 60 | + assert kwargs["choices"] == {1: "Dict 1", 2: "Dict 2"} |
51 | 61 |
|
52 | | - field = EnumOverrideModel._meta.get_field('callable_field') |
| 62 | + field = EnumOverrideModel._meta.get_field("callable_field") |
53 | 63 | name, path, args, kwargs = field.deconstruct() |
54 | | - assert kwargs['choices'] == get_choices_callable |
| 64 | + assert kwargs["choices"] == get_choices_callable |
55 | 65 |
|
56 | | - field = EnumOverrideModel._meta.get_field('nested_dict_field') |
| 66 | + field = EnumOverrideModel._meta.get_field("nested_dict_field") |
57 | 67 | name, path, args, kwargs = field.deconstruct() |
58 | | - assert kwargs['choices'] == { |
| 68 | + assert kwargs["choices"] == { |
59 | 69 | "Audio": {1: "Vinyl", 2: "CD"}, |
60 | 70 | "unknown": "Unknown", |
61 | 71 | } |
62 | 72 |
|
| 73 | + |
63 | 74 | def test_get_choices_handles_dict(): |
64 | 75 | """Verify that get_choices() handles dictionary choices correctly.""" |
65 | | - field = EnumOverrideModel._meta.get_field('dict_field') |
| 76 | + field = EnumOverrideModel._meta.get_field("dict_field") |
66 | 77 | # Django converts dict to list of tuples internally in super().get_choices() |
67 | 78 | choices = field.get_choices(include_blank=False) |
68 | | - assert choices == [(1, 'Dict 1'), (2, 'Dict 2')] |
| 79 | + assert choices == [(1, "Dict 1"), (2, "Dict 2")] |
| 80 | + |
69 | 81 |
|
70 | 82 | def test_get_choices_handles_nested_dict(): |
71 | 83 | """Verify that get_choices() handles nested dictionary choices correctly.""" |
72 | | - field = EnumOverrideModel._meta.get_field('nested_dict_field') |
| 84 | + field = EnumOverrideModel._meta.get_field("nested_dict_field") |
73 | 85 | choices = field.get_choices(include_blank=False) |
74 | 86 | # Normalized by Django + Coerced by EnumField |
75 | 87 | assert choices == [ |
76 | 88 | ("Audio", [(1, "Vinyl"), (2, "CD")]), |
77 | 89 | ("unknown", "Unknown"), |
78 | 90 | ] |
79 | 91 |
|
| 92 | + |
80 | 93 | def test_get_choices_handles_recursion(): |
81 | 94 | """Verify that get_choices() handles grouped choices correctly.""" |
82 | | - field = EnumOverrideModel._meta.get_field('grouped_field') |
| 95 | + field = EnumOverrideModel._meta.get_field("grouped_field") |
83 | 96 | choices = field.get_choices(include_blank=False) |
84 | 97 | assert choices == [ |
85 | | - ('Group A', [(1, 'One'), (2, 'Two')]), |
86 | | - ('Group B', [(3, 'Three')]), |
| 98 | + ("Group A", [(1, "One"), (2, "Two")]), |
| 99 | + ("Group B", [(3, "Three")]), |
87 | 100 | ] |
88 | 101 |
|
| 102 | + |
89 | 103 | def test_validation_with_overridden_choices(): |
90 | 104 | """Verify that validation uses the overridden labels or values.""" |
91 | | - field = EnumOverrideModel._meta.get_field('dict_field') |
| 105 | + field = EnumOverrideModel._meta.get_field("dict_field") |
92 | 106 | # Validation in Django usually checks if value is in choices |
93 | 107 | # EnumField also tries to coerce. |
94 | 108 | # 1 is a valid value for MyEnum and also in the dict |
95 | 109 | field.validate(1, None) |
96 | | - |
| 110 | + |
97 | 111 | # 3 is NOT in MyEnum and NOT in the dict |
98 | | - with pytest.raises(Exception): # Django raises ValidationError |
| 112 | + with pytest.raises(Exception): # Django raises ValidationError |
99 | 113 | field.validate(3, None) |
100 | 114 |
|
| 115 | + |
101 | 116 | from django import forms as django_forms |
102 | 117 | from django_enum.forms import EnumChoiceField |
103 | 118 |
|
| 119 | + |
104 | 120 | def test_form_field_with_nested_dict(): |
105 | 121 | """Verify that EnumChoiceField handles nested dictionary choices (non-strict).""" |
| 122 | + |
106 | 123 | class NonStrictForm(django_forms.Form): |
107 | 124 | field = EnumChoiceField( |
108 | | - MyEnum, |
| 125 | + MyEnum, |
109 | 126 | choices={ |
110 | 127 | "Audio": {1: "Vinyl", 2: "CD"}, |
111 | 128 | "unknown": "Unknown", |
112 | 129 | }, |
113 | | - strict=False |
| 130 | + strict=False, |
114 | 131 | ) |
115 | 132 |
|
116 | | - form = NonStrictForm(data={'field': 1}) |
| 133 | + form = NonStrictForm(data={"field": 1}) |
117 | 134 | assert form.is_valid() |
118 | | - |
| 135 | + |
119 | 136 | # 3 is not in Enum and not in dict |
120 | | - form = NonStrictForm(data={'field': 3}) |
121 | | - assert form.is_valid() # Non-strict allows it |
122 | | - |
| 137 | + form = NonStrictForm(data={"field": 3}) |
| 138 | + assert form.is_valid() # Non-strict allows it |
| 139 | + |
123 | 140 | # Rendering should include the added choice if it's not in choices |
124 | 141 | # This verifies NonStrictMixin.render() |
125 | | - widget = form.fields['field'].widget |
| 142 | + widget = form.fields["field"].widget |
126 | 143 | # Simulate a value not in choices |
127 | | - rendered = widget.render('field', 3, attrs={'id': 'id_field'}) |
| 144 | + rendered = widget.render("field", 3, attrs={"id": "id_field"}) |
128 | 145 | assert 'value="3"' in rendered |
129 | | - assert '>3<' in rendered |
| 146 | + assert ">3<" in rendered |
| 147 | + |
130 | 148 |
|
131 | 149 | def test_default_choices_still_work(): |
132 | 150 | """Verify that if no choices are provided, defaults from enum are used.""" |
| 151 | + |
133 | 152 | class DefaultModel(models.Model): |
134 | 153 | field = EnumField(MyEnum) |
| 154 | + |
135 | 155 | class Meta: |
136 | 156 | abstract = True |
137 | | - app_label = 'tests' |
| 157 | + app_label = "tests" |
138 | 158 |
|
139 | | - field = DefaultModel._meta.get_field('field') |
| 159 | + field = DefaultModel._meta.get_field("field") |
140 | 160 | name, path, args, kwargs = field.deconstruct() |
141 | | - assert kwargs['choices'] == [(1, 'Value 1'), (2, 'Value 2')] |
| 161 | + assert kwargs["choices"] == [(1, "Value 1"), (2, "Value 2")] |
0 commit comments