Using typer.prompt with choices from Enum doesn't display choices #1332
-
First Check
Commit to Help
Example Codeimport typer
from enum import Enum
class ChoiceEnum(Enum):
option_one = "opt1"
option_two = "opt2"
option_three = "opt3"
app = typer.Typer()
@app.command()
def subcommand(argument_option: ChoiceEnum = typer.Option(ChoiceEnum.option_two.value,
prompt="argument option",
show_choices=True)):
prompt_option: ChoiceEnum = typer.prompt("prompt option",
ChoiceEnum.option_three.value,
show_choices=True)
print(f"Argument choice: {argument_option}")
print(f"Prompt choice: {prompt_option}")
if __name__ == "__main__":
app()
# The result of running the above script results in the following output:
#
# > argument option (opt1, opt2, opt3) [opt2]:
# > prompt option [opt3]:
# > Argument choice: ChoiceEnum.option_two
# > Prompt choice: opt3 DescriptionUsing the Am I doing something wrong here? Is there some other way I should be doing the prompt in order for it to display the choices as is done with the argument choices? Also, why are the return values different (the prompt gives me the string "opt3", while the argument returns the enum value itself). Operating SystemmacOS Operating System DetailsNo response Typer Version0.6.1 Python VersionPython 3.10.8 Additional ContextNo response |
Beta Was this translation helpful? Give feedback.
Replies: 6 comments
-
Managed to figure out that I needed to add |
Beta Was this translation helpful? Give feedback.
-
Managed to find a workaround for this by not using an enum and instead use the
Still think that the |
Beta Was this translation helpful? Give feedback.
-
I solved the issue by creating a new class IntEnumChoice(click.Choice):
def __init__(self, enum_type: EnumType, case_sensitive: bool = True) -> None:
choices = [f"{value.value}: {value.name}" for value in enum_type]
super().__init__(choices, case_sensitive)
self._enum_type = enum_type
def convert(self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"]) -> t.Any:
try:
return self._enum_type(int(value))
except ValueError:
choices_str = ", ".join(map(repr, self.choices))
self.fail(
ngettext(
"{value!r} is not {choice}.",
"{value!r} is not one of {choices}.",
len(self.choices),
).format(value=value, choice=choices_str, choices=choices_str),
param,
ctx,
) You can easily adapt it for string |
Beta Was this translation helpful? Give feedback.
-
I'm looking for a parser.add_argument('move', choices=['rock', 'paper', 'scissors']) It would be great to have a similar feature in the core of |
Beta Was this translation helpful? Give feedback.
-
You might be interested in using the questionary library. To integrate it with click/typer, you can use click-prompt. Typer support requires writing a mixin for from enum import StrEnum, auto
from typing import Annotated
import click
import click_prompt
import typer.core
class Command(typer.core.TyperCommand):
def __call__(self, *args, **kwargs) -> None:
for p in self.params:
if isinstance(p, click.Option) and isinstance(p.type, click.Choice):
p.__class__ = click_prompt.ChoiceOption
super().__call__(*args, **kwargs)
# begin main logic
main = Typer()
class Framework(StrEnum):
django = auto()
flask = auto()
fastapi = auto()
pyramid = auto()
sanic = auto()
# set command class to Command mixin
@main.command(cls=Command)
def run(*, framework: Annotated[Framework, typer.Option(prompt="Please choose a framework")] = Framework.fastapi):
print(f"You chose to use the {framework} framework.")
if __name__ == "__main__":
main() |
Beta Was this translation helpful? Give feedback.
-
So, straightforward solution is to pass
I will probably also want to specify import click
import typer
from enum import Enum
class ChoiceEnum(Enum):
option_one = "opt1"
option_two = "opt2"
option_three = "opt3"
app = typer.Typer()
@app.command()
def subcommand():
prompt_option: ChoiceEnum = typer.prompt(
"prompt option",
ChoiceEnum.option_three.value,
type=click.Choice([e.value for e in ChoiceEnum]),
value_proc=ChoiceEnum,
show_choices=True,
)
print(f"Prompt choice: {prompt_option}")
if __name__ == "__main__":
app() Try it:
|
Beta Was this translation helpful? Give feedback.
typer.prompt
is just re-export ofclick.prompt
.And, to show choices it requires
type
parameter passed and it should be instance ofChoice
.https://github.com/pallets/click/blob/81a482fbfdd5a553cf4704f822ade04c3b102fbc/src/click/termui.py#L69
So, straightforward solution is to pass
type
parameter as follows:I will probably also want to specify
value_proc=ChoiceEnum
to convert the value fromstr
toChoiceEnum
.