Skip to main content

CLI Options

CLI Options in this project are named parameters passed to commands, typically prefixed with dashes (e.g., --name or -n). They are implemented using a two-layer system: a metadata layer for definition and a core execution layer that integrates with Click.

Defining Options

Options are defined using the typer.Option() function, which returns an OptionInfo object. While options can be defined as default values in function signatures, the recommended modern approach in this codebase is using Annotated.

import typer
from typing import Annotated

app = typer.Typer()

@app.command()
def main(
name: Annotated[str, typer.Option(help="The person to greet")] = "World",
lastname: Annotated[str, typer.Option(prompt=True)] = "Doe"
):
print(f"Hello {name} {lastname}")

When a parameter is defined with typer.Option(), it is treated as a named CLI option. If no explicit name is provided (e.g., "--name"), Typer automatically generates one based on the function parameter name.

The Metadata Layer: OptionInfo and ParameterInfo

The configuration of an option is first captured in typer.models.OptionInfo. This class acts as a data container that stores all the settings provided to typer.Option().

ParameterInfo

OptionInfo inherits from ParameterInfo, which contains metadata shared between both Options and Arguments. This includes:

  • Default Values: default and default_factory for dynamic defaults.
  • Validation: Constraints like min, max, clamp for numbers, and exists, file_okay, dir_okay for paths.
  • Environment Variables: envvar allows the option to pull its value from the environment.
  • Help Metadata: help, hidden, and rich_help_panel.

OptionInfo

OptionInfo adds option-specific metadata found in typer/models.py:

  • Prompts: prompt, confirmation_prompt, and hide_input.
  • Counters: count for incrementing integer flags (e.g., -vvv).
  • Auto-env: allow_from_autoenv for automatic environment variable mapping.

The Execution Layer: TyperOption

During command registration in typer/main.py, OptionInfo is converted into a typer.core.TyperOption. This class inherits from click.core.Option and provides the actual logic for CLI interaction.

TyperOption overrides several Click methods to provide enhanced functionality:

  • get_help_record(): Customizes how the option appears in the help text. It specifically handles Typer's unique boolean flag support where only names for False values might be provided.
  • _get_default_string(): A Typer-specific override to format how default values are displayed in help menus, ensuring consistency with Rich formatting.
  • Rich Integration: The rich_help_panel attribute allows grouping options into distinct sections in the help output when Rich is enabled.

Key Features and Behaviors

Prompts and Confirmation

Typer supports interactive prompts if an option is missing. This is configured via OptionInfo and executed by TyperOption.

@app.command()
def delete(
project: Annotated[str, typer.Option(prompt=True, confirmation_prompt=True)]
):
# User will be prompted to enter the project name twice
print(f"Deleting project {project}")

Automatic Flag Detection

In this codebase, boolean parameters are automatically treated as flags. The TyperOption class handles the generation of secondary options (like --no-force for a --force flag).

Note: The is_flag and flag_value parameters in OptionInfo are deprecated. Typer relies on the bool type hint to determine if an option should behave as a flag.

Hidden Options and Help Panels

Options can be excluded from the help text using hidden=True. For complex CLIs, rich_help_panel can be used to organize options into logical groups.

@app.command()
def sync(
config: Annotated[str, typer.Option(rich_help_panel="Config and Setup")] = "base.yaml",
verbose: Annotated[bool, typer.Option(rich_help_panel="Output Settings")] = False,
internal_id: Annotated[str, typer.Option(hidden=True)] = "secret-123"
):
...

Validation Constraints

Because OptionInfo inherits from ParameterInfo, options support a wide range of validations defined in typer/models.py:

ConstraintDescription
min / maxNumeric range validation for int or float.
existsEnsures a Path exists on the filesystem.
formatsA list of valid datetime formats for parsing.
case_sensitiveControls case sensitivity for Enum choices.

These constraints are passed down to the underlying Click types during the conversion from OptionInfo to TyperOption.