Skip to content

Commit

Permalink
adjust tests, add hashing test
Browse files Browse the repository at this point in the history
  • Loading branch information
bckohan committed Sep 6, 2024
1 parent b855066 commit da12416
Show file tree
Hide file tree
Showing 7 changed files with 51 additions and 64 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,9 @@ Many packages aim to ease usage of Python enumerations as model fields. Most wer

class Permissions(IntFlag):

READ = 0**2
WRITE = 1**2
EXECUTE = 2**3
READ = 1**2
WRITE = 2**2
EXECUTE = 3**2


class FlagExample(models.Model):
Expand Down
8 changes: 6 additions & 2 deletions django_enum/choices.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,10 @@
from django.db.models import IntegerChoices as DjangoIntegerChoices
from django.db.models import TextChoices as DjangoTextChoices
from django.db.models import enums as model_enums
from enum_properties import DecomposeMixin, EnumPropertiesMeta, SymmetricMixin

from django_enum.utils import choices, names

from enum_properties import DecomposeMixin, EnumPropertiesMeta, SymmetricMixin

ChoicesType = (
model_enums.ChoicesType
if django_version[0:2] >= (5, 0)
Expand Down Expand Up @@ -49,6 +48,7 @@ def choices(self):
"""
return super().choices or choices(self, override=True)


class DjangoSymmetricMixin(SymmetricMixin):
"""
An enumeration mixin that makes Django's Choices type label field
Expand All @@ -57,6 +57,7 @@ class DjangoSymmetricMixin(SymmetricMixin):

_symmetric_builtins_ = ["name", "label"]


class TextChoices(
DjangoSymmetricMixin, DjangoTextChoices, metaclass=DjangoEnumPropertiesMeta
):
Expand All @@ -70,6 +71,7 @@ def __hash__(self):

label: str


class IntegerChoices(
DjangoSymmetricMixin, DjangoIntegerChoices, metaclass=DjangoEnumPropertiesMeta
):
Expand All @@ -83,6 +85,7 @@ def __hash__(self):

label: str


class FloatChoices(
DjangoSymmetricMixin, float, Choices, metaclass=DjangoEnumPropertiesMeta
):
Expand All @@ -99,6 +102,7 @@ def __str__(self):

label: str


# mult inheritance type hint bug
class FlagChoices( # type: ignore
DecomposeMixin,
Expand Down
3 changes: 3 additions & 0 deletions django_enum/drf.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
with_typehint,
)


class ClassLookupDict:
"""
A dict-like object that looks up values using the MRO of a class or
Expand Down Expand Up @@ -65,6 +66,7 @@ def __getitem__(self, key: Any) -> Optional[Any]:
return self.mapping.get(cls, None)
return None


class EnumField(ChoiceField):
"""
A djangorestframework serializer field for Enumeration types. If
Expand Down Expand Up @@ -165,6 +167,7 @@ def to_representation(self, value: Any) -> Any:
"""
return getattr(value, "value", value)


class EnumFieldMixin(with_typehint(ModelSerializer)): # type: ignore
"""
A mixin for ModelSerializers that adds auto-magic support for
Expand Down
3 changes: 1 addition & 2 deletions django_enum/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,11 @@
from typing import Tuple, Type

from django.db.models import Field as ModelField
from django_filters import Filter, TypedChoiceFilter, filterset

from django_enum.forms import EnumChoiceField
from django_enum.utils import choices

from django_filters import Filter, TypedChoiceFilter, filterset


class EnumFilter(TypedChoiceFilter):
"""
Expand Down
6 changes: 3 additions & 3 deletions tests/examples/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,9 @@ class IntEnum(models.IntegerChoices):

class Permissions(IntFlag):

READ = 0**2
WRITE = 1**2
EXECUTE = 2**3
READ = 1**2
WRITE = 2**2
EXECUTE = 3**2

# this is equivalent to:
# CharField(max_length=2, choices=TextEnum.choices, null=True, blank=True)
Expand Down
68 changes: 14 additions & 54 deletions tests/test_choices.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import pytest
from importlib.util import find_spec
from tests.utils import EnumTypeMixin, IGNORE_ORA_01843
from django.test import TestCase
from django.db import connection
Expand Down Expand Up @@ -726,67 +727,26 @@ def test_clean(self):
self.assertTrue("text" in ve.message_dict)
self.assertTrue("extern" in ve.message_dict)

def do_rest_framework_missing(self):
@pytest.mark.skipif(
find_spec("rest_framework") is not None, reason="rest_framework is installed"
)
def test_rest_framework_missing(self):
with self.assertRaises(ImportError):
from django_enum.drf import EnumField

def test_rest_framework_missing(self):
import sys
from importlib import reload
from unittest.mock import patch

if "rest_framework.fields" in sys.modules:
with patch.dict(sys.modules, {"rest_framework.fields": None}):
reload(sys.modules["django_enum.drf"])
self.do_rest_framework_missing()
reload(sys.modules["django_enum.drf"])
else:
self.do_rest_framework_missing() # pragma: no cover

def do_django_filters_missing(self):

@pytest.mark.skipif(
find_spec("django_filters") is not None, reason="django-filter is installed"
)
def test_django_filters_missing(self):
with self.assertRaises(ImportError):
from django_enum.filters import EnumFilter


def test_django_filters_missing(self):
import sys
from importlib import reload
from unittest.mock import patch

if "django_filters" in sys.modules:
with patch.dict(sys.modules, {"django_filters": None}):
reload(sys.modules["django_enum.filters"])
self.do_django_filters_missing()
reload(sys.modules["django_enum.filters"])
else:
self.do_django_filters_missing() # pragma: no cover

def do_enum_properties_missing(self):

@pytest.mark.skipif(
find_spec("enum_properties") is not None, reason="enum-properties is installed"
)
def test_enum_properties_missing(self):
with self.assertRaises(ImportError):
from django_enum.choices import (
DjangoEnumPropertiesMeta,
DjangoSymmetricMixin,
FloatChoices,
IntegerChoices,
TextChoices,
)
from django_enum.choices import TextChoices

self.do_test_integer_choices()
self.do_test_text_choices()

def test_enum_properties_missing(self):
import sys
from importlib import reload
from unittest.mock import patch

if "enum_properties" in sys.modules:
with patch.dict(sys.modules, {"enum_properties": None}):
from django_enum import choices

reload(sys.modules["django_enum.choices"])
self.do_enum_properties_missing()
reload(sys.modules["django_enum.choices"])
else:
self.do_enum_properties_missing() # pragma: no cover
21 changes: 21 additions & 0 deletions tests/test_choices_ep.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
pytest.importorskip("enum_properties")

from tests.test_choices import TestChoices as BaseTestChoices
from django_enum.choices import FlagChoices
from tests.enum_prop.models import EnumTester
from datetime import date, datetime, time, timedelta
from decimal import Decimal
Expand Down Expand Up @@ -129,6 +130,26 @@ def test_coerce_to_primitive_error(self):
tester.refresh_from_db()
self.assertEqual(tester.no_coerce, 32767)

def test_flag_choice_hashable(self):
class HashableFlagChoice(FlagChoices):
READ = 1**2
WRITE = 2**2
EXECUTE = 3**2

self.assertEqual(hash(HashableFlagChoice.READ), hash(1**2))
self.assertEqual(hash(HashableFlagChoice.WRITE), hash(2**2))
self.assertEqual(hash(HashableFlagChoice.EXECUTE), hash(3**2))

test_dict = {
HashableFlagChoice.READ: "read",
HashableFlagChoice.WRITE: "write",
HashableFlagChoice.EXECUTE: "execute",
}

self.assertEqual(test_dict[HashableFlagChoice.READ], "read")
self.assertEqual(test_dict[HashableFlagChoice.WRITE], "write")
self.assertEqual(test_dict[HashableFlagChoice.EXECUTE], "execute")


# we do this to avoid the base class tests from being collected and re-run in this module
BaseTestChoices = None

0 comments on commit da12416

Please sign in to comment.