How require options for CLI app based on Python and Click

Viewed 126

I am building a CLI app with Python and the Click library.

How do I achieve the following use case:

First I only want the subcommand to be followed by an argument no options are required:

$ myapp subcommand argument

This is straight forward.

But how can I write the code that if argument2 is set that also some options are required?

$ myapp subcommand argument2 -o1 abc -o2 def

For example:

no options are required:

$ ./myapp.py install basic

options are required:

$ ./myapp.py install custom -o1 abc -o2 def

Furthermore I do not know how to make choice for arguments, that means that the user must choose between "basic" or "custom". In case he chooses "custom", he needs to add some options.

1 Answers

I have achieved this successfully by making your argument2 be a click.Command. Running through the code below, my main way of interacting with the CLI application is via the cli group. That cli group has another group, install, added as a command. So we have a CLI with nested groups. install has 2 commands, basic and custom, as in your example.

basic takes no parameters, while custom takes 2 required Options.

Calls would look like this:

❯ myapp install custom -o1 arg1 -o2 def
This is a custom install with option1: arg1 and option2: def

❯ myapp install basic
Executing a basic install

You can see the nested group install acts as a command inside the help message:

❯ myapp
Usage: myapp [OPTIONS] COMMAND [ARGS]...

Options:
  --help  Show this message and exit.

Commands:
  install

And if you were to invoke install, this is the help output you'd get.

❯ myapp install
Usage: myapp install [OPTIONS] COMMAND [ARGS]...

Options:
  --help  Show this message and exit.

Commands:
  basic
  custom

This is the code:

import click


@click.group()
def cli():
    pass


@click.group()
def install():
    pass


@install.command()
def basic():
    print('Executing a basic install')


@install.command()
@click.option("-o1", "--option1", required=True)
@click.option("-o2", "--option2", required=True)
def custom(option1, option2):
    print(f'This is a custom install with option1: {option1} and option2: {option2}')


def main():
    cli.add_command(install)
    cli()


if __name__ == '__main__':
    main()
Related