Search code examples
pythoncommand-line-interfacepython-click

How require options for CLI app based on Python and Click


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.


Solution

  • 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()