How to iterate through the list of files supplied by the shell in a Python 3 Click app?
Asked Answered
C

1

6

I am writing a console app with the Click library (almost no experience with it yet) and Python 3.6.

I need a program that can be called like this from the OS shell:

myapp --myoptiona=123 --myoptionb=456 *

to iterate through the list of all the files in the current directory (or whatever the mask specifies) and do something with them.

How can this be achieved with Click?

Cachet answered 4/2, 2018 at 4:36 Comment(0)
R
5

If you need to accept a variable number of file parameters, you can use nargs=-1 with a click.argument to generate the command like:

Code:

@click.command()
@click.option('--myoptiona')
@click.option('--myoptionb')
@click.argument('files', nargs=-1)
def cli(myoptiona, myoptionb, files):
    """The Great CLI APP"""
    filenames = []
    for filename in files:
        # if our shell does not do filename globbing
        expanded = list(glob(filename))
        if len(expanded) == 0 and '*' not in filename:
            raise(click.BadParameter('{}: file not found'.format(filename)))
        filenames.extend(expanded)

    click.echo('myoptiona: %s' % myoptiona)
    click.echo('myoptionb: %s' % myoptionb)
    for name in filenames:
        click.echo('a file: %s' % name)

Test Code:

import click
from glob import glob

@click.command()
@click.option('--myoptiona')
@click.option('--myoptionb')
@click.argument('files', nargs=-1)
def cli(myoptiona, myoptionb, files):
    """The Great CLI APP"""
    filenames = []
    for filename in files:
        expanded = list(glob(filename))
        if len(expanded) == 0 and '*' not in filename:
            raise(click.BadParameter(
                "file '{}' not found".format(filename)))
        filenames.extend(expanded)

    click.echo('myoptiona: %s' % myoptiona)
    click.echo('myoptionb: %s' % myoptionb)
    for name in filenames:
        click.echo('a file: %s' % name)


if __name__ == "__main__":
    commands = (
        '--myoptiona 3 --myoptionb 4',
        '--myoptiona 3 file1 file2',
        '--myoptiona 3 --myoptionb 4 file1 file4',
        'file1 file2 file3',
        'file*',
        '--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)
            cli(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)]
-----------
> --myoptiona 3 --myoptionb 4
myoptiona: 3
myoptionb: 4
-----------
> --myoptiona 3 file1 file2
myoptiona: 3
myoptionb: None
a file: file1
a file: file2
-----------
> --myoptiona 3 --myoptionb 4 file1 file4
Usage: test.py [OPTIONS] [FILES]...

Error: Invalid value: 'file4': file not found
-----------
> file1 file2 file3
myoptiona: None
myoptionb: None
a file: file1
a file: file2
a file: file3
-----------
> file*
myoptiona: None
myoptionb: None
a file: file.conf
a file: file1
a file: file2
a file: file3
-----------
> --help
Usage: test.py [OPTIONS] [FILES]...

  The Great CLI APP

Options:
  --myoptiona TEXT
  --myoptionb TEXT
  --help            Show this message and exit.
Retral answered 4/2, 2018 at 6:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.