I have a script like:
#myscript.py
import click
def step1(arg1):
print('Step 1: ' + arg1)
def step2(arg2):
print('Step 2: ' + arg2)
def main(arg1, arg2):
step1(arg1)
step2(arg2)
Most of the time I want to run the script with myscript arg1 arg2
, but occasionally I might want to run only one step: e.g. myscript step1 arg1
. How do I set up click to do this? Is there a way to have one default command and then other optional ones?
This seems to be the one thing that Click discourages:
Sometimes, it might be interesting to invoke one command from another command. This is a pattern that is generally discouraged with Click, but possible nonetheless.
Do I need to use this click.invoke()
pattern?
I didn't phrase the question to fully explain what I was trying to do, since each step also requires the output from the previous one. Huge thanks to Paul for starting me on the right path.
My solution was something like:
@click.group(invoke_without_command=True)
@click.option('--arg1')
@click.option('--arg2')
@click.pass_context
def cli(ctx, arg1, arg2):
'''Description
'''
if ctx.invoked_subcommand is None:
do_everything(ctx, arg1, arg2)
@cli.command()
@click.option('--arg1')
def step_1(arg1):
return do_something(arg1)
@cli.command()
@click.argument('step_one_result')
@click.option('--arg2')
def step_2(step_one_result, arg2):
do_something_else(step_one_result, arg2)
def do_everything(ctx, arg1, arg2):
step_one_result = ctx.invoke(step_1, arg1=arg1)
ctx.invoke(do_something_else, step_one_result=step_one_result, arg2=arg2)
#and because of weirdness with pass_context and using setuptools
def main():
cli(obj={})
if __name__ == '__main__':
main()
EDIT: you'll notice the use of ctx.invoke()
which was necessary to call the functions without getting the following error
line 619, in make_context
ctx = Context(self, info_name=info_name, parent=parent, **extra)
TypeError: __init__() got an unexpected keyword argument 'arg1'