Savir
Savir

Reputation: 18438

Automatically answer 'yes' on Python's 'click' prompts (unattended command run)

I have built a command line interface using Python's click library (version 7.1.2) that can run a command that asks the (human) user to answer certain confirmations on the way (The well known "Are you sure you want to continue? Y/n")

Now, I'm trying to run that command automatically on a Kubernetes CronJob and I need a way of "pretending" to input Y to each of the prompts.

I have seen the click.confirmation_option, but if I understand correctly, that seems more like a confirmation to run the whole command, right? (maybe I'm wrong?)

I'm more looking for something like some kind of assume_yes in the example below (could be passed either to the invocation or when creating full context ctx = cli.make_context...):

from my_command import cli

ctx = cli.make_context(
    'main_command_group', ["action", "--num_times", 3]
)
with ctx:
    result = cli.invoke(ctx, assume_yes=True)

Is that possible?

I can always add some kind of environment variable, or pass an extra boolean Option (a flag) to my Click command and edit my code so before even trying to show the confirmation prompt, it'd check whether the environment variable (or the flag) is True, and if so, then assume yes (without even showing the prompt), but it feels like Click must have something for unattended runs.

EDIT: (As per the comments)

Upvotes: 0

Views: 2614

Answers (2)

wankata
wankata

Reputation: 989

OK, if you want to do this globally, and not per command, you may override easily the confirm() behaviour:

def confirm(*args, **kwargs):
    if not os.environ.get('yes'):
        click.confirm(*args, **kwargs)

And than, you could use your local version of confirm, instead of click.confirm in your code:

@click.command() 
def test():
    confirm('Create customer', default=False, abort=True)
    ...

Now, if you export the yes environment variable, you will see the difference.

Upvotes: 1

wankata
wankata

Reputation: 989

How do you expect from Click_ to handle this out of the box? The system needs to know that you are a robot, and not a human. How could you achieve this? One way is to have some environment variable, another way is to use special API for your cron job. Nevertheless – you will end up with a special option for this case.

You are totally right – the confirmation_option doesn't cover your case, but it shows you how are you supposed to handle such cases.

So, what I would do is something like this:

@click.option('--yes', is_flag=True)
def my_method(customer_name, yes):
        if not yes: 
            click.confirm(f"Create customer {customer_name}", default=False, abort=True)
        customer = CustomerManger.create(name=customer_name)

You could use environment variables, but I don't see any reason to do it. You can force your cron job to provide the --yes option. It is easier and more obvious.

I played around with the abort=True here, because otherwise I need to repeat the create line one more time, but it may not be suitable for you, if you don't want to abort the whole command and just want to skip the creation of the customer.

And something not related to your question: I advise you to default to False (this is how Click_ works by default), instead of True in your confirmation. I could hit enter unintentionally and shoot myself in the foot. You won't have confirmation dialogue if it wasn't dangerous to confirm bad data, so better don't easy the confirmation that way :)

Upvotes: 1

Related Questions