:py:mod:`tyro.extras`
=====================
.. py:module:: tyro.extras
.. autoapi-nested-parse::
The :mod:`tyro.extras` submodule contains helpers that complement :func:`tyro.cli()`.
.. warning::
Compared to the core interface, APIs here are more likely to be changed or deprecated.
Package Contents
----------------
.. py:function:: get_parser(f: Type[OutT], *, prog: None | str = None, description: None | str = None, default: OutT | tyro._singleton.NonpropagatingMissingType | tyro._singleton.PropagatingMissingType = MISSING_NONPROP, use_underscores: bool = False, console_outputs: bool = True, add_help: bool = True, config: None | Sequence[tyro.conf._markers.Marker] = None, registry: None | tyro.constructors.ConstructorRegistry = None) -> tyro._backends._argparse.ArgumentParser
get_parser(f: Callable[Ellipsis, OutT], *, prog: None | str = None, description: None | str = None, default: OutT | tyro._singleton.NonpropagatingMissingType | tyro._singleton.PropagatingMissingType = MISSING_NONPROP, use_underscores: bool = False, console_outputs: bool = True, add_help: bool = True, config: None | Sequence[tyro.conf._markers.Marker] = None, registry: None | tyro.constructors.ConstructorRegistry = None) -> tyro._backends._argparse.ArgumentParser
Get an :py:class:`argparse.ArgumentParser` object that approximates the CLI generated
by :func:`tyro.cli`. Useful for tools like ``sphinx-argparse``, ``argcomplete``, etc.
.. deprecated:: 1.0.0
This function is deprecated and will be removed in a future version.
.. note::
The returned parser uses argparse-style subparsers, which is less flexible than
tyro's subcommand parser.
For tab completion, we recommend using :func:`tyro.cli`'s built-in
``--tyro-write-completion`` flag.
:param f: The function or type to populate from command-line arguments.
:param prog: The name of the program to display in the help text.
:param description: The description text shown at the top of the help output.
:param default: An instance to use for default values.
:param use_underscores: If True, uses underscores as word delimiters in the help text.
:param console_outputs: If set to False, suppresses parsing errors and help messages.
:param add_help: Add a -h/--help option to the parser. This mirrors the argument from
:py:class:`argparse.ArgumentParser()`.
:param config: A sequence of configuration marker objects from :mod:`tyro.conf`.
:param registry: A :class:`tyro.constructors.ConstructorRegistry` instance containing custom
constructor rules.
.. py:function:: set_accent_color(accent_color: Literal[black, red, green, yellow, blue, magenta, cyan, white, bright_black, bright_red, bright_green, bright_yellow, bright_blue, bright_magenta, bright_cyan, bright_white] | None) -> None
Set an accent color to use in help messages. Experimental.
.. py:function:: overridable_config_cli(configs: Mapping[str, Tuple[str, T]], *, prog: str | None = None, description: str | None = None, args: Sequence[str] | None = None, use_underscores: bool = False, console_outputs: bool = True, add_help: bool = True, config: Sequence[Any] | None = None, sort_subcommands: bool = False, registry: tyro.constructors.ConstructorRegistry | None = None) -> T
Helper function for creating a CLI interface that allows us to choose
between default config objects (typically dataclasses) and override values
within it. Turns off subcommand creation for any union types within the
config object.
This is a lightweight wrapper over :func:`tyro.cli()`, with some default
arguments populated. Also see
:func:`tyro.extras.subcommand_type_from_defaults()`.
Example usage:
.. code-block:: python
import dataclasses
import tyro
@dataclasses.dataclass
class Config:
a: int
b: str
default_configs = {
"small": (
"Small config",
Config(1, "small"),
),
"big": (
"Big config",
Config(100, "big"),
),
}
config = tyro.extras.overridable_config_cli(default_configs)
print(config)
:param configs: A dictionary of config names mapped to a tuple of
(description, config object).
:param prog: The name of the program printed in helptext. Mirrors argument from
`argparse.ArgumentParser()`.
:param description: Description text for the parser, displayed when the --help flag is
passed in. If not specified, the class docstring is used. Mirrors argument from
`argparse.ArgumentParser()`.
:param args: If set, parse arguments from a sequence of strings instead of the
commandline. Mirrors argument from `argparse.ArgumentParser.parse_args()`.
:param use_underscores: If True, use underscores as a word delimiter instead of hyphens.
This primarily impacts helptext; underscores and hyphens are treated equivalently
when parsing happens. We default helptext to hyphens to follow the GNU style guide.
https://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html
:param console_outputs: If set to `False`, parsing errors and help messages will be
suppressed.
:param add_help: Add a -h/--help option to the parser. This mirrors the argument from
`argparse.ArgumentParser()`.
:param config: Sequence of config marker objects, from `tyro.conf`. We include
:class:`tyro.conf.AvoidSubcommands` by default.
:param sort_subcommands: If True, sort the subcommands alphabetically by name.
:param registry: A :class:`tyro.constructors.ConstructorRegistry` instance containing custom
constructor rules.
.. py:function:: subcommand_type_from_defaults(defaults: Mapping[str, T], descriptions: Mapping[str, str] = {}, *, prefix_names: bool = True, sort_subcommands: bool = False) -> Type[T]
Construct a Union type for defining subcommands that choose between defaults.
For example, when ``defaults`` is set to:
.. code-block:: python
{
"small": Config(...),
"big": Config(...),
}
We return:
.. code-block:: python
Union[
Annotated[
Config,
tyro.conf.subcommand("small", default=Config(...))
],
Annotated[
Config,
tyro.conf.subcommand("big", default=Config(...))
]
]
Direct use of :py:data:`typing.Union` and :func:`tyro.conf.subcommand()` should generally be
preferred, but this function can be helpful for succinctness.
.. warning::
The type returned by this function can be safely used as an input to
:func:`tyro.cli()`, but for static analysis when used for annotations we
recommend applying a `TYPE_CHECKING` guard:
.. code-block:: python
from typing import TYPE_CHECKING
if TYPE_CHECKING:
# Static type seen by language servers, type checkers, etc.
SelectableConfig = Config
else:
# Runtime type used by tyro.
SelectableConfig = subcommand_type_from_defaults(...)
:param defaults: A dictionary of default subcommand instances.
:param descriptions: A dictionary conttaining descriptions for helptext.
:param prefix_names: Whether to prefix subcommand names.
:param sort_subcommands: If True, sort the subcommands alphabetically by name.
:returns: A subcommand type, which can be passed to :func:`tyro.cli`.
.. py:function:: literal_type_from_choices(choices: Iterable[T]) -> Type[T]
Generate a :py:data:`typing.Literal` type that constrains values to a set of choices.
Using ``Literal[...]`` directly should generally be preferred, but this function can be
helpful when choices are generated dynamically.
.. warning::
The type returned by this function can be safely used as an input to
:func:`tyro.cli()`, but for static analysis when used for annotations we
recommend applying a `TYPE_CHECKING` guard:
.. code-block:: python
from typing import TYPE_CHECKING
if TYPE_CHECKING:
# Static type seen by language servers, type checkers, etc.
Color = str
else:
# Runtime type used by tyro.
Color = literal_type_from_choices(["red", "green", "blue"])
:param choices: Options to choose from.
:returns: A type that can be passed to :func:`tyro.cli()`.
.. py:function:: from_yaml(cls: Type[DataclassType], stream: Union[str, IO[str], bytes, IO[bytes]]) -> DataclassType
Re-construct a dataclass instance from a yaml-compatible string, which should be
generated from :func:`tyro.extras.to_yaml()`.
.. warning::
**Deprecated.** Serialization functionality is stable but deprecated.
It may be removed in a future version of :code:`tyro`.
As a secondary feature aimed at enabling the use of :func:`tyro.cli` for general
configuration use cases, we also introduce functions for human-readable dataclass
serialization: :func:`tyro.extras.from_yaml` and :func:`tyro.extras.to_yaml` attempt
to strike a balance between flexibility and robustness — in contrast to naively
dumping or loading dataclass instances (via pickle, PyYAML, etc), explicit type
references enable custom tags that are robust against code reorganization and
refactor, while a PyYAML backend enables serialization of arbitrary Python objects.
:param cls: Type to reconstruct.
:param stream: YAML to read from.
:returns: Instantiated dataclass.
.. py:function:: to_yaml(instance: Any) -> str
Serialize a dataclass; returns a yaml-compatible string that can be deserialized
via :func:`tyro.extras.from_yaml()`.
.. warning::
**Deprecated.** Serialization functionality is stable but deprecated.
It may be removed in a future version of :code:`tyro`.
As a secondary feature aimed at enabling the use of :func:`tyro.cli` for general
configuration use cases, we also introduce functions for human-readable dataclass
serialization: :func:`tyro.extras.from_yaml` and :func:`tyro.extras.to_yaml` attempt
to strike a balance between flexibility and robustness — in contrast to naively
dumping or loading dataclass instances (via pickle, PyYAML, etc), explicit type
references enable custom tags that are robust against code reorganization and
refactor, while a PyYAML backend enables serialization of arbitrary Python objects.
:param instance: Dataclass instance to serialize.
:returns: YAML string.
.. py:class:: SubcommandApp
This class provides a decorator-based API for subcommands in
:mod:`tyro`, inspired by `Typer `_ and
`cyclopts `_. Under-the-hood, this is a light wrapper
over :func:`tyro.cli`.
Example:
.. code-block:: python
from tyro.extras import SubcommandApp
app = SubcommandApp()
@app.command
def greet(name: str, loud: bool = False):
'''Greet someone.'''
greeting = f"Hello, {name}!"
if loud:
greeting = greeting.upper()
print(greeting)
@app.command(name="addition", aliases=["sum"])
def add(a: int, b: int):
'''Add two numbers.'''
print(f"{a} + {b} = {a + b}")
if __name__ == "__main__":
app.cli()
Subcommand groups can be nested by registering one
:class:`SubcommandApp` as a subcommand on another:
.. code-block:: python
db = SubcommandApp()
@db.command
def migrate(): ...
@db.command
def seed(): ...
app = SubcommandApp()
app.command(db, name="db") # `mycli db migrate`, `mycli db seed`
To make one subcommand the default when no subcommand is given, pass
``is_default=True``:
.. code-block:: python
@app.command(is_default=True)
def run(name: str = "world"):
print(f"hello {name}")
# `mycli` runs `run("world")`; `mycli --name alice` runs `run("alice")`;
# `mycli run --name alice` also works.
Usage:
.. code-block:: bash
python my_script.py greet Alice
python my_script.py greet Bob --loud
python my_script.py addition 5 3
python my_script.py sum 5 3 # via alias
.. py:method:: command(func: CallableT) -> CallableT
command(func: None = None, *, name: str | None = None, aliases: Sequence[str] | None = None, help: str | None = None, is_default: bool = False) -> Callable[[CallableT], CallableT]
command(func: SubcommandApp, *, name: str | None = None, aliases: Sequence[str] | None = None, help: str | None = None, is_default: bool = False) -> SubcommandApp
Register a function or nested :class:`SubcommandApp` as a subcommand.
This method is inspired by Typer's ``@app.command()`` and cyclopts's
``@app.command()`` decorators.
:param func: The function (or :class:`SubcommandApp` instance) to
register. If ``None``, returns a decorator.
:param name: Name of the subcommand. Defaults to the function's
``__name__``. Required when registering a
:class:`SubcommandApp` (since the app has no name of its own).
:param aliases: Alternative names that resolve to the same subcommand.
For example, ``aliases=["sum"]`` lets users invoke ``add`` as
either ``add`` or ``sum``.
:param help: Override the helptext for this subcommand. If not set, the
function's docstring (or nested app's description) is used.
:param is_default: If ``True``, this subcommand becomes the implicit
choice when the user invokes the CLI without naming a
subcommand. At most one command per :class:`SubcommandApp`
may set this.
.. py:method:: cli(*, prog: str | None = None, description: str | None = None, args: Sequence[str] | None = None, use_underscores: bool = False, console_outputs: bool = True, add_help: bool = True, config: Sequence[Any] | None = None, sort_subcommands: bool = False, registry: tyro.constructors.ConstructorRegistry | None = None) -> Any
Run the command-line interface.
This method creates a CLI using tyro, with all subcommands registered using
:func:`command()`.
:param prog: The name of the program printed in helptext. Mirrors argument from
`argparse.ArgumentParser()`.
:param description: Description text for the parser, displayed when the --help flag is
passed in. If not specified, the class docstring is used. Mirrors argument from
`argparse.ArgumentParser()`.
:param args: If set, parse arguments from a sequence of strings instead of the
commandline. Mirrors argument from `argparse.ArgumentParser.parse_args()`.
:param use_underscores: If True, use underscores as a word delimiter instead of hyphens.
This primarily impacts helptext; underscores and hyphens are treated equivalently
when parsing happens. We default helptext to hyphens to follow the GNU style guide.
https://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html
:param console_outputs: If set to `False`, parsing errors and help messages will be
suppressed.
:param add_help: Add a -h/--help option to the parser. This mirrors the argument from
`argparse.ArgumentParser()`.
:param config: Sequence of config marker objects, from `tyro.conf`.
:param sort_subcommands: If True, sort the subcommands alphabetically by name.
:param registry: A :class:`tyro.constructors.ConstructorRegistry` instance containing custom
constructor rules.
.. py:function:: subcommand_cli_from_dict(subcommands: Dict[str, Callable[Ellipsis, T]], *, prog: str | None = None, description: str | None = None, args: Sequence[str] | None = None, use_underscores: bool = False, console_outputs: bool = True, add_help: bool = True, config: Sequence[tyro.conf._markers.Marker] | None = None, sort_subcommands: bool = False, registry: tyro.constructors.ConstructorRegistry | None = None) -> T
subcommand_cli_from_dict(subcommands: Dict[str, Callable[Ellipsis, Any]], *, prog: str | None = None, description: str | None = None, args: Sequence[str] | None = None, use_underscores: bool = False, console_outputs: bool = True, add_help: bool = True, config: Sequence[tyro.conf._markers.Marker] | None = None, sort_subcommands: bool = False, registry: tyro.constructors.ConstructorRegistry | None = None) -> Any
Generate a subcommand CLI from a dictionary of functions.
For an input like:
.. code-block:: python
tyro.extras.subcommand_cli_from_dict(
{
"checkout": checkout,
"commit": commit,
}
)
This is internally accomplished by generating and calling:
.. code-block:: python
from typing import Annotated, Any, Union
import tyro
tyro.cli(
Union[
Annotated[
Any,
tyro.conf.subcommand(name="checkout", constructor=checkout),
],
Annotated[
Any,
tyro.conf.subcommand(name="commit", constructor=commit),
],
]
)
:param subcommands: Dictionary that maps the subcommand name to function to call.
:param prog: The name of the program printed in helptext. Mirrors argument from
:py:class:`argparse.ArgumentParser`.
:param description: Description text for the parser, displayed when the --help flag is
passed in. If not specified, `f`'s docstring is used. Mirrors argument from
:py:class:`argparse.ArgumentParser`.
:param args: If set, parse arguments from a sequence of strings instead of the
commandline. Mirrors argument from :py:meth:`argparse.ArgumentParser.parse_args()`.
:param use_underscores: If True, use underscores as a word delimiter instead of hyphens.
This primarily impacts helptext; underscores and hyphens are treated equivalently
when parsing happens. We default helptext to hyphens to follow the GNU style guide.
https://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html
:param console_outputs: If set to ``False``, parsing errors and help messages will be
supressed. This can be useful for distributed settings, where :func:`tyro.cli()`
is called from multiple workers but we only want console outputs from the
main one.
:param add_help: Add a -h/--help option to the parser. This mirrors the argument from
:py:class:`argparse.ArgumentParser()`.
:param config: Sequence of config marker objects, from :mod:`tyro.conf`.
:param registry: A :class:`tyro.constructors.ConstructorRegistry` instance containing custom
constructor rules.
.. py:class:: Verbosity
Parsed verbosity counters from ``-v``/``-q`` CLI flags.
Drop into any tyro CLI struct to get standard ``--verbose``/``-v`` and
``--quiet``/``-q`` count flags that map to Python :mod:`logging` levels.
The two flags are mutually exclusive.
Example::
import logging
import tyro
from dataclasses import dataclass, field
from tyro.extras import Verbosity
@dataclass
class Args:
verbosity: Verbosity = Verbosity()
args = tyro.cli(Args)
logging.basicConfig(level=args.verbosity.log_level())
Default level mapping (baseline: ``logging.WARNING``):
.. code-block:: text
(none) → WARNING (30)
-v → INFO (20)
-vv → DEBUG (10)
-q → ERROR (40)
-qq → CRITICAL (50)
Values are clamped to the ``DEBUG``..``CRITICAL`` range.
.. py:attribute:: verbose
:type: typing_extensions.Annotated[tyro.conf.UseCounterAction[int], conf.arg(aliases=['-v'], help='Increase log verbosity.'), _verbosity_mutex]
:value: 0
.. py:attribute:: quiet
:type: typing_extensions.Annotated[tyro.conf.UseCounterAction[int], conf.arg(aliases=['-q'], help='Decrease log verbosity.'), _verbosity_mutex]
:value: 0
.. py:method:: log_level(*, default: int = logging.WARNING) -> int
Compute the effective logging level, clamped to ``DEBUG``..``CRITICAL``.
Formula: ``default + (quiet - verbose) * 10``.
:param default: Baseline logging level. Defaults to ``logging.WARNING``.
:returns: An integer logging level suitable for :func:`logging.basicConfig`.