Reputation: 44325
In python 3.8 I want to define some click options that are common to multiple commands. I tried the following piece of code:
import click
@click.group()
@click.option(
"-v",
"--verbose",
count=True,
default=0,
help="-v for DEBUG",
)
@click.option(
"--path",
help="Main Path.",
)
def cli():
pass
@click.command("list")
@click.option(
"--list-option",
help="Special option for list command.",
)
def my_list_command(verbose, path, list_option):
print(verbose, path, list_option)
@click.command("find")
@click.option(
"--find-option",
help="Special option for find command.",
)
def my_find_command(verbose, path, find_option):
print(verbose, path, find_option)
cli.add_command(my_list_command)
cli.add_command(my_find_command)
if __name__ == '__main__':
cli()
But when I try to run the command
python script.py list
I get an error
TypeError: cli() got an unexpected keyword argument 'verbose'
What I want, is that the command list
has the following three options: verbose
, path
and list-option
and that the command find
has the following three options: verbose
, path
and find-option
. I do not want to define the options for verbose
and path
twice.
Is there a way to do this?
I also tried to use @click.pass_context
but that does not seem to solev the issue.
Upvotes: 8
Views: 5695
Reputation: 27283
The way you currently defined it it will work, but the --verbose
option belongs to the main command group, so you'd need to call it as python script.py --verbose list
(and my_find_command
and my_list_command
won't receive it as an argument, only cli
).
To use the same option across multiple commands without repeating yourself too much, you can just assign it to a variable and then use it twice:
verbose_option = click.option(
"-v",
"--verbose",
count=True,
default=0,
help="-v for DEBUG",
)
...
@click.command()
@verbose_option
def foo(verbose):
...
@click.command()
@verbose_option
def bar(verbose):
...
Unrelated, but while we're at it: There's a simpler way of grouping commands, without having to do cli.add_command(my_find_command)
: Just use @cli.command()
instead of @click.command()
:
import click
option_verbose = click.option(
"-v",
"--verbose",
count=True,
default=0,
help="-v for DEBUG",
)
@click.group()
def cli():
pass
@cli.command("list")
@option_verbose
@click.option(
"--list-option",
help="Special option for list command.",
)
def my_list_command(verbose, list_option):
print(verbose, list_option)
@cli.command("find")
@option_verbose
@click.option(
"--find-option",
help="Special option for find command.",
)
def my_find_command(verbose, list_option):
print(verbose, list_option)
if __name__ == '__main__':
cli()
If there's several options you want to apply, you can define your own decorator that calls all those options on the argument:
def common_options(fn):
return click.option(
"-v",
"--verbose",
)(
click.option(
"-n",
"--dry-run",
)(fn)
)
Upvotes: 16