.. Comment: this file is automatically generated by `update_example_docs.py`. It should not be modified manually. .. _example-category-basics: Basics ====== In these examples, we show basic examples of using :func:`tyro.cli`: functions, dataclasses, supported annotations, and configuration. .. _example-01_functions: Functions --------- In the simplest case, :func:`tyro.cli()` can be used to run a function with arguments populated from the CLI. .. code-block:: python :linenos: # 01_functions.py import tyro def main(field1: str, field2: int = 3) -> None: """Function, whose arguments will be populated from a CLI interface. Args: field1: A string field. field2: A numeric field, with a default value. """ print(field1, field2) if __name__ == "__main__": tyro.cli(main) We can use ``--help`` to show the help message, or ``--field1`` and ``--field2`` to set the arguments: .. raw:: html
$ python ./01_functions.py --help usage: 01_functions.py [-h] --field1 STR [--field2 INT] Function, whose arguments will be populated from a CLI interface. ╭─ options ───────────────────────────────────────────────────────────────╮ │ -h, --help show this help message and exit │ │ --field1 STR A string field. (required) │ │ --field2 INT A numeric field, with a default value. (default: 3) │ ╰─────────────────────────────────────────────────────────────────────────╯.. raw:: html
$ python ./01_functions.py --field1 hello
hello 3
.. raw:: html
$ python ./01_functions.py --field1 hello --field2 10
hello 10
.. _example-02_dataclasses:
Dataclasses
-----------
In addition to functions, :func:`tyro.cli()` can also take dataclasses as input.
.. code-block:: python
:linenos:
# 02_dataclasses.py
from dataclasses import dataclass
from pprint import pprint
import tyro
@dataclass
class Args:
"""Description.
This should show up in the helptext!"""
field1: str
"""A string field."""
field2: int = 3
"""A numeric field, with a default value."""
if __name__ == "__main__":
args = tyro.cli(Args)
pprint(args)
To show the help message, we can use the ``--help`` flag:
.. raw:: html
$ python ./02_dataclasses.py --help usage: 02_dataclasses.py [-h] --field1 STR [--field2 INT] Description. This should show up in the helptext! ╭─ options ───────────────────────────────────────────────────────────────╮ │ -h, --help show this help message and exit │ │ --field1 STR A string field. (required) │ │ --field2 INT A numeric field, with a default value. (default: 3) │ ╰─────────────────────────────────────────────────────────────────────────╯We can override ``field1`` and ``field2``: .. raw:: html
$ python ./02_dataclasses.py --field1 hello
Args(field1='hello', field2=3)
.. raw:: html
$ python ./02_dataclasses.py --field1 hello --field2 5
Args(field1='hello', field2=5)
.. _example-03_multivalue:
Multi-value Arguments
---------------------
Arguments of both fixed and variable lengths can be annotated with standard
Python collection types. For Python 3.7 and 3.8, we can use either ``from
__future__ import annotations`` to support ``list[T]`` and ``tuple[T]``,
or the older :py:class:`typing.List` and :py:data:`typing.Tuple`.
.. code-block:: python
:linenos:
# 03_multivalue.py
import pathlib
from dataclasses import dataclass
from pprint import pprint
import tyro
@dataclass
class Config:
# Example of a variable-length tuple. `list[T]`, `set[T]`,
# `dict[K, V]`, etc are supported as well.
source_paths: tuple[pathlib.Path, ...]
"""This can be multiple!"""
# Fixed-length tuples are also okay.
dimensions: tuple[int, int] = (32, 32)
"""Height and width."""
if __name__ == "__main__":
config = tyro.cli(Config)
pprint(config)
To print help:
.. raw:: html
$ python ./03_multivalue.py --help usage: 03_multivalue.py [-h] --source-paths [PATH [PATH ...]] [--dimensions INT INT] ╭─ options ──────────────────────────────────────────────────╮ │ -h, --help show this help message and exit │ │ --source-paths [PATH [PATH ...]] │ │ This can be multiple! (required) │ │ --dimensions INT INT Height and width. (default: 32 32) │ ╰────────────────────────────────────────────────────────────╯We can override arguments: .. raw:: html
$ python ./03_multivalue.py --source-paths ./data --dimensions 16 16
Config(source_paths=(PosixPath('data'),), dimensions=(16, 16))
.. raw:: html
$ python ./03_multivalue.py --source-paths ./data1 ./data2
Config(source_paths=(PosixPath('data1'), PosixPath('data2')),
dimensions=(32, 32))
.. _example-04_flags:
Booleans and Flags
------------------
Booleans can either be expected to be explicitly passed in, or, if given a default
value, automatically converted to flags.
To turn off conversion, see :class:`tyro.conf.FlagConversionOff`.
.. code-block:: python
:linenos:
# 04_flags.py
from dataclasses import dataclass
from pprint import pprint
import tyro
@dataclass
class Args:
# Boolean. This expects an explicit "True" or "False".
boolean: bool
# Optional boolean. Same as above, but can be omitted.
optional_boolean: bool | None = None
# Pass --flag-a in to set this value to True.
flag_a: bool = False
# Pass --no-flag-b in to set this value to False.
flag_b: bool = True
if __name__ == "__main__":
args = tyro.cli(Args)
pprint(args)
.. raw:: html
$ python ./04_flags.py --help usage: 04_flags.py [-h] [OPTIONS] ╭─ options ────────────────────────────────────────────────────────────────╮ │ -h, --help │ │ show this help message and exit │ │ --boolean {True,False} │ │ Boolean. This expects an explicit "True" or "False". (required) │ │ --optional-boolean {None,True,False} │ │ Optional boolean. Same as above, but can be omitted. (default: None) │ │ --flag-a, --no-flag-a │ │ Pass --flag-a in to set this value to True. (default: False) │ │ --flag-b, --no-flag-b │ │ Pass --no-flag-b in to set this value to False. (default: True) │ ╰──────────────────────────────────────────────────────────────────────────╯.. raw:: html
$ python ./04_flags.py --boolean True
Args(boolean=True, optional_boolean=None, flag_a=False, flag_b=True)
.. raw:: html
$ python ./04_flags.py --boolean False --flag-a
Args(boolean=False, optional_boolean=None, flag_a=True, flag_b=True)
.. raw:: html
$ python ./04_flags.py --boolean False --no-flag-b
Args(boolean=False, optional_boolean=None, flag_a=False, flag_b=False)
.. _example-05_choices:
Choices
-------
:py:data:`typing.Literal[]` can be used to restrict inputs to a fixed set of literal choices.
.. code-block:: python
:linenos:
# 05_choices.py
import dataclasses
from pprint import pprint
from typing import Literal
import tyro
@dataclasses.dataclass
class Args:
# We can use Literal[] to restrict the set of allowable inputs, for example, over
# a set of strings.
string: Literal["red", "green"] = "red"
# Integers also work. (as well as booleans, enums, etc)
number: Literal[0, 1, 2] = 0
if __name__ == "__main__":
args = tyro.cli(Args)
pprint(args)
.. raw:: html
$ python ./05_choices.py --help usage: 05_choices.py [-h] [--string {red,green}] [--number {0,1,2}] ╭─ options ──────────────────────────────────────────────────────────────────╮ │ -h, --help show this help message and exit │ │ --string {red,green} We can use Literal[] to restrict the set of │ │ allowable inputs, for example, over a set of │ │ strings. (default: red) │ │ --number {0,1,2} Integers also work. (as well as booleans, enums, │ │ etc) (default: 0) │ ╰────────────────────────────────────────────────────────────────────────────╯.. raw:: html
$ python ./05_choices.py --string red
Args(string='red', number=0)
.. raw:: html
$ python ./05_choices.py --string blue ╭─ Parsing error ────────────────────────────────────────────────────────╮ │ Argument --string: invalid choice: 'blue' (choose from 'red', 'green') │ │ ────────────────────────────────────────────────────────────────────── │ │ For full helptext, run 05_choices.py --help │ ╰────────────────────────────────────────────────────────────────────────╯.. _example-06_enums: Enums ----- In addition to literals, enums can also be used to provide a fixed set of choices. .. code-block:: python :linenos: # 06_enums.py import enum from dataclasses import dataclass from pprint import pprint import tyro class Color(enum.Enum): RED = enum.auto() BLUE = enum.auto() @dataclass class Config: color: Color = Color.RED """Color argument.""" opacity: float = 0.5 """Opacity argument.""" if __name__ == "__main__": config = tyro.cli(Config) pprint(config) .. raw:: html
$ python ./06_enums.py --help usage: 06_enums.py [-h] [--color {RED,BLUE}] [--opacity FLOAT] ╭─ options ────────────────────────────────────────────────╮ │ -h, --help show this help message and exit │ │ --color {RED,BLUE} Color argument. (default: RED) │ │ --opacity FLOAT Opacity argument. (default: 0.5) │ ╰──────────────────────────────────────────────────────────╯.. raw:: html
$ python ./06_enums.py --color RED
Config(color=<Color.RED: 1>, opacity=0.5)
.. raw:: html
$ python ./06_enums.py --color BLUE --opacity 0.75
Config(color=<Color.BLUE: 2>, opacity=0.75)
.. _example-07_unions:
Unions
------
:code:`X | Y` or :py:data:`typing.Union` can be used to expand inputs to
multiple types.
.. code-block:: python
:linenos:
# 07_unions.py
import dataclasses
import enum
from pprint import pprint
from typing import Literal, Optional
import tyro
class Color(enum.Enum):
RED = enum.auto()
GREEN = enum.auto()
BLUE = enum.auto()
@dataclasses.dataclass(frozen=True)
class Args:
# Unions can be used to specify multiple allowable types.
union_over_types: int | str = 0
string_or_enum: Literal["red", "green"] | Color = "red"
# Unions also work over more complex nested types.
union_over_tuples: tuple[int, int] | tuple[str] = ("1",)
# And can be nested in other types.
tuple_of_string_or_enum: tuple[Literal["red", "green"] | Color, ...] = (
"red",
Color.RED,
)
# Optional[T] is equivalent to `T | None`.
integer: Optional[Literal[0, 1, 2, 3]] = None
if __name__ == "__main__":
args = tyro.cli(Args)
pprint(args)
.. raw:: html
$ python ./07_unions.py --help usage: 07_unions.py [-h] [OPTIONS] ╭─ options ──────────────────────────────────────────────────────────────────╮ │ -h, --help │ │ show this help message and exit │ │ --union-over-types INT|STR │ │ Unions can be used to specify multiple allowable types. (default: 0) │ │ --string-or-enum {red,green,RED,GREEN,BLUE} │ │ Unions can be used to specify multiple allowable types. (default: red) │ │ --union-over-tuples {INT INT}|STR │ │ Unions also work over more complex nested types. (default: 1) │ │ --tuple-of-string-or-enum [{red,green,RED,GREEN,BLUE} │ │ [{red,green,RED,GREEN,BLUE} ...]] │ │ And can be nested in other types. (default: red RED) │ │ --integer {None,0,1,2,3} │ │ Optional[T] is equivalent to `T | None`. (default: None) │ ╰────────────────────────────────────────────────────────────────────────────╯.. raw:: html
$ python ./07_unions.py --union-over-types 3
Args(union_over_types=3,
string_or_enum='red',
union_over_tuples=('1',),
tuple_of_string_or_enum=('red', <Color.RED: 1>),
integer=None)
.. raw:: html
$ python ./07_unions.py --union-over-types three
Args(union_over_types='three',
string_or_enum='red',
union_over_tuples=('1',),
tuple_of_string_or_enum=('red', <Color.RED: 1>),
integer=None)
.. raw:: html
$ python ./07_unions.py --integer None
Args(union_over_types=0,
string_or_enum='red',
union_over_tuples=('1',),
tuple_of_string_or_enum=('red', <Color.RED: 1>),
integer=None)
.. raw:: html
$ python ./07_unions.py --integer 0
Args(union_over_types=0,
string_or_enum='red',
union_over_tuples=('1',),
tuple_of_string_or_enum=('red', <Color.RED: 1>),
integer=0)
.. _example-08_positional:
Positional Arguments
--------------------
Positional-only arguments in functions are converted to positional CLI arguments.
For more general positional arguments, see :class:`tyro.conf.Positional`.
.. code-block:: python
:linenos:
# 08_positional.py
from __future__ import annotations
import pathlib
import tyro
def main(
source: pathlib.Path,
dest: pathlib.Path,
/, # Mark the end of positional arguments.
verbose: bool = False,
) -> None:
"""Command-line interface defined using a function signature. This
docstring is parsed to generate helptext.
Args:
source: Source path.
dest: Destination path.
verbose: Explain what is being done.
"""
print(f"{source=}\n{dest=}\n{verbose=}")
if __name__ == "__main__":
tyro.cli(main)
.. raw:: html
$ python 08_positional.py --help usage: 08_positional.py [-h] [--verbose | --no-verbose] PATH PATH Command-line interface defined using a function signature. This docstring is parsed to generate helptext. ╭─ positional arguments ─────────────────────────────────────────╮ │ PATH Source path. (required) │ │ PATH Destination path. (required) │ ╰────────────────────────────────────────────────────────────────╯ ╭─ options ──────────────────────────────────────────────────────╮ │ -h, --help show this help message and exit │ │ --verbose, --no-verbose │ │ Explain what is being done. (default: False) │ ╰────────────────────────────────────────────────────────────────╯.. raw:: html
$ python 08_positional.py ./a ./b
source=PosixPath('a')
dest=PosixPath('b')
verbose=False
.. raw:: html
$ python 08_positional.py ./test1 ./test2 --verbose
source=PosixPath('test1')
dest=PosixPath('test2')
verbose=True
.. _example-09_conf:
Configuration via typing.Annotated[]
------------------------------------
The :mod:`tyro.conf` module contains utilities that can be used in conjunction
with :py:data:`typing.Annotated` to configure command-line interfaces beyond
what is expressible via static type annotations.
Features here are supported, but generally unnecessary and should be used sparingly.
.. code-block:: python
:linenos:
# 09_conf.py
import dataclasses
from typing_extensions import Annotated
import tyro
@dataclasses.dataclass
class Args:
# A numeric field parsed as a positional argument.
positional: tyro.conf.Positional[int]
# A boolean field with flag conversion turned off.
boolean: tyro.conf.FlagConversionOff[bool] = False
# A numeric field that can't be changed via the CLI.
fixed: tyro.conf.Fixed[int] = 5
# A field with manually overridden properties.
manual: Annotated[
str,
tyro.conf.arg(
name="renamed",
metavar="STRING",
help="A field with manually overridden properties!",
),
] = "Hello"
if __name__ == "__main__":
print(tyro.cli(Args))
.. raw:: html
$ python ./09_conf.py --help usage: 09_conf.py [-h] [OPTIONS] INT ╭─ positional arguments ─────────────────────────────────────────────────────╮ │ INT A numeric field parsed as a positional argument. │ │ (required) │ ╰────────────────────────────────────────────────────────────────────────────╯ ╭─ options ──────────────────────────────────────────────────────────────────╮ │ -h, --help show this help message and exit │ │ --boolean {True,False} A boolean field with flag conversion turned off. │ │ (default: False) │ │ --fixed {fixed} A numeric field that can't be changed via the CLI. │ │ (fixed to: 5) │ │ --renamed STRING A field with manually overridden properties! │ │ (default: Hello) │ ╰────────────────────────────────────────────────────────────────────────────╯.. raw:: html
$ python ./09_conf.py 5 --boolean True
Args(positional=5, boolean=True, fixed=5, manual='Hello')
.. _example-10_aliases:
Argument Aliases
----------------
:func:`tyro.conf.arg()` can be used to attach aliases to arguments.
.. code-block:: python
:linenos:
# 10_aliases.py
from typing import Annotated
import tyro
def checkout(
branch: Annotated[str, tyro.conf.arg(aliases=["-b"])],
) -> None:
"""Check out a branch."""
print(f"{branch=}")
if __name__ == "__main__":
tyro.cli(checkout)
.. raw:: html
$ python ./10_aliases.py --help usage: 10_aliases.py [-h] --branch STR Check out a branch. ╭─ options ───────────────────────────────────────────────╮ │ -h, --help show this help message and exit │ │ --branch STR, -b STR (required) │ ╰─────────────────────────────────────────────────────────╯.. raw:: html
$ python ./10_aliases.py --branch main
branch='main'
.. raw:: html
$ python ./10_aliases.py -b main
branch='main'
.. _example-11_type_aliases_py312:
Type Aliases (3.12+)
--------------------
In Python 3.12, the :code:`type` statement is introduced to create type aliases.
.. code-block:: python
:linenos:
# 11_type_aliases_py312.py
import dataclasses
import tyro
# Lazily-evaluated type alias.
type Field1Type = Inner
@dataclasses.dataclass
class Inner:
a: int
b: str
@dataclasses.dataclass
class Args:
"""Description.
This should show up in the helptext!"""
field1: Field1Type
"""A field."""
field2: int = 3
"""A numeric field, with a default value."""
if __name__ == "__main__":
args = tyro.cli(Args)
print(args)
.. raw:: html
$ python ./11_type_aliases_py312.py --help usage: 11_type_aliases_py312.py [-h] [--field2 INT] --field1.a INT --field1.b STR Description. This should show up in the helptext! ╭─ options ─────────────────────────────────────────────────────────────────╮ │ -h, --help show this help message and exit │ │ --field2 INT A numeric field, with a default value. (default: 3) │ ╰───────────────────────────────────────────────────────────────────────────╯ ╭─ field1 options ──────────────────────────────────────────────────────────╮ │ A field. │ │ ──────────────────────────────── │ │ --field1.a INT (required) │ │ --field1.b STR (required) │ ╰───────────────────────────────────────────────────────────────────────────╯.. _example-12_counters: Counters -------- Repeatable 'counter' arguments can be specified via :data:`tyro.conf.UseCounterAction`. .. code-block:: python :linenos: # 12_counters.py from typing_extensions import Annotated import tyro from tyro.conf import UseCounterAction def main( verbosity: UseCounterAction[int], aliased_verbosity: Annotated[UseCounterAction[int], tyro.conf.arg(aliases=["-v"])], ) -> None: """Example showing how to use counter actions. Args: verbosity: Verbosity level. aliased_verbosity: Same as above, but can also be specified with -v, -vv, -vvv, etc. """ print("Verbosity level:", verbosity) print("Verbosity level (aliased):", aliased_verbosity) if __name__ == "__main__": tyro.cli(main) .. raw:: html
$ python ./12_counters.py --help usage: 12_counters.py [-h] [--verbosity] [--aliased-verbosity] Example showing how to use counter actions. ╭─ options ──────────────────────────────────────────────────────────────────╮ │ -h, --help show this help message and exit │ │ --verbosity Verbosity level. (repeatable) │ │ --aliased-verbosity, -v │ │ Same as above, but can also be specified with -v, -vv, │ │ -vvv, etc. (repeatable) │ ╰────────────────────────────────────────────────────────────────────────────╯.. raw:: html
$ python ./12_counters.py --verbosity
Verbosity level: 1
Verbosity level (aliased): 0
.. raw:: html
$ python ./12_counters.py --verbosity --verbosity
Verbosity level: 2
Verbosity level (aliased): 0
.. raw:: html
$ python ./12_counters.py -vvv
Verbosity level: 0
Verbosity level (aliased): 3
.. _example-13_classes:
Instantiating Classes
---------------------
In addition to functions and dataclasses, we can also generate CLIs from the
constructors of standard Python classes.
.. code-block:: python
:linenos:
# 13_classes.py
import tyro
class Args:
def __init__(
self,
field1: str,
field2: int,
flag: bool = False,
):
"""Arguments.
Args:
field1: A string field.
field2: A numeric field.
flag: A boolean flag.
"""
self.data = [field1, field2, flag]
if __name__ == "__main__":
args = tyro.cli(Args)
print(args.data)
.. raw:: html
$ python ./13_classes.py --help usage: 13_classes.py [-h] --field1 STR --field2 INT [--flag | --no-flag] Arguments. ╭─ options ────────────────────────────────────────────────╮ │ -h, --help show this help message and exit │ │ --field1 STR A string field. (required) │ │ --field2 INT A numeric field. (required) │ │ --flag, --no-flag A boolean flag. (default: False) │ ╰──────────────────────────────────────────────────────────╯.. raw:: html
$ python ./13_classes.py --field1 hello --field2 7
['hello', 7, False]