I would suggest doing that with a custom click.Command
class like:
Custom Class:
def command_required_option_from_option(require_name, require_map):
class CommandOptionRequiredClass(click.Command):
def invoke(self, ctx):
require = ctx.params[require_name]
if require not in require_map:
raise click.ClickException(
"Unexpected value for --'{}': {}".format(
require_name, require))
if ctx.params[require_map[require].lower()] is None:
raise click.ClickException(
"With {}={} must specify option --{}".format(
require_name, require, require_map[require]))
super(CommandOptionRequiredClass, self).invoke(ctx)
return CommandOptionRequiredClass
Using the Custom Class
required_options = {
1: 'generator_string',
2: 'number_of_sample_points',
3: 'number_of_center_points',
}
@click.command(cls=command_required_option_from_option('doe', required_options))
...
How does this work?
This works because click is a well designed OO framework. The @click.command()
decorator usually instantiates a click.Command
object but allows this behavior to be over ridden with the cls
parameter. So it is a relatively easy matter to inherit from click.Command
in our own class and over ride desired methods.
In this case, we override click.Command.invoke()
and then validate that the required option has been set before running the command
Test Code:
import click
required_options = {
1: 'generator_string',
2: 'number_of_sample_points',
3: 'number_of_center_points',
}
@click.command(context_settings=dict(max_content_width=800),
cls=command_required_option_from_option('doe', required_options))
@click.option('--input', required=True,
type=click.Path(exists=True))
@click.option('--doe', required=True, type=int)
@click.option('--generator_string', required=False, type=str, is_eager=True)
@click.option('--number_of_sample_points', required=False, type=int,
is_eager=True)
@click.option('--number_of_center_points', required=False, type=int,
is_eager=True)
def main(input, doe, generator_string, number_of_sample_points,
number_of_center_points):
click.echo('input: {}'.format(input))
click.echo('doe: {}'.format(doe))
click.echo('generator_string: {}'.format(generator_string))
click.echo('Num of sample_points: {}'.format(number_of_sample_points))
click.echo('Num of center_points: {}'.format(number_of_center_points))
if __name__ == "__main__":
commands = (
'--input ./input.txt --doe 0',
'--input ./input.txt --doe 1',
'--input ./input.txt --doe 2',
'--input ./input.txt --doe 3',
'--input ./input.txt --doe 1 --generator_string 1234',
'--input ./input.txt --doe 2 --number_of_sample_points 3',
'--input ./input.txt --doe 3 --number_of_center_points 2',
'',
'--help',
)
import sys, time
time.sleep(1)
print('Click Version: {}'.format(click.__version__))
print('Python Version: {}'.format(sys.version))
for cmd in commands:
try:
time.sleep(0.1)
print('-----------')
print('> ' + cmd)
time.sleep(0.1)
main(cmd.split())
except BaseException as exc:
if str(exc) != '0' and \
not isinstance(exc, (click.ClickException, SystemExit)):
raise
Results:
Click Version: 6.7
Python Version: 3.6.3 (v3.6.3:2c5fed8, Oct 3 2017, 18:11:49) [MSC v.1900 64 bit (AMD64)]
-----------
> --input ./input.txt --doe 0
Error: Unexpected value for --'doe': 0
-----------
> --input ./input.txt --doe 1
Error: With doe=1 must specify option --generator_string
-----------
> --input ./input.txt --doe 2
Error: With doe=2 must specify option --number_of_sample_points
-----------
> --input ./input.txt --doe 3
Error: With doe=3 must specify option --number_of_center_points
-----------
> --input ./input.txt --doe 1 --generator_string 1234
input: ./input.txt
doe: 1
generator_string: 1234
Num of sample_points: None
Num of center_points: None
-----------
> --input ./input.txt --doe 2 --number_of_sample_points 3
input: ./input.txt
doe: 2
generator_string: None
Num of sample_points: 3
Num of center_points: None
-----------
> --input ./input.txt --doe 3 --number_of_center_points 2
input: ./input.txt
doe: 3
generator_string: None
Num of sample_points: None
Num of center_points: 2
-----------
>
Usage: test.py [OPTIONS]
Error: Missing option "--input".
-----------
> --help
Usage: test.py [OPTIONS]
Options:
--input PATH [required]
--doe INTEGER [required]
--generator_string TEXT
--number_of_sample_points INTEGER
--number_of_center_points INTEGER
--help Show this message and exit.
--doe
as subcommands. Each subcommand can have completely different options. – Deltadeltaic