click-constrained-option is an extension package that adds constrains to option in Click.
Tested under click 7.x
Build option that:
- mutually exclusive with others
- depend on other options
- is required conditionally
- is promoted conditionally
- set its default value conditionally
- set its type conditionally
pip install click-constrained-option# example.py
import click
from click_constrained_option import ConstrainedOption
@click.command()
@click.option(cls=ConstrainedOption,
group_require_one=["apple", "orange", "pear"])
@click.option("--apple",
cls=ConstrainedOption,
is_flag=True)
@click.option("--orange",
cls=ConstrainedOption,
is_flag=True)
@click.option("--pear",
cls=ConstrainedOption,
is_flag=True)
def cli(**kwargs):
click.echo(kwargs)
if __name__ == "__main__":
cli()$ python example.py
Error: require exact one of '--apple' '--orange' '--pear'
$ python example.py --apple --pear
Error: require exact one of '--apple' '--orange' '--pear'| kwarg | type | usage |
|---|---|---|
| allowed_func | function |
return True to indicate allowance, vice versa |
| allowed_if | str |
name of the option |
| allowed_if_not | str |
name of the option |
| allowed_if_all_of | list |
list of the option names |
| allowed_if_none_of | list |
list of the option names |
| allowed_if_any_of | list |
list of the option names |
| allowed_if_one_of | list |
list of the option names |
| required_func | function |
return True to indicate requirement, vice versa |
| required_if | str |
name of the option |
| required_if_not | str |
name of the option |
| required_if_all_of | list |
list of the option names |
| required_if_none_of | list |
list of the option names |
| required_if_any_of | list |
list of the option names |
| required_if_one_of | list |
list of the option names |
| prompt_func | function |
return True to indicate prompt, vice versa |
| prompt_if | str |
name of the option |
| prompt_if_not | str |
name of the option |
| prompt_if_all_of | list |
list of the option names |
| prompt_if_none_of | list |
list of the option names |
| prompt_if_any_of | list |
list of the option names |
| prompt_if_one_of | list |
list of the option names |
| group_require_one | list |
list of the option names |
| group_require_any | list |
list of the option names |
| group_require_all | list |
list of the option names |
| default_func | function |
return a value to use as the default |
| type_func | function |
return a valid type of the option |
-
If multiple kwargs are used, then all of them must be satisfied. For example, if
prompt_ifandprompt_if_all_ofare specified, then the option is prompted only when both condition hold true. -
If the custom function has an argument equals an option name in the command, then the value of that option will be used as argument. For example, value of
--foowill be passed to a custom functionbar(foo).
--username is allowed if --login is set:
import click
from click_constrained_option import ConstrainedOption
@click.command()
@click.option("--username",
cls=ConstrainedOption,
allowed_if="login")
@click.option("--login", is_flag=True)
def cli(**kwargs):
click.echo(kwargs)
if __name__ == "__main__":
cli()$ python example.py --username=foo
Error: Usage for '--username': require '--login'--login is allowed if at least one of --userid and --email is specified, and --oauth is not set:
import click
from click_constrained_option import ConstrainedOption
@click.command()
@click.option("--login",
cls=ConstrainedOption,
is_flag=True,
allowed_if_any_of=["userid", "email"],
allowed_if_not="cookie")
@click.option("--userid")
@click.option("--email")
@click.option("--oauth", is_flag=True)
def cli(**kwargs):
click.echo(kwargs)
if __name__ == "__main__":
cli()$ python example.py --login --userid=foo --oauth
Error: Usage for '--login': conflict with '--oauth'
$ python example.py --login
Error: Usage for '--login': require at least one of '--userid' '--email'--port is required if --listen is an IP address:
import click
import re
from click_constrained_option import ConstrainedOption
@click.command()
@click.option("--port",
cls=ConstrainedOption,
required_func=lambda b: re.match(r"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}", b))
@click.option("--listen")
def cli(**kwargs):
click.echo(kwargs)
if __name__ == "__main__":
cli()$ python example.py --listen=127.0.0.1
Error: Missing option '--port'Exact one of the --order-by-date --order-by-name --order-by-rank must be set:
import click
from click_constrained_option import ConstrainedOption
@click.option(cls=ConstrainedOption,
group_require_one=["order_by_name", "order_by_rank", "order_by_date"])
@click.option("--order-by-name",
cls=ConstrainedOption,
is_flag=True)
@click.option("--order-by-rank",
cls=ConstrainedOption,
is_flag=True)
@click.option("--order-by-date",
cls=ConstrainedOption,
is_flag=True)
def cli(**kwargs):
click.echo(kwargs)
if __name__ == "__main__":
cli()$ python example.py
Error: require exact one of '--order-by-name' '--order-by-rank' '--order-by-date'--password will be prompted if one of --userid --email is specified
import click
from click_constrained_option import ConstrainedOption
@click.command()
@click.option("--userid")
@click.option("--email")
@click.option("--password",
hide_input=True,
prompt_if_one_of=["userid", "email"])
def cli(**kwargs):
click.echo(kwargs)
if __name__ == "__main__":
cli()$ python example.py --userid
Password: Type of --time will be int if --time-format=timestamp
import click
from click_constrained_option import ConstrainedOption
@click.command()
@click.option("--time-format",
type=click.Choice(["iso-8601", "timestamp"]))
@click.option("--time",
cls=ConstrainedOption,
type_func=lambda time_format: click.INT if time_format == "timestamp" else click.STRING)
def cli(**kwargs):
click.echo(kwargs)
if __name__ == "__main__":
cli()$ python --time-format="timestamp" --time=str_not_int
Error: Invalid value for '--time': str_not_int is not a valid integerDefault of --lucky is set through custom function
import click
from click_constrained_option import ConstrainedOption
from random import randint
@click.command()
@click.option("--lucky",
default=lambda : randint(0, 9))
def cli(**kwargs):
click.echo(kwargs)
if __name__ == "__main__":
cli()$ python example.py
{'lucky': '5'}