I am learning getopt
in Python to parse and validate command line inputs:
#!/usr/bin/python
'''\nMailing Script
Usage: python script.py -y <year> -c <type_user>"
Arguments:
-y, --year any value from 2008 to 2013
-c, --campaign any value in:
'80c', '80d', 'allowances', 'late_filing',
'exempt_income', 'other_sources'
Flags:
-h help
'''
import sys, getopt
first_yr, last_yr = (2008, 2013)
campaign_type = (
'80c', '80d', 'allowances', 'late_filing',
'exempt_income', 'other_sources',
)
def usage():
print sys.exit(__doc__)
def parse_arguments(argv):
try:
opts, args = getopt.getopt(argv[1:], "y:c:", ["year=", "campaign="])
except getopt.GetoptError:
usage()
for opt, arg in opts:
if opt == '-h':
usage()
elif opt in ("-y", "--year"):
target_year = arg
# customized exception
try:
if not target_year in map(str, range(first_yr, last_yr+1)):
raise Exception()
except:
sys.exit("Argument Error: Invalid year passed. \n"
"One valid year is within (%s, %s)" % (first_yr, last_yr)
)
elif opt in ("-c", "--campaign"):
campaign = arg.lower()
try:
if not campaign in campaign_type:
raise Exception()
except Exception, e:
sys.exit("Argument Error: Invalid 'Campaign type' passed. \n"
"A valid value can be any of %s" % str(campaign_type)
)
# to avoid 'UnboundLocalError' Exception when one argument not passed
try:
target_year, campaign
except UnboundLocalError, u:
usage()
print 'Year : ', target_year
print 'campaign: ', campaign
# return argument values
return (target_year, campaign)
if __name__ == "__main__":
target_year, campaign = parse_arguments(sys.argv)
Presently I didn't learn 16.4. argparse. I will learn it in the next step.
I want to improve my script as follows:
All arguments are mandatory. Presently if the user misses some argument then the script raises an
UnboundLocalError
exception. I then catch it and callusage()
. Is it a correct way? Should I uselen(argv)
in some ways to handle this?I check for correct values of arguments. If any argument value is wrong then I explicitly raise an exception and print an error message in the
except
clause. I am again not sure whether it's a preferable way to write this kind of code. I feel it adds one more level of nested blocks.
Some runs of this script:
$ python opt.py -y 2012 -c 80c Year : 2012 campaign: 80c
Correct as I want:
$ python opt.py -year=2012 Argument Error: Invalid year passed. One valid year is within (2008, 2013)
I think I should print message something like "insufficient arguments passed" or "use --year=2012 or -y 2012".