In click, I'm defining this command:
@click.command('time', short_help='Timesheet Generator')
@click.argument('time_command', type=click.Choice(['this', 'last']))
@click.argument('data_mode', type=click.Choice(['excel', 'exchange']), default='exchange')
@click.option('--password', prompt=True, hide_input=True, confirmation_prompt=False)
@pass_context
def cli(ctx, time_command, data_mode, password):
The issue I have is that I only want the password to prompt if the data_mode
argument equals exchange
. How can I pull this off?
We can remove the need for a prompt if another parameter does not match a specific value by building a custom class derived from click.Option
, and in that class over riding the click.Option.handle_parse_result()
method like:
import click
def PromptIf(arg_name, arg_value):
class Cls(click.Option):
def __init__(self, *args, **kwargs):
kwargs['prompt'] = kwargs.get('prompt', True)
super(Cls, self).__init__(*args, **kwargs)
def handle_parse_result(self, ctx, opts, args):
assert any(c.name == arg_name for c in ctx.command.params), \
"Param '{}' not found for option '{}'".format(
arg_name, self.name)
if arg_name not in opts:
raise click.UsageError(
"Illegal usage: `%s` is a required parameter with" % (
arg_name))
# remove prompt from
if opts[arg_name] != arg_value:
self.prompt = None
return super(Cls, self).handle_parse_result(ctx, opts, args)
return Cls
To use the custom class, pass the cls
parameter to click.option
decorator like:
@click.option('--an_option', cls=PromptIf('an_argument', 'an_arg_value'))
pass in the name of the parameter to examine for the desired value, and the value to check for.
This works because click is a well designed OO framework. The @click.option()
decorator usually instantiates a click.Option
object but allows this behavior to be overridden with the cls
parameter. So it is a relatively easy matter to inherit from click.Option
in our own class and over ride the desired methods.
In this case we over ride click.Option.handle_parse_result()
and disable the need to prompt if the other specified parameter does not match the desired.
Note: This answer was inspired by this answer.
@click.command()
@click.argument('an_argument', type=click.Choice(['excel', 'exchange']),
default='exchange')
@click.option('--password', hide_input=True, confirmation_prompt=False,
cls=PromptIf('an_argument', 'exchange'))
def cli(an_argument, password):
click.echo(an_argument)
click.echo(password)
cli('exchange'.split())
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With