support for Django 5.0+ choice override types (dictionaries and calla…#178
support for Django 5.0+ choice override types (dictionaries and calla…#178JohananOppongAmoateng wants to merge 7 commits intodjango-commons:mainfrom
Conversation
88724cc to
914b828
Compare
There was a problem hiding this comment.
Pull request overview
Adds compatibility in EnumField (and related form widgets/fields) for Django 5.0+ “choices overrides” that can be provided as dictionaries or callables, while preserving the original override format through deconstruct().
Changes:
- Add
normalize_choices()utility and exposedjango_versionfromdjango_enum.utils. - Update
EnumFieldto preserve originalchoicesoverrides indeconstruct()and recursively coerce nested/grouped choices inget_choices(). - Update form widgets/fields to better handle nested/grouped choices and normalize dict/callable choices on Django < 5.0; add a dedicated test module.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| tests/test_django5_overrides.py | Adds regression tests for dict/callable/nested/grouped choices overrides and deconstruction behavior. |
| src/django_enum/utils.py | Introduces normalize_choices() and exports django_version for cross-version choices handling. |
| src/django_enum/forms.py | Updates non-strict widget rendering logic and normalizes pre-Django-5 choices inputs. |
| src/django_enum/fields.py | Preserves original override formats in deconstruct() and improves recursive coercion of complex choices. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| raw_choices = zip(get_set_values(value), get_set_bits(value)) | ||
| self.choices = list(self.choices) | ||
| choice_values = set(choice[0] for choice in self.choices) | ||
| for value, label in raw_choices: | ||
| if value not in choice_values: | ||
| self.choices.append((value, label)) | ||
| return super().render(*args, **kwargs) # type: ignore[misc] | ||
|
|
There was a problem hiding this comment.
NonStrictFlagMixin.render() converts self.choices with list(self.choices). If self.choices is a dict (allowed on Django 5+), this becomes a list of keys, which will break the subsequent (choice, label) unpacking in _get_values() and also makes the later isinstance(self.choices, dict) branch unreachable. Consider preserving the original dict (or converting dicts via .items()) before iterating/unpacking so dict-based choices work correctly.
| with pytest.raises(Exception): # Django raises ValidationError | ||
| field.validate(3, None) |
There was a problem hiding this comment.
This test expects a ValidationError, but it currently uses pytest.raises(Exception), which can mask unrelated errors and make failures harder to diagnose. Prefer asserting the specific django.core.exceptions.ValidationError (as other tests in this suite do).
| from django.db import models | ||
| from django_enum import EnumField | ||
| from django.db.models import IntegerChoices | ||
| from django import VERSION as django_version |
There was a problem hiding this comment.
django_version is imported but never used in this test module. Either remove the import, or use it (e.g., for a module-level skip/conditional assertions) to avoid dead code.
| from django import VERSION as django_version |
Codecov Report❌ Patch coverage is
🚀 New features to boost your workflow:
|
This PR adds support for Django 5.0+ choice override types (dictionaries and callables) in EnumField