Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/python_introspect/annotation_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ def enum_input_values(annotation: object) -> tuple[str, ...]:

choices = declared_annotation_choices(annotation)
if choices is not None:
return tuple(choices.label(choice) for choice in choices.choices())
return tuple(label for label, _ in choices.labelled_choices())
enum_type = declared_enum_type(annotation)
if enum_type is None:
return ()
Expand Down
25 changes: 21 additions & 4 deletions src/python_introspect/choices.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,30 @@ def label(self, choice: object) -> str:

return str(choice)

def labelled_choices(self) -> tuple[tuple[str, object], ...]:
"""Return each label with its value in one enumeration of the choice set."""
return tuple((self.label(choice), choice) for choice in self.choices())

def choice_for_label(self, label: str) -> object:
"""Decode one display label back to its admissible value."""

for choice in self.choices():
if self.label(choice) == label:
options = self.labelled_choices()
for name, choice in options:
if name == label:
return choice
raise ValueError(f"{label!r} is not one of {[self.label(c) for c in self.choices()]}.")
raise ValueError(f"{label!r} is not one of {[name for name, _ in options]}.")

class LabelledChoices(AnnotationChoices):
"""Choices whose source already supplies labels and values together."""

@abstractmethod
def labelled_choices(self) -> tuple[tuple[str, object], ...]:
"""Return the source's ordered label/value pairs."""

def choices(self) -> tuple[object, ...]:
return tuple(value for _, value in self.labelled_choices())

def label(self, choice: object) -> str:
return next(label for label, value in self.labelled_choices() if value == choice)


def declared_annotation_choices(annotation: object) -> AnnotationChoices | None:
Expand Down
2 changes: 1 addition & 1 deletion src/python_introspect/validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ def _(metadata: AnnotationChoices, value: object, path: str) -> None:
if item not in choices:
raise AnnotationValidationError(
f"{path} must hold values from "
f"{[metadata.label(choice) for choice in choices]}; got {item!r}."
f"{[label for label, _ in metadata.labelled_choices()]}; got {item!r}."
)


Expand Down
Loading