Skip to content

Commit

Permalink
fix: fix joining strings when they are promises
Browse files Browse the repository at this point in the history
  • Loading branch information
bellini666 committed Jun 21, 2023
1 parent 031dbd5 commit 2bab774
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 9 deletions.
34 changes: 27 additions & 7 deletions django_choices_field/fields.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,29 @@
import functools
import itertools
from typing import ClassVar, Dict, Optional, Type
from typing import Callable, ClassVar, Dict, Optional, Sequence, Type, cast

from django.core.exceptions import ValidationError
from django.db import models

from .types import IntegerChoicesFlag


def _get_flag_description(descs: Sequence[str]) -> str:
return "|".join(str(desc) for desc in descs)


try:
from django.utils.functional import Promise, lazy
except ImportError: # pragma: nocover
Promise = None
_get_flag_description_lazy = None
else:
_get_flag_description_lazy = cast(
Callable[[Sequence[str]], str],
lazy(_get_flag_description, str),
)


class TextChoicesField(models.CharField):
description: ClassVar[str] = "TextChoices"
default_error_messages: ClassVar[Dict[str, str]] = {
Expand Down Expand Up @@ -122,12 +138,16 @@ def __init__(
kwargs["choices"] = default_choices[:]
for i in range(1, len(default_choices)):
for combination in itertools.combinations(default_choices, i + 1):
kwargs["choices"].append(
(
functools.reduce(lambda a, b: a | b[0], combination, 0),
"|".join(c[1] for c in combination),
),
)
value = functools.reduce(lambda a, b: a | b[0], combination, 0)

descs = [c[1] for c in combination]
if Promise is not None and any(isinstance(desc, Promise) for desc in descs):
assert _get_flag_description_lazy is not None
desc = _get_flag_description_lazy(descs)
else:
desc = _get_flag_description(descs)

kwargs["choices"].append((value, desc))

super().__init__(verbose_name=verbose_name, name=name, **kwargs)

Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "django-choices-field"
version = "2.2.0"
version = "2.2.1"
description = "Django field that set/get django's new TextChoices/IntegerChoices enum."
authors = ["Thiago Bellini Ribeiro <[email protected]>"]
license = "MIT"
Expand Down
14 changes: 14 additions & 0 deletions tests/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import sys

from django.db import models
from django.utils.translation import gettext_lazy as _

from django_choices_field import IntegerChoicesField, TextChoicesField
from django_choices_field.fields import IntegerChoicesFlagField
Expand All @@ -22,6 +23,11 @@ class IntegerFlagEnum(IntegerChoicesFlag):
IF_BAR = enum.auto() if sys.version_info >= (3, 11) else 2, "IF Bar Description"
IF_BIN = enum.auto() if sys.version_info >= (3, 11) else 4, "IF Bin Description"

class IntegerFlagEnumTranslated(IntegerChoicesFlag):
IF_FOO = enum.auto() if sys.version_info >= (3, 11) else 1, _("IF Foo Description")
IF_BAR = enum.auto() if sys.version_info >= (3, 11) else 2, _("IF Bar Description")
IF_BIN = enum.auto() if sys.version_info >= (3, 11) else 4, _("IF Bin Description")

objects = models.Manager["MyModel"]()

c_field = TextChoicesField(
Expand All @@ -48,3 +54,11 @@ class IntegerFlagEnum(IntegerChoicesFlag):
choices_enum=IntegerFlagEnum,
null=True,
)
ift_field = IntegerChoicesFlagField(
choices_enum=IntegerFlagEnumTranslated,
default=IntegerFlagEnumTranslated.IF_FOO,
)
ift_field_nullable = IntegerChoicesFlagField(
choices_enum=IntegerFlagEnumTranslated,
null=True,
)
5 changes: 4 additions & 1 deletion tests/test_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@ def test_field_choices_integer(fname: str):
]


@pytest.mark.parametrize("fname", ["if_field", "if_field_nullable"])
@pytest.mark.parametrize(
"fname",
["if_field", "if_field_nullable", "ift_field", "ift_field_nullable"],
)
def test_field_choices_integer_flags(fname: str):
f = MyModel._meta.get_field(fname)
assert f.choices == [
Expand Down

0 comments on commit 2bab774

Please sign in to comment.