.. Comment: this file is automatically generated by `update_example_docs.py`. It should not be modified manually. .. _example-category-generics: Generics ======== :mod:`tyro`'s understanding of Python's type system includes user-defined parameterized types, which can reduce boilerplate and improve type safety. .. _example-01_generics_py312: Generics (3.12+) ---------------- This example uses syntax introduced in Python 3.12 (`PEP 695 `_). .. note:: If used in conjunction with :code:`from __future__ import annotations`, the updated type parameter syntax requires Python 3.12.4 or newer. For technical details, see `this CPython PR `_. .. code-block:: python :linenos: # 01_generics_py312.py import dataclasses import tyro @dataclasses.dataclass class Point3[ScalarType: (int, float)]: x: ScalarType y: ScalarType z: ScalarType frame_id: str @dataclasses.dataclass class Triangle: a: Point3[float] b: Point3[float] c: Point3[float] @dataclasses.dataclass class Args[ShapeType]: shape: ShapeType if __name__ == "__main__": args = tyro.cli(Args[Triangle]) print(args) .. raw:: html
    $ python ./01_generics_py312.py --help
    usage: ./01_generics_py312.py [-h] [OPTIONS]
    
    ╭─ options ───────────────────────────────────────────────╮
    │ -h, --help              show this help message and exit │
    ╰─────────────────────────────────────────────────────────╯
    ╭─ shape.a options ───────────────────────────────────────╮
    │ --shape.a.x FLOAT       (required)                      │
    │ --shape.a.y FLOAT       (required)                      │
    │ --shape.a.z FLOAT       (required)                      │
    │ --shape.a.frame-id STR  (required)                      │
    ╰─────────────────────────────────────────────────────────╯
    ╭─ shape.b options ───────────────────────────────────────╮
    │ --shape.b.x FLOAT       (required)                      │
    │ --shape.b.y FLOAT       (required)                      │
    │ --shape.b.z FLOAT       (required)                      │
    │ --shape.b.frame-id STR  (required)                      │
    ╰─────────────────────────────────────────────────────────╯
    ╭─ shape.c options ───────────────────────────────────────╮
    │ --shape.c.x FLOAT       (required)                      │
    │ --shape.c.y FLOAT       (required)                      │
    │ --shape.c.z FLOAT       (required)                      │
    │ --shape.c.frame-id STR  (required)                      │
    ╰─────────────────────────────────────────────────────────╯
    
.. _example-02_generics: Generics (Python <3.12) ----------------------- The legacy :py:class:`typing.Generic` and :py:class:`typing.TypeVar` syntax for generic types is also supported. .. code-block:: python :linenos: # 02_generics.py import dataclasses from typing import Generic, TypeVar import tyro ScalarType = TypeVar("ScalarType", int, float) ShapeType = TypeVar("ShapeType") @dataclasses.dataclass class Point3(Generic[ScalarType]): x: ScalarType y: ScalarType z: ScalarType frame_id: str @dataclasses.dataclass class Triangle: a: Point3[float] b: Point3[float] c: Point3[float] @dataclasses.dataclass class Args(Generic[ShapeType]): shape: ShapeType if __name__ == "__main__": args = tyro.cli(Args[Triangle]) print(args) .. raw:: html
    $ python ./02_generics.py --help
    usage: ./02_generics.py [-h] [OPTIONS]
    
    ╭─ options ───────────────────────────────────────────────╮
    │ -h, --help              show this help message and exit │
    ╰─────────────────────────────────────────────────────────╯
    ╭─ shape.a options ───────────────────────────────────────╮
    │ --shape.a.x FLOAT       (required)                      │
    │ --shape.a.y FLOAT       (required)                      │
    │ --shape.a.z FLOAT       (required)                      │
    │ --shape.a.frame-id STR  (required)                      │
    ╰─────────────────────────────────────────────────────────╯
    ╭─ shape.b options ───────────────────────────────────────╮
    │ --shape.b.x FLOAT       (required)                      │
    │ --shape.b.y FLOAT       (required)                      │
    │ --shape.b.z FLOAT       (required)                      │
    │ --shape.b.frame-id STR  (required)                      │
    ╰─────────────────────────────────────────────────────────╯
    ╭─ shape.c options ───────────────────────────────────────╮
    │ --shape.c.x FLOAT       (required)                      │
    │ --shape.c.y FLOAT       (required)                      │
    │ --shape.c.z FLOAT       (required)                      │
    │ --shape.c.frame-id STR  (required)                      │
    ╰─────────────────────────────────────────────────────────╯
    
.. _example-03_generic_subcommands: Generic subcommands ------------------- Just like standard classes, generic classes within unions can be selected between using subcommands. .. code-block:: python :linenos: # 03_generic_subcommands.py import dataclasses from pathlib import Path import tyro @dataclasses.dataclass class Sgd: lr: float = 1e-4 @dataclasses.dataclass class Adam: lr: float = 3e-4 betas: tuple[float, float] = (0.9, 0.999) @dataclasses.dataclass class Experiment[OptimizerT: (Adam, Sgd)]: path: Path opt: OptimizerT if __name__ == "__main__": args = tyro.cli(Experiment[Adam] | Experiment[Sgd]) print(args) .. raw:: html
    $ python ./03_generic_subcommands.py --help
    usage: ./03_generic_subcommands.py [-h] {experiment-adam,experiment-sgd}
    
    ╭─ options ────────────────────────────────────────────╮
    │ -h, --help           show this help message and exit │
    ╰──────────────────────────────────────────────────────╯
    ╭─ subcommands ────────────────────────────────────────╮
    │ (required)                                           │
    │   • experiment-adam                                  │
    │   • experiment-sgd                                   │
    ╰──────────────────────────────────────────────────────╯
    
.. raw:: html
    $ python ./03_generic_subcommands.py experiment-adam --help
    usage: ./03_generic_subcommands.py experiment-adam [-h] --path PATH [--opt.lr FLOAT] [--opt.betas FLOAT FLOAT]
    
    ╭─ options ────────────────────────────────────────────────╮
    │ -h, --help               show this help message and exit │
    │ --path PATH              (required)                      │
    ╰──────────────────────────────────────────────────────────╯
    ╭─ opt options ────────────────────────────────────────────╮
    │ --opt.lr FLOAT           (default: 0.0003)               │
    │ --opt.betas FLOAT FLOAT  (default: 0.9 0.999)            │
    ╰──────────────────────────────────────────────────────────╯
    
.. raw:: html
    $ python ./03_generic_subcommands.py experiment-sgd --help
    usage: ./03_generic_subcommands.py experiment-sgd [-h] --path PATH [--opt.lr FLOAT]
    
    ╭─ options ───────────────────────────────────────╮
    │ -h, --help      show this help message and exit │
    │ --path PATH     (required)                      │
    ╰─────────────────────────────────────────────────╯
    ╭─ opt options ───────────────────────────────────╮
    │ --opt.lr FLOAT  (default: 0.0001)               │
    ╰─────────────────────────────────────────────────╯
    
.. raw:: html
    $ python ./03_generic_subcommands.py experiment-adam --path /tmp --opt.lr 1e-3
    Experiment(path=PosixPath('/tmp'), opt=Adam(lr=0.001, betas=(0.9, 0.999)))