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.argswill be empty unless you explicitly set"allow_extra_args": Truein thecontext_settingsof 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 receiveNone.