Search code examples
pythoncommand-line-interfacecommand-line-argumentspython-click

How to specify a default value for argument list processed by click?


I have this line of code that is expected to grab all the file names passed to my Python script:

@click.argument("logs", nargs=-1, type=click.File('r'), required=1)

When no file names are passed, I want to default to -, that is, the standard input. So, if I try:

@click.argument("logs", nargs=-1, type=click.File('r'), required=1, default="-")

click becomes unhappy and throws this error:

TypeError: nargs=-1 in combination with a default value is not supported.

Is there a workaround for this? I tried setting nargs=0 but that throws a different error:

IndexError: tuple index out of range


Solution

  • Since click had explicitly stated that they disabled this particular feature needed by the question, as reported on this issue on their project, a workaround will be needed and that can be easily implemented as part of the Python function (instead of some more pile on bash code as suggested by the comment on the other answer).

    The workaround is simply drop the required argument and handle the missing logs using a statement (similar to what this commit did which referenced the linked issue):

    import sys
    import click
    
    @click.command()
    @click.argument("logs", nargs=-1, type=click.File('r'))
    def main(logs):
        if not logs:
            logs = (sys.stdin,)
        print(logs)
        # do stuff with logs
    
    if __name__ == '__main__': 
        main()
    
    

    Example execution

    $ python fail.py 
    (<_io.TextIOWrapper name='<stdin>' mode='r' encoding='UTF-8'>,)
    $ python fail.py -
    (<_io.TextIOWrapper name='<stdin>' mode='r' encoding='UTF-8'>,)
    $ python fail.py foo bar
    (<_io.TextIOWrapper name='foo' mode='r' encoding='UTF-8'>, <_io.TextIOWrapper name='bar' mode='r' encoding='UTF-8'>)