Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Error handling when expecting argument

First post, also first attempt to code something beyond 99 bottles...

I am working on code which accepts an argument from the cli such as a text file. Expected usage would be:

$:myfile.py input.txt

I've got that piece going smoothly however if an argument is not supplied, the cli returns an error and i'd like to provide some error response such as a help list or just a simple "Nope - give me a file"

Right now here is the first few lines:

import sys
with open(sys.argv[1], 'r') as f:
    ifile = f.read()
    if len(sys.argv) == 1:
        empty = "Please give me something to do!"
        print empty

If i supply the expected argument, everything is fine, but if no argument is supplied, I get this:

Traceback (most recent call last):
  File "myfile.py", line 3, in <module>
    with open(sys.argv[1], 'r') as f:
IndexError: list index out of range

Lets say I just want the variable "Empty" to print if the condition isn't met... what would i do to fix that.

edit: after trying one of the suggestion below with argparse I am getting better results but I notice argparse throwing in a character I am not expecting. The code is now:

   def main(filename):
    # do something with filename
    print('your filename is %s' % filename)


if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='my program help')
    parser.add_argument('-f', help='specify file path')

when I run this I expect to see -h and -f as options but I see an extra F in the description.

my program help

optional arguments:
  -h, --help  show this help message and exit
  -f F        specify macro file path

Can you tell me how to get rid of this extra F. I have tried a few things but it either appears, or I get errors when I run it.

like image 544
snowblind Avatar asked Oct 17 '22 18:10

snowblind


1 Answers

use argparse for parsing cli input arguments:

example code for your case:

import argparse


def main(filename):
    # do something with filename
    print('your filename is %s' % filename)


if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='my program help')
    parser.add_argument('filename', help='your desired filename')

    args = parser.parse_args()
    main(args.filename)

running from terminal without argument we get:

$ python ans_argparse.py
usage: ans_argparse.py [-h] filename
ans_argparse.py: error: the following arguments are required: filename

running with arguments:

$ python ans_argparse.py 'myfile.txt'
your filename is 'myfile.txt'

creating custom parser may take time and is not that straight forward. argparse has lots of features and is embedded inside the stdlib so prefer to use it.

Another Example

I usually create parse_args() function so testing it or invoking it outside of __main__ is easier:

import sys
import argparse


def main(filename):
    # do something with filename
    print('your filename is %s' % filename)


def parse_args(args_lst):
    parser = argparse.ArgumentParser(description='my program help')
    parser.add_argument('filename', help='your desired filename')
    return parser.parse_args(args_lst)


if __name__ == '__main__':
    args = parse_args(sys.argv[1:])                 
    main(args.filename)

and you can call it like this:

args = parse_args(['another_filename.txt'])

Update

use the metavar optional argument for changing the display name of the variable on the help. I encourage you to read the doc of argparse for more examples and use cases

like this:

parser.add_argument('-f', metavar='FILENAME', required=True, 
                    help='the file path for this program')

output of python myprog.py --help:

optional arguments:
  -h, --help   show this help message and exit
  -f FILENAME  the file path for this program

note: do not forget the required=True argument so you'll get an error message from argparse.

like image 172
ShmulikA Avatar answered Oct 20 '22 11:10

ShmulikA