Reputation: 5855
This question is about the click package:
Click is a Python package for creating beautiful command line interfaces in a composable way with as little code as necessary. It’s the “Command Line Interface Creation Kit”. It’s highly configurable but comes with sensible defaults out of the box.
It aims to make the process of writing command line tools quick and fun while also preventing any frustration caused by the inability to implement an intended CLI API.
I'd like to add a click.Option
to my click.Command
, which changes the behavior of the other parameters of that command. Consider the following example:
@click.option('--x', default=42, prompt=True)
@click.command
def cli_a(x):
print(x)
@click.option('--x', default=42, prompt=False)
@click.command
def cli_b(x):
print(x)
If cli_a
is called without explicitly specifying x
the user is prompted to provide a value (or confirm the default value with ENTER). If cli_b
is called without specifying x
the default value is used without prompting the user.
I'd now like to add a flag click.Option
that allows the user to choose between one of the above variants (at runtime). So, calling cli_c --i
would behave like cli_a
and calling cli_c
would behave like cli_b
.
@click.option('--i', is_flag=True, default=False, expose_value=False)
@click.option('--x', default=42, prompt=False)
@click.command
def cli_c(x):
print(x)
Is that doable with the current API? Is it feasible?
A similar use-case would be something like an anwser-all-confimation-prompts-with-yes flag. Usually this comes up if the cli tool is supposed to be usable interactively by the user and in automated mode via a script or some such thing.
Upvotes: 7
Views: 3027
Reputation: 5855
I have come up with following code, which produces the desired behavior:
def deactivate_prompts(ctx, param, value):
if not value:
click.echo("entering batch mode, deactivating all prompts ...")
for p in ctx.command.params:
if isinstance(p, click.Option) and p.prompt is not None:
p.prompt = None
return value
@click.option('--i/--b', default=True, is_eager=True, expose_value=False, callback=deactivate_prompts)
@click.option('--x', default=42, prompt=True)
@click.command
def cli_c(x):
print(x)
The idea is to use the callback of an eager option to modify all (other) Options
of the Command
.
POTENTIAL WEAK POINTS:
Option
that may or may not display a prompt must be configured as if displaying a prompt.Option
, so an alternate value-source is a must. I.e. a default value must be provided.Upvotes: 7