Typer: Build Great CLIs

repository·master·Indexed 12 days ago

https://github.com/fastapi/typer

A library for building command-line interfaces (CLIs) based on Python type hints. Built on top of Click, Typer provides automatic help generation, shell completion for Bash, Zsh, Fish, and PowerShell, and type safety. It allows developers to create simple CLIs using `typer.run()` or complex applications with multiple subcommands using `typer.Typer()`.

Tokens
53.3K
Snippets
225
Records
269
Agent score
96%

What's inside Typer

  1. How Typer handles shell autocompletion

    master
    Typer provides built-in shell autocompletion for all major shells. This functionality was inspired by click-completion, but Typer now implements its own internal logic to provide improved features, bug fixes, and better support for modern shells, including modern versions of PowerShell on Windows.
  2. Automatic command name formatting

    master

    When you do not explicitly provide a name to @app.command(), Typer follows these rules for generating the CLI command name from the function name:

    1. The function name is used as the base.
    2. Underscores (_) in the function name are automatically replaced with dashes (-).

    Example: def create_user(...) becomes the command create-user.

  3. Configure the target app or function for the `typer` command

    master

    When using typer <PATH_OR_MODULE> run, the command determines which Typer application or function to execute based on a specific priority order. You can override this using CLI options.

    CLI Options:

    • --app: The name of the variable containing the Typer() object.
    • --func: The name of the variable containing a function intended for typer.run().

    Resolution Priority:

    1. An object specified via --app.
    2. A function specified via --func.
    3. A Typer app named app, cli, or main in the target file.
    4. The first Typer app found in the file (regardless of name).
    5. A function named main, cli, or app in the target file.
    6. The first function found in the file (regardless of name).
  4. Understand CLI arguments vs CLI options

    master

    Typer distinguishes between two types of parameters passed to a CLI application:

    CLI Arguments

    • Definition: Parameters passed in a specific sequence.
    • Requirement: By default, they are required.
    • Ordering: The order is critical. The application identifies which value belongs to which parameter based on its position in the command.
    • Usage: If a value contains spaces, wrap it in quotes (e.g., python main.py "John Doe").

    CLI Options

    • Definition: Parameters identified by a specific name, typically prepended with -- (e.g., --size).
    • Requirement: By default, they are optional.
    • Ordering: The order does not matter because the application looks for the specific name/flag.
    • Types: Options can be simple flags (boolean switches that are either present or absent) or can accept values like arguments.
  5. Precedence of command name setting in Typer

    master

    When adding a sub-app to a main application, you can define the command name used in the CLI. There are two ways to set this, with the latter having higher precedence.

    Precedence order (from lowest to highest priority):

    1. Explicitly set in typer.Typer(name="..."): The name string provided during Typer initialization.
    2. Explicitly set in app.add_typer(sub_app, name="..."): The name string provided when adding the sub-app to a parent app. This always wins.
  6. How Typer callbacks work in sub-Typer apps

    master

    When you create a typer.Typer() app, you can define a callback function. This callback always executes and is used to define CLI arguments and options that appear before a command.

    When nesting Typer apps (adding a sub-Typer to a main Typer app), the sub-Typer can have its own callback. This callback handles CLI parameters specific to that sub-command group and can execute extra logic (like printing messages or initializing resources) before the actual command runs.

    import typer
    
    app = typer.Typer()
    
    @app.callback()
    def callback():
        print("Running a users command")
    
    @app.command()
    def create(name: str):
        print(f"Creating user: {name}")
    
    if __name__ == "__main__":
        app()
  7. How `typer.run()` works under the hood

    master

    When you call typer.run(your_function), Typer performs several automated steps to convert your function into a CLI application:

    1. It creates a new typer.Typer() application instance.
    2. It creates a new command using your provided function.
    3. It calls that application instance as if it were a function (e.g., app()).

    Use typer.run() for simple scripts where you only have a single command and don't need extra configuration.

  8. Use File-like objects instead of Path

    master
    While typer.Path is often sufficient for most use cases, Typer provides specialized file types that return a Python file-like object (the same type returned by open()) instead of a pathlib.Path object. This is particularly useful when migrating existing applications that expect file handles or when you want to interact with files using standard file methods like .read() and .write() directly.
  9. Typer design philosophy: The FastAPI of CLIs

    master

    Typer is designed to be the "FastAPI of CLIs." It follows the same design patterns and usage as FastAPI, specifically:

    • Function Parameters for Declarations: Using function parameters to declare CLI arguments and options.
    • Type Annotations: Using standard Python type annotations to declare types, which are used for both data validation and documentation (inspired by Pydantic).
    • Simplicity: Providing a simple way to turn a function into a CLI app using typer.run(some_function).
  10. Understand Typer terminology: Arguments vs Options

    master

    Typer distinguishes between how parameters are handled on the command line:

    • CLI argument: A parameter that depends on a specific order. These are required by default.
    • CLI option: A parameter that depends on a name starting with -- (e.g., --lastname). These are optional by default.
    • CLI parameter: A general term covering both CLI arguments and CLI options.

    In Python code, these correspond to function parameters. A parameter with a default value is an 'optional parameter', while one without a default value is 'required'.

  11. Modify CLI options using typer.Option()

    master

    You can use typer.Option() to define and modify CLI options in a Typer application. It functions similarly to typer.Argument(), but provides additional features specifically for handling command-line options (flags, named parameters, etc.) rather than positional arguments.

    import typer
    
    def main(name: str = typer.Option(...)):
        ...
    
    if __name__ == "__main__":
        typer.run(main)