Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Require and option only if a choice is made when using click

When using click I know how to define a multiple choice option. I also know how to set an option as a required one. But, how can I indicate that an option B is required only if the value of option A is foo?

Here's an example:

import click

@click.command()
@click.option('--output',
              type=click.Choice(['stdout', 'file']), default='stdout')
@click.option('--filename', type=click.STRING)
def main(output, filename):
    print("output: " + output)
    if output == 'file':
        if filename is None:
            print("filename must be provided!")
        else:
            print("filename: " + str(filename))

if __name__ == "__main__":
    main()

If the output option is stdout, then filename is not needed. However, if the user chooses output to be file, then the other option filename must be provided. Is this pattern supported by click?

At the beginning of the function I can add something like:

if output == 'file' and filename is None:
    raise ValueError('When output is "file", a filename must be provided')

But I am interested whether there's a nicer/cleaner solution.

like image 774
Dror Avatar asked Sep 27 '17 06:09

Dror


People also ask

What is on click option?

A user interface technique for Mac computers, where the Option key is depressed and held down while the mouse is clicked on an item onscreen. Depending on the context — what is clicked, which app is active, etc., — a variety of functions may be initiated.

How do you make a click option in Python?

Python click simple example The example creates a command that outputs a message. Click uses the echo instead of the print . It increases compatibility and adds colouring support. $ ./simple.py Hello there $ ./simple.py --help Usage: simple.py [OPTIONS] Options: --help Show this message and exit.

What is click Pass_context?

This is a special attribute where commands are supposed to remember what they need to pass on to their children. In order for this to work, we need to mark our function with pass_context() , because otherwise, the context object would be entirely hidden from us.

What is Python click option?

Click, or “Command Line Interface Creation Kit” is a Python library for building command line interfaces. The three main points of Python Click are arbitrary nesting of commands, automatic help page generation, and supporting lazy loading of subcommands at runtime.


1 Answers

In the particular case of this example, I think an easier method would be to get rid of --output, and simply assume stdout if --filename is not specified and if --filename is specified, then use it instead of stdout.

But assuming this is a contrived example, you can inherit from click.Option to allow hooking into the click processing:

Custom Class:

class OptionRequiredIf(click.Option):

    def full_process_value(self, ctx, value):
        value = super(OptionRequiredIf, self).full_process_value(ctx, value)

        if value is None and ctx.params['output'] == 'file':
            msg = 'Required if --output=file'
            raise click.MissingParameter(ctx=ctx, param=self, message=msg)
        return value

Using Custom Class:

To use the custom class, pass it as the cls argument to the option decorator like:

@click.option('--filename', type=click.STRING, cls=OptionRequiredIf)

Test Code:

import click

@click.command()
@click.option('--output',
              type=click.Choice(['stdout', 'file']), default='stdout')
@click.option('--filename', type=click.STRING, cls=OptionRequiredIf)
def main(output, filename):
    print("output: " + output)
    if output == 'file':
        if filename is None:
            print("filename must be provided!")
        else:
            print("filename: " + str(filename))


main('--output=file'.split())

Results:

Usage: test.py [OPTIONS]

Error: Missing option "--filename".  Required if --output=file
like image 198
Stephen Rauch Avatar answered Nov 01 '22 20:11

Stephen Rauch