Skip to content

Commit

Permalink
Merge pull request #673 from awesto/releases/0.11.x
Browse files Browse the repository at this point in the history
Releases/0.11.x
  • Loading branch information
jrief committed Oct 25, 2017
2 parents 4273487 + b4dca07 commit e4087d9
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 13 deletions.
60 changes: 59 additions & 1 deletion example/tests/test_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@
import decimal

from django.contrib.auth import get_user_model
from django.core.exceptions import ValidationError
from django.db import models
from django.test import TestCase

from shop.models.fields import JSONField
from shop.models.fields import JSONField, ChoiceEnum, ChoiceEnumField

from myshop.models import Cart, CartItem, Customer
from myshop.models.manufacturer import Manufacturer
Expand Down Expand Up @@ -50,3 +51,60 @@ def test_json_field_create(self):
"""Test saving a JSON object in our JSONField"""
extra = {'product_code': 'foo'}
self.assertEqual(self.sample.extra, extra)


class MyChoices(ChoiceEnum):
A = 0
B = 1


class EnumTest(TestCase):
def test_enum(self):
choice_a = MyChoices.A
self.assertIsInstance(choice_a, MyChoices)
self.assertEqual(MyChoices.B.name, 'B')
self.assertEqual(MyChoices.B.value, 1)
choice_b = MyChoices('B')
self.assertEqual(str(choice_b), 'MyChoices.B')
self.assertEqual(MyChoices.default(), MyChoices.A)
self.assertListEqual(MyChoices.choices(), [(0, 'MyChoices.A'), (1, 'MyChoices.B')])


class EnumFieldTests(TestCase):
def test_to_python(self):
f = ChoiceEnumField(enum_type=MyChoices)
self.assertEqual(f.to_python(0), MyChoices.A)
self.assertEqual(f.to_python('A'), MyChoices.A)
self.assertEqual(f.to_python(1), MyChoices.B)
with self.assertRaises(ValueError):
f.to_python(None)
with self.assertRaises(ValueError):
f.to_python(3)

def test_deconstruct(self):
f = ChoiceEnumField(enum_type=MyChoices)
name, path, args_, kwargs_ = f.deconstruct()
self.assertIsNone(name)
self.assertEqual(path, 'shop.models.fields.ChoiceEnumField')
self.assertListEqual(args_, [])
self.assertDictEqual(kwargs_, {})

def test_from_db_value(self):
f = ChoiceEnumField(enum_type=MyChoices)
self.assertEqual(f.from_db_value(0, None, None, None), MyChoices.A)
self.assertEqual(f.from_db_value(1, None, None, None), MyChoices.B)
self.assertEqual(f.from_db_value(2, None, None, None), 2)

def test_get_prep_value(self):
f = ChoiceEnumField(enum_type=MyChoices)
self.assertEqual(f.get_prep_value(MyChoices.A), 0)
self.assertEqual(f.get_prep_value(MyChoices.B), 1)
with self.assertRaises(ValueError):
f.get_prep_value('X')

def test_value_to_string(self):
f = ChoiceEnumField(enum_type=MyChoices)
self.assertEqual(f.value_to_string(MyChoices.A), 'A')
self.assertEqual(f.value_to_string(MyChoices.B), 'B')
with self.assertRaises(ValueError):
f.value_to_string(0)
19 changes: 7 additions & 12 deletions shop/models/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,6 @@ def deconstruct(self):


class ChoiceEnumMeta(enum.EnumMeta):
def __new__(cls, name, bases, attrs):
new_class = super(ChoiceEnumMeta, cls).__new__(cls, name, bases, attrs)
values = [p.value for p in new_class.__members__.values()]
if len(values) > len(set(values)):
msg = "Duplicate values found in class '{}'".format(name)
raise ValueError(msg)
return new_class

def __call__(cls, value, *args, **kwargs):
if isinstance(value, string_types):
try:
Expand Down Expand Up @@ -74,7 +66,7 @@ class ChoiceEnumField(models.PositiveSmallIntegerField):
description = _("Customer recognition state")

def __init__(self, *args, **kwargs):
self.enum_type = kwargs.pop('enum_type', ChoiceEnum)
self.enum_type = kwargs.pop('enum_type', ChoiceEnum) # fallback is required form migrations
if not issubclass(self.enum_type, ChoiceEnum):
raise ValueError("enum_type must be a subclass of `ChoiceEnum`.")
kwargs.update(choices=self.enum_type.choices())
Expand All @@ -100,11 +92,14 @@ def from_db_value(self, value, expression, connection, context):
def get_prep_value(self, state):
if isinstance(state, self.enum_type):
return state.value
return state
if isinstance(state, int):
return state
raise ValueError("Value must be of type {}".format(self.enum_type))

def to_python(self, state):
return self.enum_type(state)

def value_to_string(self, obj):
value = self.value_from_object(obj)
return value.name
if not isinstance(obj, self.enum_type):
raise ValueError("Value must be of type {}".format(self.enum_type))
return obj.name

0 comments on commit e4087d9

Please sign in to comment.