Application Callbacks
Application callbacks in this codebase allow you to define logic and parameters that apply to the entire CLI application rather than a specific subcommand. By using the Typer class's callback mechanisms, you can handle global flags like --verbose or perform initialization tasks that must occur before any command executes.
Defining Callbacks
There are two primary ways to define a callback for a Typer application:
- The
@app.callback()decorator: This is the most common method. It allows you to define a function that captures global parameters and contains the logic to be executed. - The
callbackparameter inTyper(): You can pass a function directly to theTyperconstructor.
If both are used, the @app.callback() decorator takes precedence and overrides the function passed to the constructor.
Using the Callback Decorator
The Typer.callback() method (found in typer/main.py) is used as a decorator to register a function as the main entry point for the application's global logic.
import typer
app = typer.Typer()
state = {"verbose": False}
@app.callback()
def main(verbose: bool = False):
"""
Manage users in the awesome CLI app.
"""
if verbose:
print("Will write verbose output")
state["verbose"] = True
@app.command()
def create(username: str):
if state["verbose"]:
print("About to create a user")
print(f"Creating user: {username}")
In this example from docs_src/commands/callback/tutorial001_py310.py, the main function acts as the callback. The verbose parameter becomes a global option for the entire CLI.
Global Options and Execution Order
Parameters defined in the callback function are treated as options for the main program. Because of how the underlying engine parses arguments, these global options must be provided before the subcommand on the command line.
For the example above:
- Correct:
python main.py --verbose create hiro - Incorrect:
python main.py create hiro --verbose(This will fail becausecreatedoes not have a--verboseoption).
Initialization Logic
Callbacks are often used for setup tasks, such as initializing a database connection or loading a configuration file, that should happen regardless of which subcommand is called.
Executing Without Subcommands
By default, a callback only executes if a subcommand is also provided. If you want the callback to run even when the user provides no subcommand, set invoke_without_command=True.
This is configured in the Typer constructor or the @app.callback() decorator:
# From typer/main.py
@app.callback(invoke_without_command=True)
def main():
"""
This logic runs even if no subcommand is called.
"""
print("Initializing system...")
Showing Help by Default
If your application requires a subcommand to be useful, you can set no_args_is_help=True. When a user runs the program without any arguments, Typer will automatically display the help screen instead of executing the callback logic or failing.
# Example configuration in Typer constructor
app = typer.Typer(no_args_is_help=True)
Callback Configuration Options
The Typer.callback() method supports several parameters to control the behavior of the application's entry point:
help: Sets the help text for the main application (displayed when running--help).epilog: Adds text at the very end of the help output.invoke_without_command: Controls if the callback runs when no subcommand is specified.no_args_is_help: Controls if the help screen is shown when no arguments are provided.rich_help_panel: If Rich is installed, organizes the callback's options into a specific panel in the help output.
These settings are stored in a TyperInfo object internally within the Typer instance's registered_callback attribute.