Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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?

like image 839
Ivan Avatar asked Feb 04 '18 04:02

Ivan


People also ask

How do I get a list of files in a directory in Python?

To get a list of all the files and folders in a particular directory in the filesystem, use os. listdir() in legacy versions of Python or os. scandir() in Python 3.


1 Answers

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.
like image 188
Stephen Rauch Avatar answered Oct 18 '22 02:10

Stephen Rauch