-
-
Notifications
You must be signed in to change notification settings - Fork 672
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[FEATURE] Define choices via dictionary instead of enum #241
Comments
Thanks for the code example! I tried it, but I get an error. Thoughts? min.py: import typer
from enum import Enum
from typing import Dict
class A:
pass
a = A()
networks: Dict[str, A] = {"A": a}
NetworkEnum = Enum(
"NetworkEnum",
names=[(name, network) for name, network in networks.items()],
module=__name__,
)
app = typer.Typer()
@app.command()
def main(network: NetworkEnum):
the_network = networks[network.value]
print(the_network)
if __name__ == "__main__":
app()
Here's a workaround: import typer
from enum import Enum
from typing import Dict
class A:
pass
a = A()
networks: Dict[str, A] = {"A": a}
NetworkEnum = Enum(
"NetworkEnum",
names=[(name, name) for name in networks.keys()],
module=__name__,
)
app = typer.Typer()
@app.command()
def main(network: NetworkEnum):
the_network = networks[network.value]
print(the_network)
if __name__ == "__main__":
app() which results in
|
Right, my apologies, this must have been a typo! The point is basically that, while the existing option to map a string (= user input) to an enum member is nice, it doesn't cover the other classic kind of mapping: dictionaries, i.e. mapping (string) dictionary keys to dictionary values. This is particularly useful when the dictionary is dynamic and cannot be rewritten as an enum (at least not easily – this is what I meant to illustrate with the code example you fixed). |
I feel like this is an extension of the more basic functionality which is the option to specify choices from a list. Of course you can generate an enum but I feel like this is conflicting with the whole point of typer which is to make defining CLIs clean and simple. Similar to the examples provided, we could have: import typing
import typer
value_options = ['hello', 'world']
def main(value: typing.Annotated[str, typer.Argument(choices=value_options)]):
print(value)
if __name__ == "__main__":
typer.run(main) instead of the current solution import enum
import typer
value_options = ['hello', 'world']
ValueEnum = enum.Enum('ValueEnum', {
f'value_{index}': value
for index, value in enumerate(value_options)
})
def main(value: ValueEnum):
print(value.value)
if __name__ == "__main__":
typer.run(main) I think a big benefit here is that you can correctly type-annotate the value. Related again to this would be support for import typing
import typer
def main(value: typing.Literal['hello', 'world']):
print(value.value)
if __name__ == "__main__":
typer.run(main) |
Imho, the point of using import enum
import typer
class ValueEnum(enum.Enum):
HELLO = "hello"
WORLD = "world"
def main(value: ValueEnum) -> None:
print(value.value)
# What if I have typo here like `ValueEnum.HELLOW`?
# It will be caught either by Python itself or static analysis tools.
if value is ValueEnum.HELLO: ...
if __name__ == "__main__":
typer.run(main) |
@jfcherng That's why I think supporting |
@jfcherng I agree with @inkychris. Static analysis is not possible here, anyway, because the whole point is to generate the choices dynamically:
|
Is there any updated guidance for doing this now? |
I have a (dynamic) dictionary mapping strings (names) to more complicated objects. I want to define a Typer argument (or option) that allows the user to choose one of those objects by providing the corresponding name.
The solution I would like
Pseudo-code:
Basically, I would like to tell Typer to use the dictionary's string keys as the possible values the user can choose from on the command line and then map them to the corresponding NeuralNetwork object when invoking
main()
.Alternatives I've considered
Since Typer currently doesn't support Union types (let alone dynamically created ones), the only alternative with proper type checking and auto-completion that I've found is the following:
While this works, it requires boilerplate code and is much less readable.
The text was updated successfully, but these errors were encountered: