What’s supported¶
For minimum-boilerplate CLIs, tyro aims to maximize support of
Python’s standard typing features.
Inputs can be annotated with:
Union types, like
X | Y,typing.Union, andtyping.Optional.typing.Literalandenum.Enum.Type aliases, for example using Python 3.12’s PEP 695 type statement.
Generics, such as those annotated with
typing.TypeVaror with the type parameter syntax introduced by Python 3.12’s PEP 695.Compositions of the above types, like
tuple[int | str, ...] | None.
Types can also be placed and nested in various structures, such as:
attrs,pydantic,ml_collections,msgspec, andflax.linenmodels.typing.TypedDict, including with flags liketotal=and associated annotations liketyping.Required,typing.NotRequired, andtyping.ReadOnly.
What’s not supported¶
There are some limitations. We currently do not fully support:
Self-referential types. For example,
type RecursiveList[T] = T | list[RecursiveList[T]].Variable-length sequences over nested structures, unless a default is provided. For types like
list[Dataclass], we require a default value to infer length from. The length of the corresponding field cannot be changed from the CLI interface.Type parameters in class and static methods. For example:
class MyClass[T: int | str]: @staticmethod def method1(arg: T) -> T: return arg @classmethod def method2(cls, arg: T) -> T: return arg # The `int` type parameter will be ignored. tyro.cli(MyClass[int].method1) tyro.cli(MyClass[int].method2)
This is because
MyClass[int].method1/MyClass[int].method2cannot be distinguished fromMyClass.method1/MyClass.method2at runtime.
For some of these cases, a custom constructor can be defined as a workaround.