Option groups¶
Usage¶
The recommended way of defining option groups is through the decorator
cloup.option_group()
. This decorator is overloaded with two signatures;
the only difference between the two is how you provide the help
argument:
# help as keyword argument
@option_group(name, *options, [help], [constraint])
# help as 2nd positional argument
@option_group(name, help, *options, [constraint])
name
is used as title of the option group help section,help
is an optional extended description of the option group, shown below the name,constraint
is an optional instance ofConstraint
(see Constraints for more info); a description of the constraint is shown between squared brackets in the option group title.
import cloup
from cloup import option_group, option
from cloup.constraints import SetAtLeast
@cloup.command('clouptest')
@option_group(
"Input options",
"This is a very long description of the option group. I don't think this is "
"needed very often; still, if you want to provide it, you can pass it as 2nd "
"positional argument or as keyword argument 'help' after all options.",
option('-o', '--one', help='1st input option'),
option('--two', help='2nd input option'),
option('--three', help='3rd input option'),
)
@option_group(
'Output options',
option('--four / --no-four', help='1st output option'),
option('--five', help='2nd output option'),
option('--six', help='3rd output option'),
constraint=RequireAtLeast(1),
)
# Options that don't belong to any option group (including --help)
# are shown under "Other options"
@option('--seven', help='first uncategorized option',
type=click.Choice(['yes', 'no', 'ask']))
@option('--height', help='second uncategorized option')
def cli(**kwargs):
""" A CLI that does nothing. """
print(kwargs)
Usage: clouptest [OPTIONS]
A CLI that does nothing.
Input options:
This is a very long description of the option group. I don't think this is
needed very often; still, if you want to provide it, you can pass it as
2nd positional argument or as keyword argument 'help' after all options.
-o, --one TEXT 1st input option
--two TEXT 2nd input option
--three TEXT 3rd input option
Output options [at least 1 required]:
--four / --no-four 1st output option
--five TEXT 2nd output option
--six TEXT 3rd output option
Other options:
--seven [yes|no|ask] first uncategorized option
--height TEXT second uncategorized option
--help Show this message and exit.
The default option group
Options that are not assigned to any user-defined option group are listed
under a section which is shows at the bottom. This section is titled
“Other options”, unless the default group is the only one defined, in which
case cloup.Command
behaves like a normal click.Command
, naming it
just “Options”.
In the example above, I used the cloup.option()
decorator to define
options but this is entirely optional as you can use click.option()
as
well. The only difference is that cloup.option()
uses
GroupedOption
as default option class, which is just a
click.Option
with an additional attribute called group
.
Nonetheless, you don’t need to use GroupedOption
, because the attribute
group
will be added to any type of Option
via monkey-patching anyway.
By default, the help columns of all option groups are aligned; this is consistent
with how argparse
format option groups and I think it’s visually pleasing.
Nonetheless, you can also format each option group independently passing
align_option_groups=False
to @command()
.
Alternative usage (flat style)¶
In “flat style”, you first define your option groups. Then, you use the
option()
decorator of OptionGroup
:
from cloup import OptionGroup
from cloup.constraints import SetAtLeast
input_grp = OptionGroup(
'Input options', help='This is a very useful description of the group')
output_grp = OptionGroup(
'Output options', constraint=SetAtLeast(1))
@cloup.command('clouptest')
# Input options
@input_grp.option('-o', '--one', help='1st input option')
@input_grp.option('--two', help='2nd input option')
# Output options
@output_grp.option('--four / --no-four', help='1st output option')
@output_grp.option('--five', help='2nd output option')
def cli_flat(**kwargs):
""" A CLI that does nothing. """
print(kwargs)
Equivalently, you could pass the option group as an argument to cloup.option
:
@option('-o', '--one', help='1st input option', group=input_grp)
Note that this works only with cloup.option
, not click.option
.
How it works¶
This feature is implemented simply by adding an attribute group
to options,
monkey-patching them if they are not of type GroupedOption
. This attribute
is of type OptionGroup
or None
.
When the command is initialized, OptionGroupMixin
just groups all options by
their group
attribute. Options that don’t have a group
attribute or have
it set to None
are put into the “default option group”
(together with --help
).
In order to show option groups in the command help,
OptionGroupMixin
“overrides” Command.format_options
.
Feature support¶
Note
If you use command classes/decorators (re)defined by Cloup, you can skip this section.
This features depends on:
(required)
OptionGroupMixin
(optional)
ConstraintMixin
, if you want to use constraints.
Note that cloup.Command
includes both while cloup.Group
doesn’t include
neither of them: groups should have only a few options, so they should not need
neither option groups nor constraints. (If you disagree, open an issue describing
why you need it.) Anyway, you can always add this mixins to Group
with two
lines of code.