This question is about the Python click package and relates to control flow based on arguments passed to the CLI.
I'm trying to build a master CLI to sit at the top directory of my repo, which will control many different modes of operation from one central place. When you invoke this command, it will take perhaps n options, where the first will determine which module to invoke, and then pass along the n-1 args to another module. But I want each module's commands and options to be defined within its respective module, not the main CLI controller, as I'm trying to keep the main controller simple and each module nicely abstracted away.
Here is a simple example of what I want:
import click
@click.command()
@click.option('--foo-arg', default='asdf')
def foo(foo_arg):
click.echo(f"Hello from foo with arg {foo_arg}")
@click.command()
@click.option('--bar-arg', default='zxcv')
def bar(bar_arg):
click.echo(f"Hello from bar with arg {bar_arg}")
@click.command()
@click.option('--mode', type=click.Choice(["foo", "bar"]))
def cli(mode):
if mode == "foo":
foo()
if mode == "bar":
bar()
if __name__ == '__main__':
cli()
In this example, foo() and bar() should be thought of as modules that are buried within the repo and which may also require a large number of CLI options, which I don't want to overload the main cli.py with. I feel like foo()'s CLI options should live within foo for contextual reasons. The following is how I want it to work.
Example 1:
python -m cli --mode foo --foo-arg asdf
should produce
Hello from foo with arg asdf
Example 2:
python -m cli --mode bar --bar-arg zxcv
should produce
Hello from bar with arg zxcv
Example 3:
python -m cli --mode foo --bar-arg qwer
should fail since foo() doesn't have the --bar-arg option.
Disclaimer: I know that I could register foo and bar as separate commands (invoked via python -m cli foo --foo-arg asd, i.e. with foo instead of --foo). However, due to a reason beyond the scope of this question, I need foo or bar to be specified by the --mode option identifier. This is a limitation of a tool that interacts with my app, which is unfortunately outside my control.
Is there a way to parse the args and make control flow possible based on a subset of args and then pass the remaining ones to a subsequent module, while not defining every module's options as decorators on def cli()?