Reputation: 652
I want to enhance an existing command-line application done with Python click to allow for certain options depending on what the --format
option is set to.
In my special case, I would like to enable --delimiter
option when the --format
option equals csv
and an --indent
option when the --format
option equals json
. It should all fit into one command, so I do not want to introduce subcommands if not absolutely necessary.
I looked into the group
mechanism of click
and also the additional extension package click-option-group
but I think this is only about grouping the commands, but does not fulfill the goal above.
This question is similar: python-click: dependent options on another option, but the difference is that it has predefined values for the "sub option", whereas in my case --indent
is a user-specified value, e.g. 2
, 4
, 1
, et cetera...
Furthermore, as all the answers that go into my direction are rather old, I would look for a more up-to-date answer, as to what is possible as of today. What also would be great if it were possible to use functionality of a Python library with preference on click
instead of having to add additional code outside of the library.
Thanks for your help.
Upvotes: 1
Views: 1811
Reputation: 352
You can use the cloup library like this:
import cloup
from cloup.constraints import (
If, require_one, Equal
)
@cloup.command(show_constraints=True)
@click.option('-f', '--format', required=True,
type=click.Choice(['csv', 'json']))
@click.option('-d', '--delimiter', required=False, type=click.Choice(['\t', ', ']))
@click.option('-i', '--indent', required=False, type=int)
@cloup.constraint(If(Equal('format', 'csv'), then=require_one.hidden()), ['delimiter'])
@cloup.constraint(If(Equal('format', 'json'), then=require_one.hidden()), ['indent'])
def formatter(format, delimiter, indent):
pass
Upvotes: 2
Reputation: 989
You can use a callback function like this:
def fix_required(ctx, param, value):
if value == 'csv':
ctx.command.params[1].required = True
else:
ctx.command.params[2].required = True
@click.command()
@click.option('-f', '--format', required=True,
type=click.Choice(['csv', 'json']), callback=fix_required)
@click.option('-i', '--delimiter', required=False, type=click.Choice(['\t', ', ']))
@click.option('-i', '--indent', required=False, type=int)
def formatter(format, delimiter, indent):
pass
The params list is ordered after the order of the option annotations, so it is predictable and should be kept up to date if you add options to your command or edit their order.
Upvotes: 1