Skip to main content

Constrained option support for click

Project description

click-constrained-option

click-constrained-option is an extension package that adds constrains to option in Click.

Tested under click 7.x

What it does

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

Quick start

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'

API

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

Note

  • If multiple kwargs are used, then all of them must be satisfied. For example, if prompt_if and prompt_if_all_of are 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 --foo will be passed to a custom function bar(foo).

Examples

Dependency and exclusive relation

--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'

Mutually exclusive group

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'

Conditional prompt

--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: 

Conditional type

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 integer

Conditional default

Default 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'}

Project details


Release history Release notifications | RSS feed

This version

0.1

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

click-constrained-option-0.1.tar.gz (6.2 kB view hashes)

Uploaded Source

Built Distribution

click_constrained_option-0.1-py3-none-any.whl (6.4 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page