Skip to main content

Context and Callbacks

To access the underlying Click execution state or metadata about specific parameters, you can inject typer.Context and typer.CallbackParam into your command functions and callbacks using type hints.

Accessing the Execution Context

You can access the current execution state, such as which subcommand was invoked, by declaring a parameter with the type typer.Context.

import typer

app = typer.Typer()

@app.command()
def create(username: str):
print(f"Creating user: {username}")

@app.callback()
def main(ctx: typer.Context):
"""
Manage users in the awesome CLI app.
"""
# Access the subcommand that is about to be executed
print(f"About to execute command: {ctx.invoked_subcommand}")

if __name__ == "__main__":
app()

In this example from docs_src/commands/context/tutorial001_py310.py, the main callback uses ctx.invoked_subcommand to inspect which command the user requested before it runs.

Validating Parameters with Metadata

When writing a callback for a specific Option or Argument, use typer.CallbackParam to access metadata about the parameter (like its name) and typer.Context to check the parsing state.

import typer

app = typer.Typer()

def name_callback(ctx: typer.Context, param: typer.CallbackParam, value: str):
# Avoid running logic during shell completion or help generation
if ctx.resilient_parsing:
return

print(f"Validating param: {param.name}")
if value != "Camila":
raise typer.BadParameter("Only Camila is allowed")
return value

@app.command()
def main(name: str | None = typer.Option(default=None, callback=name_callback)):
print(f"Hello {name}")

if __name__ == "__main__":
app()

As shown in docs_src/options/callback/tutorial004_py310.py, the CallbackParam object provides access to param.name, while ctx.resilient_parsing ensures the validation logic doesn't interfere with internal Click processes like autocompletion.

Handling Extra Arguments

If you need to capture arbitrary arguments that aren't defined as formal parameters, use context_settings to allow extra arguments and access them via ctx.args.

import typer

app = typer.Typer()

@app.command(
context_settings={"allow_extra_args": True, "ignore_unknown_options": True}
)
def main(ctx: typer.Context):
for extra_arg in ctx.args:
print(f"Got extra arg: {extra_arg}")

if __name__ == "__main__":
app()

This pattern from docs_src/commands/context/tutorial004_py310.py requires setting allow_extra_args in the context_settings dictionary passed to the @app.command decorator.

Troubleshooting

  • Logic running during completion: If your callback performs side effects (like database writes or network calls), always check if ctx.resilient_parsing: return. This prevents the logic from executing when Typer/Click is just trying to parse the command line for shell completion.
  • Missing extra arguments: ctx.args will be empty unless you explicitly set "allow_extra_args": True in the context_settings of your command or app.
  • Callback return values: Parameter callbacks must return the value that should be assigned to the parameter. If you don't return the value (or a modified version), the command will receive None.