Skip to content

Enum - Choices

To define a CLI parameter that can take a value from a predefined set of values you can use a standard Python enum.Enum:

from enum import Enum

import typer


class NeuralNetwork(str, Enum):
    simple = "simple"
    conv = "conv"
    lstm = "lstm"


def main(network: NeuralNetwork = NeuralNetwork.simple):
    print(f"Training neural network of type: {network.value}")


if __name__ == "__main__":
    typer.run(main)

Tip

Notice that the function parameter network will be an Enum, not a str.

To get the str value in your function's code use network.value.

Check it:

$ python main.py --help

// Notice the predefined values [simple|conv|lstm]
Usage: main.py [OPTIONS]

Options:
  --network [simple|conv|lstm]  [default: simple]
  --help                        Show this message and exit.

// Try it
$ python main.py --network conv

Training neural network of type: conv

// Invalid value
$ python main.py --network capsule

Usage: main.py [OPTIONS]
Try "main.py --help" for help.

Error: Invalid value for '--network': 'capsule' is not one of 'simple', 'conv', 'lstm'.

// Note that enums are case sensitive by default
$ python main.py --network CONV

Usage: main.py [OPTIONS]
Try "main.py --help" for help.

Error: Invalid value for '--network': 'CONV' is not one of 'simple', 'conv', 'lstm'.

Case insensitive Enum choices

You can make an Enum (choice) CLI parameter be case-insensitive with the case_sensitive parameter:

from enum import Enum

import typer
from typing_extensions import Annotated


class NeuralNetwork(str, Enum):
    simple = "simple"
    conv = "conv"
    lstm = "lstm"


def main(
    network: Annotated[
        NeuralNetwork, typer.Option(case_sensitive=False)
    ] = NeuralNetwork.simple,
):
    print(f"Training neural network of type: {network.value}")


if __name__ == "__main__":
    typer.run(main)

Tip

Prefer to use the Annotated version if possible.

from enum import Enum

import typer


class NeuralNetwork(str, Enum):
    simple = "simple"
    conv = "conv"
    lstm = "lstm"


def main(
    network: NeuralNetwork = typer.Option(NeuralNetwork.simple, case_sensitive=False),
):
    print(f"Training neural network of type: {network.value}")


if __name__ == "__main__":
    typer.run(main)

And then the values of the Enum will be checked no matter if lower case, upper case, or a mix:

// Notice the upper case CONV
$ python main.py --network CONV

Training neural network of type: conv

// A mix also works
$ python main.py --network LsTm

Training neural network of type: lstm

List of Enum values

A CLI parameter can also take a list of Enum values:

from enum import Enum
from typing import List

import typer
from typing_extensions import Annotated


class Food(str, Enum):
    food_1 = "Eggs"
    food_2 = "Bacon"
    food_3 = "Cheese"


def main(groceries: Annotated[List[Food], typer.Option()] = [Food.food_1, Food.food_3]):
    print(f"Buying groceries: {', '.join([f.value for f in groceries])}")


if __name__ == "__main__":
    typer.run(main)

Tip

Prefer to use the Annotated version if possible.

from enum import Enum
from typing import List

import typer


class Food(str, Enum):
    food_1 = "Eggs"
    food_2 = "Bacon"
    food_3 = "Cheese"


def main(groceries: List[Food] = typer.Option([Food.food_1, Food.food_3])):
    print(f"Buying groceries: {', '.join([f.value for f in groceries])}")


if __name__ == "__main__":
    typer.run(main)

This works just like any other parameter value taking a list of things:

$ python main.py --help

// Notice the default values being shown
Usage: main.py [OPTIONS]

Options:
  --groceries [Eggs|Bacon|Cheese]  [default: Eggs, Cheese]
  --help                           Show this message and exit.

// Try it with the default values
$ python main.py

Buying groceries: Eggs, Cheese

// Try it with a single value
$ python main.py --groceries "Eggs"

Buying groceries: Eggs

// Try it with multiple values
$ python main.py --groceries "Eggs" --groceries "Bacon"

Buying groceries: Eggs, Bacon