Click: Add feature to forbid option be passed multiple times

Created on 29 Mar 2018  路  6Comments  路  Source: pallets/click

For example:

@click.option("--string", type=click.STRING)
def echo(string):
    click.echo(string)

when running

echo --string=str1 --string=str2

it will print the second one.
I would like to forbid passing it more than once.

All 6 comments

Just to give a second opinion on this feature request, httpie also treats multiple options the same way as click does currently, for example:

# One --print option, --print=H (print request header)
http --print=H PUT httpbin.org/put hello=world
PUT /put HTTP/1.1
Accept: application/json, */*
Accept-Encoding: gzip, deflate
Connection: keep-alive
Content-Length: 18
Content-Type: application/json
Host: httpbin.org
User-Agent: HTTPie/0.9.9

# Two --print options, the --print=h (print response header) is used
$ http --print=H --print=h PUT httpbin.org/put hello=world
HTTP/1.1 200 OK
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: *
Connection: keep-alive
Content-Length: 351
Content-Type: application/json
Date: Tue, 15 May 2018 00:55:27 GMT
Server: gunicorn/19.8.1
Via: 1.1 vegur

I found a work-around that is to turn on the multiple flag and check the option's length, for example:

import click

@click.command()
@click.option("--string", multiple=True, type=click.STRING)
def echo(string):
    if len(string) > 1:
        raise click.exceptions.BadOptionUsage('--string', 'Only one --string option is allowed.')
    string = string[0]
    click.echo(string)

if __name__ == '__main__':
    echo()

Run it:

$ python cli.py --string=hi
hi
$ python cli.py --string=hi --string=hi2
Usage: issue_955.py [OPTIONS]

Error: Only one --string option is allowed.

I'm closing this issue since click is consistent with the kind of processing most commonly done in C (getopt(), e.g.) as far as I could tell.

@dawran6 will you be open to a PR that adds this check as an opt-in option? Something like @click.option('--flag', allow_repeat=False)?

I'm sticking with the current behavior. It allows overriding options defined earlier, which is useful when using alias in the shell or building up a list of args in Python. The behavior seems consistent with Python itself, where later assignment overrides earlier ones.

I vote for the current behavior for the same reason as @davidism

Was this page helpful?
0 / 5 - 0 ratings