What's supported ================ For minimum-boilerplate CLIs, :mod:`tyro` aims to maximize support of Python's standard :mod:`typing` features. Inputs can be annotated with: - Basic types like :class:`int`, :class:`str`, :class:`float`, :class:`bool`, :class:`pathlib.Path`, :data:`None`. - :class:`datetime.date`, :class:`datetime.datetime`, and :class:`datetime.time`. - Container types like :class:`list`, :class:`dict`, :class:`tuple`, and :class:`set`. - Union types, like ``X | Y``, :py:data:`typing.Union`, and :py:data:`typing.Optional`. - :py:data:`typing.Literal` and :class:`enum.Enum`. - Type aliases, for example using Python 3.12's `PEP 695 `_ `type` statement. - Generics, such as those annotated with :py:class:`typing.TypeVar` or 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: - :func:`dataclasses.dataclass`. - ``attrs``, ``pydantic``, ``ml_collections``, ``msgspec``, and ``flax.linen`` models. - :py:class:`typing.NamedTuple`. - :py:class:`typing.TypedDict`, including with flags like ``total=`` and associated annotations like :py:data:`typing.Required`, :py:data:`typing.NotRequired`, and :py:data:`typing.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: .. code-block:: python 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].method2`` cannot be distinguished from ``MyClass.method1`` / ``MyClass.method2`` at runtime. For some of these cases, a :ref:`custom constructor ` can be defined as a workaround.