Open sapristi opened 4 years ago
I think if this was configurable as an option, this would be great - on the other hand, we have a use-case where we have an Enum set up as
class Preset(str, Enum):
PRESET_FOOBAR = "foo:bar"
PRESET_BAZQUX = "baz:qux"
which then means we can do run --preset foo:bar
in the CLI but reference Preset.PRESET_FOOBAR
in code (which this PR / issue would break)
Do you think there's some way to nicely make the behaviour configurable?
@sapristi +1
One way to make this feature configurable as an option would be to create a dummy NamedEnum
class:
class NamedEnum(Enum):
pass
And to add the behaviour I described only to instances of NamedEnum
.
+1 to this feature!
I often have enums with numerical values, which are not convenient to use and see in the help message. But enum names are ALWAYS understandable.
I guess, this will also fix the problem when using IntEnum
, as now it crashes because it can't join ints because it expects strings. :)
The documentation for Enums - Choices is also slightly confusing in this aspect as the examples use the same words for both enum.name
and enum.value
:
class NeuralNetwork(str, Enum):
simple = "simple"
conv = "conv"
lstm = "lstm"
Ok I finally found a way to have this without changing typer:
class MyEnum(Enum):
choice1 = {"k": "v"}
choice2 = 2
def __init__(self, val):
self.val = val
@property
def value(self):
return self.name
With these re-definition of enum methods, one can use an Enum in typer, and obtained objects have the custom values in the val
attribute:
@app.command()
def test(value: ME):
print("HELLO", value.val)
Edit: not perfect though , as default values need to be passed as x.name
:
@app.command()
def test(value: ME = ME.choice1.name):
print("HELLO", value.val)
@HaiyiMei's workaround from here seems to actually work quite well for this.
import typer
import click
import enum
from typing import Annotated
class Color(enum.IntEnum):
RED = 0xFF0000
GREEN = 0x00FF00
BLUE = 0x0000FF
ColorArgument = typer.Argument(help="Color to set",
click_type=click.Choice(Color._member_names_, case_sensitive=False),
show_default=False)
def main(color_str: Annotated[str, ColorArgument] = Color.BLUE.name):
color = Color[color_str] # This is guaranteed to work because click validates the names
print(f"Set color to 0x{color.value:06x}")
if __name__ == "__main__":
typer.run(main)
This produces a nice help message too:
Usage: scratch.py [OPTIONS] [COLOR_STR]:[RED|GREEN|BLUE]
┌─ Arguments ─────────────────────────────────────────────────────────────────┐
│ color_str [COLOR_STR]:[RED|GREEN|BLUE] Color to set │
└─────────────────────────────────────────────────────────────────────────────┘
┌─ Options ───────────────────────────────────────────────────────────────────┐
│ --help Show this message and exit. │
└─────────────────────────────────────────────────────────────────────────────┘
@HaiyiMei's workaround from here seems to actually work quite well for this.
import typer import click import enum from typing import Annotated class Color(enum.IntEnum): RED = 0xFF0000 GREEN = 0x00FF00 BLUE = 0x0000FF ColorArgument = typer.Argument(help="Color to set", click_type=click.Choice(Color._member_names_, case_sensitive=False), show_default=False) def main(color_str: Annotated[str, ColorArgument] = Color.BLUE.name): color = Color[color_str] # This is guaranteed to work because click validates the names print(f"Set color to 0x{color.value:06x}") if __name__ == "__main__": typer.run(main)
This produces a nice help message too:
Usage: scratch.py [OPTIONS] [COLOR_STR]:[RED|GREEN|BLUE] ┌─ Arguments ─────────────────────────────────────────────────────────────────┐ │ color_str [COLOR_STR]:[RED|GREEN|BLUE] Color to set │ └─────────────────────────────────────────────────────────────────────────────┘ ┌─ Options ───────────────────────────────────────────────────────────────────┐ │ --help Show this message and exit. │ └─────────────────────────────────────────────────────────────────────────────┘
Nicely done @multiplemonomials! Any ideas around how one could do something similar for multiple colors? Ie. a list of colors as input arguments?
Is your feature request related to a problem
I would like to be able to unleash the power of Enum ! The first case I stumbled onto is that of logging, e.g have the following Enum usable in typer:
Instead I have to use this one, and then convert the string to the right value
The solution you would like
I would like typer to interpret the
value.name
as arguments, and providevalue.value
to the called function, so that the following program would work as intended: