Flexible UNIX command line interface with Python
Question: I was wondering how to create a flexible CLI interface with Python. So far I
have come up with the following:

    
    
    $ cat cat.py
    #!/usr/bin/env python
    
    from sys import stdin
    from fileinput import input
    from argparse import ArgumentParser, FileType
    
    def main(args):
    
       for line in input():
          print line.strip()
    
    if __name__ == "__main__":
       parser = ArgumentParser()
       parser.add_argument('FILE', nargs='?', type=FileType('r'), default=stdin)
       main(parser.parse_args())
    

This handles both stdin and file input:

    
    
    $ echo 'stdin test' | ./cat.py
    stdin test
    
    $ ./cat.py file
    file test
    

The problem is it doesn't handle multiple input or no input the way I would
like:

    
    
    $ ./cat.py file file
    usage: cat.py [-h] [FILE]
    cat.py: error: unrecognized arguments: file
    
    $ ./cat.py 
    

For multiple inputs it should `cat` the file multiple times and for no input
input should ideally have same the behaviour as `-h`:

    
    
    $ ./cat.py -h
    usage: cat.py [-h] [FILE]
    
    positional arguments:
      FILE
    
    optional arguments:
      -h, --help  show this help message and exit
    

Any ideas on creating a flexible CLI interface with Python?


Answer: Use [`nargs='*'`](http://docs.python.org/2/library/argparse.html#nargs) to
allow for 0 or more arguments:

    
    
    if __name__ == "__main__":
        parser = ArgumentParser()
        parser.add_argument('FILE', nargs='*', type=FileType('r'), default=stdin)
        main(parser.parse_args())
    

The help output now is:

    
    
    $ bin/python cat.py -h
    usage: cat.py [-h] [FILE [FILE ...]]
    
    positional arguments:
      FILE
    
    optional arguments:
      -h, --help  show this help message and exit
    

and when no arguments are given, `stdout` is used.

If you want to require at least one `FILE` argument, use `nargs='+'` instead,
but then the default is ignored, so you may as well drop that:

    
    
    if __name__ == "__main__":
        parser = ArgumentParser()
        parser.add_argument('FILE', nargs='+', type=FileType('r'))
        main(parser.parse_args())
    

Now not specifying a command-line argument gives:

    
    
    $ bin/python cat.py
    usage: cat.py [-h] FILE [FILE ...]
    cat.py: error: too few arguments
    

You can always specify `stdin` still by passing in `-` as an argument:

    
    
    $ echo 'hello world!' | bin/python cat.py -
    hello world!
    

