Skip to content

NumberΒΆ

You can define numeric validations with max and min values for int and float CLI parameters:

import typer
from typing_extensions import Annotated


def main(
    id: Annotated[int, typer.Argument(min=0, max=1000)],
    age: Annotated[int, typer.Option(min=18)] = 20,
    score: Annotated[float, typer.Option(max=100)] = 0,
):
    print(f"ID is {id}")
    print(f"--age is {age}")
    print(f"--score is {score}")


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

Tip

Prefer to use the Annotated version if possible.

import typer


def main(
    id: int = typer.Argument(..., min=0, max=1000),
    age: int = typer.Option(20, min=18),
    score: float = typer.Option(0, max=100),
):
    print(f"ID is {id}")
    print(f"--age is {age}")
    print(f"--score is {score}")


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

CLI arguments and CLI options can both use these validations.

You can specify min, max or both.

Check it:

fast β†’python main.py --help
Usage: main.py [OPTIONS] ID

Arguments:
ID [required]

Options:
--age INTEGER RANGE [default: 20]
--score FLOAT RANGE [default: 0]
--help Show this message and exit.

python main.py 5 --age 20 --score 90
ID is 5
--age is 20
--score is 90.0

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

Error: Invalid value for 'ID': 1002 is not in the range 0<=x<=1000.

python main.py 5 --age 15
Usage: main.py [OPTIONS] ID
Try "main.py --help" for help.

Error: Invalid value for '--age': 15 is not in the range x>=18.

python main.py 5 --age 20 --score 100.5
Usage: main.py [OPTIONS] ID
Try "main.py --help" for help.

Error: Invalid value for '--score': 100.5 is not in the range x<=100.

python main.py 5 --age 20 --score -5
ID is 5
--age is 20
--score is -5.0

restart ↻

Clamping numbersΒΆ

You might want to, instead of showing an error, use the closest minimum or maximum valid values.

You can do it with the clamp parameter:

import typer
from typing_extensions import Annotated


def main(
    id: Annotated[int, typer.Argument(min=0, max=1000)],
    rank: Annotated[int, typer.Option(max=10, clamp=True)] = 0,
    score: Annotated[float, typer.Option(min=0, max=100, clamp=True)] = 0,
):
    print(f"ID is {id}")
    print(f"--rank is {rank}")
    print(f"--score is {score}")


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

Tip

Prefer to use the Annotated version if possible.

import typer


def main(
    id: int = typer.Argument(..., min=0, max=1000),
    rank: int = typer.Option(0, max=10, clamp=True),
    score: float = typer.Option(0, min=0, max=100, clamp=True),
):
    print(f"ID is {id}")
    print(f"--rank is {rank}")
    print(f"--score is {score}")


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

And then, when you pass data that is out of the valid range, it will be "clamped", the closest valid value will be used:

fast β†’python main.py 1002
Usage: main.py [OPTIONS] ID
Try "main.py --help" for help.

Error: Invalid value for 'ID': 1002 is not in the range 0<=x<=1000.

python main.py 5 --rank 11 --score -5
ID is 5
--rank is 10
--score is 0

restart ↻

Counter CLI optionsΒΆ

You can make a CLI option work as a counter with the counter parameter:

import typer
from typing_extensions import Annotated


def main(verbose: Annotated[int, typer.Option("--verbose", "-v", count=True)] = 0):
    print(f"Verbose level is {verbose}")


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

Tip

Prefer to use the Annotated version if possible.

import typer


def main(verbose: int = typer.Option(0, "--verbose", "-v", count=True)):
    print(f"Verbose level is {verbose}")


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

It means that the CLI option will be like a boolean flag, e.g. --verbose.

And the value you receive in the function will be the amount of times that --verbose was added:

fast β†’python main.py
Verbose level is 0

python main.py --verbose
Verbose level is 1

python main.py --verbose --verbose --verbose
Verbose level is 3

python main.py -v
Verbose level is 1

python main.py -v -v -v
Verbose level is 3

python main.py -vvv
Verbose level is 3

restart ↻
Was this page helpful?