Funktionierender Prototyp des Serious Games zur Vermittlung von Wissen zu Software-Engineering-Arbeitsmodellen.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

enums.py 2.7KB

1 year ago
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. import enum
  2. from types import DynamicClassAttribute
  3. from django.utils.functional import Promise
  4. __all__ = ["Choices", "IntegerChoices", "TextChoices"]
  5. class ChoicesMeta(enum.EnumMeta):
  6. """A metaclass for creating a enum choices."""
  7. def __new__(metacls, classname, bases, classdict, **kwds):
  8. labels = []
  9. for key in classdict._member_names:
  10. value = classdict[key]
  11. if (
  12. isinstance(value, (list, tuple))
  13. and len(value) > 1
  14. and isinstance(value[-1], (Promise, str))
  15. ):
  16. *value, label = value
  17. value = tuple(value)
  18. else:
  19. label = key.replace("_", " ").title()
  20. labels.append(label)
  21. # Use dict.__setitem__() to suppress defenses against double
  22. # assignment in enum's classdict.
  23. dict.__setitem__(classdict, key, value)
  24. cls = super().__new__(metacls, classname, bases, classdict, **kwds)
  25. for member, label in zip(cls.__members__.values(), labels):
  26. member._label_ = label
  27. return enum.unique(cls)
  28. def __contains__(cls, member):
  29. if not isinstance(member, enum.Enum):
  30. # Allow non-enums to match against member values.
  31. return any(x.value == member for x in cls)
  32. return super().__contains__(member)
  33. @property
  34. def names(cls):
  35. empty = ["__empty__"] if hasattr(cls, "__empty__") else []
  36. return empty + [member.name for member in cls]
  37. @property
  38. def choices(cls):
  39. empty = [(None, cls.__empty__)] if hasattr(cls, "__empty__") else []
  40. return empty + [(member.value, member.label) for member in cls]
  41. @property
  42. def labels(cls):
  43. return [label for _, label in cls.choices]
  44. @property
  45. def values(cls):
  46. return [value for value, _ in cls.choices]
  47. class Choices(enum.Enum, metaclass=ChoicesMeta):
  48. """Class for creating enumerated choices."""
  49. @DynamicClassAttribute
  50. def label(self):
  51. return self._label_
  52. @property
  53. def do_not_call_in_templates(self):
  54. return True
  55. def __str__(self):
  56. """
  57. Use value when cast to str, so that Choices set as model instance
  58. attributes are rendered as expected in templates and similar contexts.
  59. """
  60. return str(self.value)
  61. # A similar format was proposed for Python 3.10.
  62. def __repr__(self):
  63. return f"{self.__class__.__qualname__}.{self._name_}"
  64. class IntegerChoices(int, Choices):
  65. """Class for creating enumerated integer choices."""
  66. pass
  67. class TextChoices(str, Choices):
  68. """Class for creating enumerated string choices."""
  69. def _generate_next_value_(name, start, count, last_values):
  70. return name