|
14 | 14 | # stdlib imports |
15 | 15 | import numbers |
16 | 16 | import re |
| 17 | +from enum import StrEnum |
17 | 18 | from typing import Any |
18 | 19 |
|
19 | 20 | import zope.interface.common.idatetime |
|
50 | 51 | from zope.schema.interfaces import IFromUnicode |
51 | 52 | from zope.schema.interfaces import InvalidValue |
52 | 53 |
|
53 | | -from nti.schema import MessageFactory as _ |
54 | | -from nti.schema.interfaces import BeforeDictAssignedEvent |
55 | | -from nti.schema.interfaces import BeforeObjectAssignedEvent |
56 | | -from nti.schema.interfaces import BeforeSchemaFieldAssignedEvent |
57 | | -from nti.schema.interfaces import BeforeSequenceAssignedEvent |
58 | | -from nti.schema.interfaces import BeforeSetAssignedEvent |
59 | | -from nti.schema.interfaces import BeforeTextAssignedEvent |
60 | | -from nti.schema.interfaces import BeforeTextLineAssignedEvent |
61 | | -from nti.schema.interfaces import IFromObject |
62 | | -from nti.schema.interfaces import IListOrTuple |
63 | | -from nti.schema.interfaces import IVariant |
64 | | -from nti.schema.interfaces import VariantValidationError |
| 54 | +from . import MessageFactory as _ |
| 55 | +from .interfaces import BeforeDictAssignedEvent |
| 56 | +from .interfaces import BeforeObjectAssignedEvent |
| 57 | +from .interfaces import BeforeSchemaFieldAssignedEvent |
| 58 | +from .interfaces import BeforeSequenceAssignedEvent |
| 59 | +from .interfaces import BeforeSetAssignedEvent |
| 60 | +from .interfaces import BeforeTextAssignedEvent |
| 61 | +from .interfaces import BeforeTextLineAssignedEvent |
| 62 | +from .interfaces import IFromObject |
| 63 | +from .interfaces import IListOrTuple |
| 64 | +from .interfaces import IVariant |
| 65 | +from .interfaces import IStrEnumChoice |
| 66 | +from .interfaces import VariantValidationError |
65 | 67 |
|
66 | 68 | __docformat__ = "restructuredtext en" |
67 | 69 |
|
@@ -154,10 +156,10 @@ def set(self, context, value): # pylint:disable=redefined-builtin |
154 | 156 | cls.set = set |
155 | 157 |
|
156 | 158 | def __with_set(eventfactory=BeforeSchemaFieldAssignedEvent): |
157 | | - def X(cls): |
| 159 | + def attach_set(cls): |
158 | 160 | __make_set(cls, eventfactory) |
159 | 161 | return cls |
160 | | - return X |
| 162 | + return attach_set |
161 | 163 |
|
162 | 164 | def _fixup_Object_field(field, early_error=False): |
163 | 165 | # TODO: Refactor and simplify. |
@@ -585,9 +587,9 @@ def __init__(self, sch, min_length=0, max_length=None, **kwargs): |
585 | 587 | # But to work with the superclass, we have to pass it as a keyword arg. |
586 | 588 | # it's weird. |
587 | 589 | super().__init__(schema=sch, |
588 | | - min_length=min_length, |
589 | | - max_length=max_length, |
590 | | - **kwargs) |
| 590 | + min_length=min_length, |
| 591 | + max_length=max_length, |
| 592 | + **kwargs) |
591 | 593 |
|
592 | 594 | class Int(FieldValidationMixin, schema.Int): |
593 | 595 |
|
@@ -617,6 +619,38 @@ class Number(FieldValidationMixin, schema.Float): |
617 | 619 | class ValidChoice(FieldValidationMixin, schema.Choice): |
618 | 620 | pass |
619 | 621 |
|
| 622 | +@interface.implementer(IStrEnumChoice) |
| 623 | +class StrEnumChoice(ValidChoice): |
| 624 | + """ |
| 625 | + A Choice field that takes its values from |
| 626 | + a :class:`~StrEnum`. |
| 627 | +
|
| 628 | + .. versionadded:: NEXT |
| 629 | + """ |
| 630 | + |
| 631 | + def __init__(self, enum: type[StrEnum], **kwargs) -> None: |
| 632 | + if 'values' in kwargs or 'source' in kwargs or 'vocabulary' in kwargs: |
| 633 | + raise TypeError('Illegal keyword; values come from the enum') |
| 634 | + super().__init__( |
| 635 | + values=list(e.value for e in enum), |
| 636 | + **kwargs |
| 637 | + ) |
| 638 | + self.__enum = enum |
| 639 | + |
| 640 | + @property |
| 641 | + def enum(self): |
| 642 | + return self.__enum |
| 643 | + |
| 644 | + def fromUnicode(self, value): |
| 645 | + # First validate the value is a member of the values |
| 646 | + # list we provided (the enum members), raising |
| 647 | + # the correct error if not. |
| 648 | + value = super().fromUnicode(value) |
| 649 | + # Then, return the actual enum member. |
| 650 | + # Subscripting the class expects the |
| 651 | + # attribute name; calling it expects the value. |
| 652 | + return self.__enum(value) |
| 653 | + |
620 | 654 | @__with_set() |
621 | 655 | class ValidBytesLine(FieldValidationMixin, schema.BytesLine): |
622 | 656 | pass |
|
0 commit comments