pythoncommand-line-interfacetyper

How to add flags for Typer commands in Python


I am new to Typer but I cannot really find the info I need in the docs...
I am trying to add flags to my app with typer commands. I would like to have:

myApp command1 --flag1 value1 --flag2 value2

Currently I have a plain command that takes a string:

@app.command(
    name="foo",
    help="bar",
)
def command1(path: str) -> None:  # noqa: D401
    """
    Text

    Args:
        path: my favourite path
    """
    # some code here

Is there any way to adjust the function above so that it takes flags+values as in the first box?


Solution

  • If you are trying to create a typer script with only one command (command1), then you need to take a look at this documentation page, that tells that there is a "gotcha":

    You might have noticed that if you create a single command, (...) Typer is smart enough to create a CLI application with that single function as the main CLI application, not as a command/subcommand:
    Notice that it doesn't show a command main, even though the function name is main.

    But if you add multiple commands, Typer will create one CLI command for each one of them:

    The solution for that is also mentioned later in the docs:

    If you want to create a CLI app with one single command but you still want it to be a command/subcommand you can just add a callback

    In your case, it could be something similar to this (adjust for your specific program logic):

    import typer
    app = typer.Typer()
    
    # I am assuming you need a mandatory 'path' and optionals 'flag1' and 'flag2'      
    @app.command()
    def command1(path: str, flag1: str = 'value1', flag2: str = 'value2'):
        print(f"running on {path} with {flag1} and {flag2}")
    
    # this callback is added as workaround for the "just one command" gotcha
    # you can use it for documenting purposes
    @app.callback()
    def callback():
        """
        Text
        Args:
            path: my favourite path
        """
    
    if __name__ == "__main__":
        app()
    

    Then, it will generate the following --help message:

    ❯ python3 myApp.py --help
    
     Usage: myApp.py [OPTIONS] COMMAND [ARGS]...                    
                                                                    
     Text Args:     path: my favourite path                         
                                                                     
    ╭─ Commands ───────────────────────────────────────────────────╮
    │ command1                                                     │
    ╰──────────────────────────────────────────────────────────────╯
    
    
    ❯ python3 myApp.py command1 --help
    
    Usage: myApp.py command1 [OPTIONS] PATH
    
    ╭─ Arguments ──────────────────────────────────────────────────╮
    │ *    path      TEXT  [default: None] [required]              │
    ╰──────────────────────────────────────────────────────────────╯
    ╭─ Options ────────────────────────────────────────────────────╮
    │ --flag1        TEXT  [default: value1]                       │
    │ --flag2        TEXT  [default: value2]                       │
    │ --help               Show this message and exit.             │
    ╰──────────────────────────────────────────────────────────────╯