.. Comment: this file is automatically generated by `update_example_docs.py`. It should not be modified manually. .. _example-category-hierarchical_structures: Hierarchical Structures ================= In these examples, we show how :func:`tyro.cli` can be used to instantiate hierarchical structures. This can enable modular, reusable, and composable CLI interfaces. .. _example-01_nesting: Nested Dataclasses ------------------ Structures (typically :py:func:`dataclasses.dataclass`) can be nested to build hierarchical configuration objects. This helps with modularity and grouping in larger projects. .. code-block:: python :linenos: # 01_nesting.py import dataclasses import tyro @dataclasses.dataclass class OptimizerConfig: learning_rate: float = 3e-4 weight_decay: float = 1e-2 @dataclasses.dataclass class Config: # Optimizer options. opt: OptimizerConfig # Random seed. seed: int = 0 if __name__ == "__main__": config = tyro.cli(Config) print(dataclasses.asdict(config)) .. raw:: html
$ python ./01_nesting.py --help usage: 01_nesting.py [-h] [--seed INT] [--opt.learning-rate FLOAT] [--opt.weight-decay FLOAT] ╭─ options ─────────────────────────────────────────╮ │ -h, --help show this help message and exit │ │ --seed INT Random seed. (default: 0) │ ╰───────────────────────────────────────────────────╯ ╭─ opt options ─────────────────────────────────────╮ │ Optimizer options. │ │ ─────────────────────────────────── │ │ --opt.learning-rate FLOAT │ │ (default: 0.0003) │ │ --opt.weight-decay FLOAT │ │ (default: 0.01) │ ╰───────────────────────────────────────────────────╯.. raw:: html
$ python ./01_nesting.py --opt.learning-rate 1e-3
{'opt': {'learning_rate': 0.001, 'weight_decay': 0.01}, 'seed': 0}
.. raw:: html
$ python ./01_nesting.py --seed 4
{'opt': {'learning_rate': 0.0003, 'weight_decay': 0.01}, 'seed': 4}
.. _example-02_nesting_in_func:
Structures as Function Arguments
--------------------------------
Structures can be used as input to functions.
.. code-block:: python
:linenos:
# 02_nesting_in_func.py
import dataclasses
import pathlib
import tyro
@dataclasses.dataclass
class OptimizerConfig:
learning_rate: float = 3e-4
weight_decay: float = 1e-2
@dataclasses.dataclass
class Config:
# Optimizer options.
optimizer: OptimizerConfig
# Random seed.
seed: int = 0
def train(
out_dir: pathlib.Path,
config: Config,
) -> None:
"""Train a model.
Args:
out_dir: Where to save logs and checkpoints.
config: Experiment configuration.
"""
print(f"Saving to: {out_dir}")
print(f"Config: {config}")
if __name__ == "__main__":
tyro.cli(train)
.. raw:: html
$ python ./02_nesting_in_func.py --help usage: 02_nesting_in_func.py [-h] [OPTIONS] Train a model. ╭─ options ──────────────────────────────────────────────────────────────╮ │ -h, --help show this help message and exit │ │ --out-dir PATH Where to save logs and checkpoints. (required) │ ╰────────────────────────────────────────────────────────────────────────╯ ╭─ config options ───────────────────────────────────────────────────────╮ │ Experiment configuration. │ │ ───────────────────────────────────────────────── │ │ --config.seed INT Random seed. (default: 0) │ ╰────────────────────────────────────────────────────────────────────────╯ ╭─ config.optimizer options ─────────────────────────────────────────────╮ │ Optimizer options. │ │ ───────────────────────────────────────────────── │ │ --config.optimizer.learning-rate FLOAT │ │ (default: 0.0003) │ │ --config.optimizer.weight-decay FLOAT │ │ (default: 0.01) │ ╰────────────────────────────────────────────────────────────────────────╯.. raw:: html
$ python ./02_nesting_in_func.py --out-dir /tmp/test1
Saving to: /tmp/test1
Config: Config(optimizer=OptimizerConfig(learning_rate=0.0003, weight_decay=0.01), seed=0)
.. raw:: html
$ python ./02_nesting_in_func.py --out-dir /tmp/test2 --config.seed 4
Saving to: /tmp/test2
Config: Config(optimizer=OptimizerConfig(learning_rate=0.0003, weight_decay=0.01), seed=4)
.. _example-03_nesting_containers:
Nesting in Containers
---------------------
Structures can be nested inside of standard containers.
.. warning::
When placing structures inside of containers like lists or tuples, the
length of the container must be inferrable from the annotation or default
value.
.. code-block:: python
:linenos:
# 03_nesting_containers.py
import dataclasses
import tyro
@dataclasses.dataclass
class RGB:
r: int
g: int
b: int
@dataclasses.dataclass
class Args:
color_tuple: tuple[RGB, RGB]
color_dict: dict[str, RGB] = dataclasses.field(
# We can't use mutable values as defaults directly.
default_factory=lambda: {
"red": RGB(255, 0, 0),
"green": RGB(0, 255, 0),
"blue": RGB(0, 0, 255),
}
)
if __name__ == "__main__":
args = tyro.cli(Args)
print(args)
.. raw:: html
$ python ./03_nesting_containers.py --help usage: 03_nesting_containers.py [-h] [OPTIONS] ╭─ options ───────────────────────────────────────────────╮ │ -h, --help show this help message and exit │ ╰─────────────────────────────────────────────────────────╯ ╭─ color-tuple.0 options ─────────────────────────────────╮ │ --color-tuple.0.r INT (required) │ │ --color-tuple.0.g INT (required) │ │ --color-tuple.0.b INT (required) │ ╰─────────────────────────────────────────────────────────╯ ╭─ color-tuple.1 options ─────────────────────────────────╮ │ --color-tuple.1.r INT (required) │ │ --color-tuple.1.g INT (required) │ │ --color-tuple.1.b INT (required) │ ╰─────────────────────────────────────────────────────────╯ ╭─ color-dict.red options ────────────────────────────────╮ │ --color-dict.red.r INT (default: 255) │ │ --color-dict.red.g INT (default: 0) │ │ --color-dict.red.b INT (default: 0) │ ╰─────────────────────────────────────────────────────────╯ ╭─ color-dict.green options ──────────────────────────────╮ │ --color-dict.green.r INT │ │ (default: 0) │ │ --color-dict.green.g INT │ │ (default: 255) │ │ --color-dict.green.b INT │ │ (default: 0) │ ╰─────────────────────────────────────────────────────────╯ ╭─ color-dict.blue options ───────────────────────────────╮ │ --color-dict.blue.r INT │ │ (default: 0) │ │ --color-dict.blue.g INT │ │ (default: 0) │ │ --color-dict.blue.b INT │ │ (default: 255) │ ╰─────────────────────────────────────────────────────────╯.. _example-04_dictionaries: Dictionaries and TypedDict -------------------------- Dictionary inputs can be specified using either a standard ``dict[K, V]`` annotation, or a :py:class:`TypedDict` subclass. For configuring :py:class:`TypedDict`, we also support :code:`total={True/False}`, :py:data:`typing.Required`, and :py:data:`typing.NotRequired`. See the `Python docs
$ python ./04_dictionaries.py --help usage: 04_dictionaries.py [-h] [OPTIONS] ╭─ options ──────────────────────────────────────────────────────────────────╮ │ -h, --help show this help message and exit │ ╰────────────────────────────────────────────────────────────────────────────╯ ╭─ typed-dict-a options ─────────────────────────────────────────────────────╮ │ --typed-dict-a.learning-rate FLOAT │ │ (unset by default) │ │ --typed-dict-a.betas FLOAT FLOAT │ │ (unset by default) │ ╰────────────────────────────────────────────────────────────────────────────╯ ╭─ typed-dict-b options ─────────────────────────────────────────────────────╮ │ --typed-dict-b.learning-rate FLOAT │ │ NotRequired[] specifies that a particular key doesn't │ │ need to exist. (unset by default) │ │ --typed-dict-b.betas FLOAT FLOAT │ │ (required) │ ╰────────────────────────────────────────────────────────────────────────────╯ ╭─ standard-dict options ────────────────────────────────────────────────────╮ │ --standard-dict.learning-rate FLOAT │ │ (default: 0.0003) │ │ --standard-dict.beta1 FLOAT │ │ (default: 0.9) │ │ --standard-dict.beta2 FLOAT │ │ (default: 0.999) │ ╰────────────────────────────────────────────────────────────────────────────╯.. raw:: html
$ python ./04_dictionaries.py --typed-dict-a.learning-rate 3e-4 --typed-dict-b.betas 0.9 0.999
Typed dict A: {'learning_rate': 0.0003}
Typed dict B: {'betas': (0.9, 0.999)}
Standard dict: {'learning_rate': 0.0003, 'beta1': 0.9, 'beta2': 0.999}
.. raw:: html
$ python ./04_dictionaries.py --typed-dict-b.betas 0.9 0.999
Typed dict A: {}
Typed dict B: {'betas': (0.9, 0.999)}
Standard dict: {'learning_rate': 0.0003, 'beta1': 0.9, 'beta2': 0.999}
.. _example-05_tuples:
Tuples and NamedTuple
---------------------
Example using :func:`tyro.cli()` to instantiate tuple types. :py:class:`tuple`,
:py:data:`typing.Tuple`, and :py:class:`typing.NamedTuple` are all supported.
.. code-block:: python
:linenos:
# 05_tuples.py
from typing import NamedTuple
import tyro
# Named tuples are interpreted as nested structures.
class Color(NamedTuple):
r: int
g: int
b: int
class TupleType(NamedTuple):
"""Description.
This should show up in the helptext!"""
# Tuple types can contain raw values.
color: tuple[int, int, int] = (255, 0, 0)
# Tuple types can contain nested structures.
two_colors: tuple[Color, Color] = (Color(255, 0, 0), Color(0, 255, 0))
if __name__ == "__main__":
x = tyro.cli(TupleType)
assert isinstance(x, tuple)
print(x)
.. raw:: html
$ python ./05_tuples.py --help usage: 05_tuples.py [-h] [OPTIONS] Description. This should show up in the helptext! ╭─ options ──────────────────────────────────────────────────────────────────╮ │ -h, --help show this help message and exit │ │ --color INT INT INT Tuple types can contain raw values. (default: 255 │ │ 0 0) │ ╰────────────────────────────────────────────────────────────────────────────╯ ╭─ two-colors.0 options ─────────────────────────────────────────────────────╮ │ --two-colors.0.r INT (default: 255) │ │ --two-colors.0.g INT (default: 0) │ │ --two-colors.0.b INT (default: 0) │ ╰────────────────────────────────────────────────────────────────────────────╯ ╭─ two-colors.1 options ─────────────────────────────────────────────────────╮ │ --two-colors.1.r INT (default: 0) │ │ --two-colors.1.g INT (default: 255) │ │ --two-colors.1.b INT (default: 0) │ ╰────────────────────────────────────────────────────────────────────────────╯.. raw:: html
$ python ./05_tuples.py --color 127 127 127
TupleType(color=(127, 127, 127), two_colors=(Color(r=255, g=0, b=0), Color(r=0, g=255, b=0)))
.. raw:: html
$ python ./05_tuples.py --two-colors.1.r 127 --two-colors.1.g 0 --two-colors.1.b 0
TupleType(color=(255, 0, 0), two_colors=(Color(r=255, g=0, b=0), Color(r=127, g=0, b=0)))
.. _example-06_pydantic:
Pydantic Integration
--------------------
In addition to standard dataclasses, :func:`tyro.cli()` also supports
`Pydantic $ python ./06_pydantic.py --help usage: 06_pydantic.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 (required) │ │ --field2 INT An integer field. (default: 3) │ ╰─────────────────────────────────────────────────────╯.. raw:: html
$ python ./06_pydantic.py --field1 hello
field1='hello' field2=3
.. raw:: html
$ python ./06_pydantic.py --field1 hello --field2 5
field1='hello' field2=5
.. _example-07_attrs:
Attrs Integration
-----------------
In addition to standard dataclasses, :func:`tyro.cli()` also supports
`attrs $ python ./07_attrs.py --help usage: 07_attrs.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 required integer field. (default: 5) │ ╰────────────────────────────────────────────────────────────╯.. raw:: html
$ python ./07_attrs.py --field1 hello
Args(field1='hello', field2=5)
.. raw:: html
$ python ./07_attrs.py --field1 hello --field2 5
Args(field1='hello', field2=5)