Python command line arg with getopt does not work - python

I modified the sample code given here:
sample code for getopt
as follows, but it does not work. I am not sure what I am missing. I added a "-j" option to this existing code. Eventually, I want to add as many as required command option to meet my needs.
When I give input as below, it does not print anything.
./pyopts.py -i dfdf -j qwqwqw -o ddfdf
Input file is "
J file is "
Output file is "
Can you please let me know whats wrong here?
#!/usr/bin/python
import sys, getopt
def usage():
print 'test.py -i <inputfile> -j <jfile> -o <outputfile>'
def main(argv):
inputfile = ''
jfile = ''
outputfile = ''
try:
opts, args = getopt.getopt(argv,"hij:o:",["ifile=","jfile=","ofile="])
except getopt.GetoptError:
usage()
sys.exit(2)
for opt, arg in opts:
if opt == '-h':
usage()
sys.exit()
elif opt in ("-i", "--ifile"):
inputfile = arg
elif opt in ("-j", "--jfile"):
jfile = arg
elif opt in ("-o", "--ofile"):
outputfile = arg
print 'Input file is "', inputfile
print 'J file is "', jfile
print 'Output file is "', outputfile
if __name__ == "__main__":
main(sys.argv[1:])

Your error is omitting a colon following the i option. As stated by the link you supplied:
options that require an argument should be followed by a colon (:).
Therefore, the corrected version of your program should contain the following:
try:
opts, args = getopt.getopt(argv,"hi:j:o:",["ifile=","jfile=","ofile="])
except getopt.GetoptError:
usage()
sys.exit(2)
Executing it with the specified arguments derives the expected output:
~/tmp/so$ ./pyopts.py -i dfdf -j qwqwqw -o ddfdf
Input file is " dfdf
J file is " qwqwqw
Output file is " ddfdf
However, as a comment to your question specifies, you should use argparse rather than getopt:
Note: The getopt module is a parser for command line options whose API is designed to be familiar to users of the C getopt() function. Users who are unfamiliar with the C getopt() function or who would like to write less code and get better help and error messages should consider using the argparse module instead.

Related

getopt not quite working, what am I doing wrong?

I am not sure why the code below does not work - I get the error
NameError: name 'group1' is not defined.
The code worked fine before I tried to use getopt.. I am trying to parse the command line input so that eg if I put
python -q file1 file2 -r file3 file4
the file1 and file2 become the input into my first loop as 'group1'.
import sys
import csv
import vcf
import getopt
#set up the args
try:
opts, args = getopt.getopt(sys.argv[1:], 'q:r:h', ['query', 'reference', 'help'])
except getopt.GetoptError as err:
print str(err)
sys.exit(2)
for opt, arg in opts:
if opt in ('-h', '--help'):
print "Usage python -q [query files] -r [reference files]"
print "-h this help message"
elif opt in ('-q', '--query'):
group1 = arg
elif opt in ('-r', '--reference'):
group2 = arg
else:
print"check your args"
#extract core snps from query file, saving these to the set universal_snps
snps = []
outfile = sys.argv[1]
for variants in group1:
vcf_reader = vcf.Reader(open(variants))
The problem is that group1 = arg is never running, so when it later gets to for variants in group1:, the variable is not defined.
This is because you are calling the function incorrectly for how you defined your options. When you have the line:
opts, args = getopt.getopt(sys.argv[1:], 'q:r:h', ['query', 'reference', 'help'])
There is a requirement that the arguments with flags (i.e. -q file1 and -r file3 be specified before any other arguments. Therefore, if you were to call the function as:
python <scriptName> -q file1 -r file3 file2 file4
You would have the intended behaviour. This is because all the parameters without an associated flag appear at the end of the call (and would be retrievable through the args parameter

Issue handling file from command line with biopython SeqIO

This is my first attempt at using commandline args other than the quick and dirty sys.argv[] and writing a more 'proper' python script. For some reason that I can now not figure out, it seems to be objecting to how I'm trying to use the input file from the command line.
The script is meant to take an input file, some numerical indices, and then slice out a subset region of the file, however I keep getting errors that the variable I've given to the file I'm passing in is not defined:
joehealey#7c-d1-c3-89-86-2c:~/Documents/Warwick/PhD/Scripts$ python slice_genbank.py --input PAU_06042014.gbk -o test.gbk -s 3907329 -e 3934427
Traceback (most recent call last):
File "slice_genbank.py", line 70, in <module>
sub_record = record[start:end]
NameError: name 'record' is not defined
Here's the code, where am I going wrong? (I'm sure its simple):
#!/usr/bin/python
# This script is designed to take a genbank file and 'slice out'/'subset'
# regions (genes/operons etc.) and produce a separate file.
# Based upon the tutorial at http://biopython.org/DIST/docs/tutorial/Tutorial.html#htoc44
# Set up and handle arguments:
from Bio import SeqIO
import getopt
def main(argv):
record = ''
start = ''
end = ''
try:
opts, args = getopt.getopt(argv, 'hi:o:s:e:', [
'help',
'input=',
'outfile=',
'start=',
'end='
]
)
if not opts:
print "No options supplied. Aborting."
usage()
sys.exit(2)
except getopt.GetoptError:
print "Some issue with commandline args.\n"
usage()
sys.exit(2)
for opt, arg in opts:
if opt in ("-h", "--help"):
usage()
sys.exit(2)
elif opt in ("-i", "--input"):
filename = arg
record = SeqIO.read(arg, "genbank")
elif opt in ("-o", "--outfile"):
outfile = arg
elif opt in ("-s", "--start"):
start = arg
elif opt in ("-e", "--end"):
end = arg
print("Slicing " + filename + " from " + str(start) + " to " + str(end))
def usage():
print(
"""
This script 'slices' entries such as genes or operons out of a genbank,
subsetting them as their own file.
Usage:
python slice_genbank.py -h|--help -i|--input <genbank> -o|--output <genbank> -s|--start <int> -e|--end <int>"
Options:
-h|--help Displays this usage message. No options will also do this.
-i|--input The genbank file you which to subset a record from.
-o|--outfile The file name you wish to give to the new sliced genbank.
-s|--start An integer base index to slice the record from.
-e|--end An integer base index to slice the record to.
"""
)
#Do the slicing
sub_record = record[start:end]
SeqIO.write(sub_record, outfile, "genbank")
if __name__ == "__main__":
main(sys.argv[1:])
It's also possible there's an issue with the SeqIO.write syntax, but I haven't got as far as that yet.
EDIT:
Also forgot to mention that when I use `record = SeqIO.read("file.gbk", "genbank") and write the file name directly in to the script, it works correctly.
As said in the comments, your variable records is only defined in the method main() (the same is true for start and end), thus it is not visible for the rest of the program.
You can either return the values like this:
def main(argv):
...
...
return record, start, end
Your call to main() can then look like this:
record, start, end = main(sys.argv[1:])
Alternatively, you can move your main functionality into the main function (as you did).
(Another way is to define the variables in the main program and the use the global keyword in your function, this is, however, not recommended.)

Python command line arguments - hope to print error when no argument

I have a following simple code:
import sys, getopt
ifile=''
ofile=''
try:
opts, args = getopt.getopt(sys.argv[1:],"h:i:o:")
except getopt.GetoptError as e:
print (str(e))
print("test.py -i input -o output")
sys.exit(2)
for o, a in opts:
if o == '-h':
print 'test.py -i input -o output'
sys.exit()
elif o == '-i':
ifile=a
elif o == '-o':
ofile=a
What should I need to add, if I want to print error (and also help) message 'test.py -i input -o output' when I execute just the script like:
$ python test.py
Thank you
You can write
if len(sys.argv) <= 1:
print('test.py -i input -o output')
exit(1)
after the imports, which basically means that if i don't have any arguments, print the message and quit running the script.
Just as an alternative, if you are interested, the documentation for getopts actually provides a suggestion to use argparse, which significantly reduces the lines of code you have to write to handle arguments.
Look at the bottom of the doc here:
https://docs.python.org/2/library/getopt.html#getopt.GetoptError
And here is the documentation for argparse
https://docs.python.org/2/library/argparse.html#module-argparse
The big bonus with argparse is that has a built in "help" that is nicely formatted. Look at the following example. You can take this code and test on your end too.
from argparse import ArgumentParser, RawTextHelpFormatter
parser = ArgumentParser(
description='This application will perform actions',
formatter_class=RawTextHelpFormatter
)
parser.add_argument(
'-i',
help='Things with i',
)
parser.add_argument(
'-o',
help='Things with o',
)
args = vars(parser.parse_args())
if args.get('i'):
print(args.get('i'))
elif args.get('o'):
print(args.get('o'))
else:
parser.error('Invalid options provided')
Just thought I'd share as an alternative.

how show error if no args was set in console trying execute python script

I need to write python script which need command arguments for executing. I have such code:
try:
opts, args = getopt.getopt(argv,"htt:tf:d:",["from=","to=","on="])
except getopt.GetoptError:
print 'logReader.py -f <from> -t <to> -d <on>'
sys.exit(2)
for opt, arg in opts:
if opt == '-h':
print 'logReader.py -f <from> -t <to> -d <on>'
sys.exit()
# elif opt
elif opt in ("-f", "--from"):
fromTime = arg
elif opt in ("-t", "--to"):
toTime = arg
elif opt in ("-d", "--on"):
onDate = arg
But than I run my script without any arguments it just do nothing. How can I add some check like if no args are specified the error message should be shown in the console (or help)
With no arguments set, opts will be an empty list:
if not opts:
print 'logReader.py -f <from> -t <to> -d <on>'
sys.exit(2)
You should really consider using the argparse module instead, which lets you specify that some command line options are mandatory.

Should I also parse mandatory arguments with getopt(...)

"""
Saves a dir listing in a file
Usage: python listfiles.py -d dir -f filename [flags]
Arguments:
-d, --dir dir; ls of which will be saved in a file
-f, --file filename (if existing will be overwritten)
Flags:
-h, --help show this help
-v, --verbose be verbose
"""
...
def usage():
print __doc__
def main(args):
verbose = False
srcdir = filename = None
try:
opts, args = getopt.getopt(args,
'hvd:f:', ['help', 'verbose', 'dir=', 'file='])
except getopt.GetoptError:
usage()
sys.exit(2)
for opt, arg in opts:
if opt in ('-h', '--help'):
usage()
sys.exit(0)
if opt in ('-v', '--verbose'):
verbose = True
elif opt in ('-d', '--dir'):
srcdir = arg
elif opt in ('-f', '--file'):
filename = arg
if srcdir and filename:
fsock = open(filename, 'w')
write_dirlist_tosock(srcdir, fsock, verbose)
fsock.close()
else:
usage()
sys.exit(1)
if __name__ == '__main__':
main(sys.argv[1:])
I am not sure if it is pythonic to use getopt() to also handle mandatory arguments. Would appreciate some suggestions
the getopt module is only for those users who are already familiar with the same module in C, the python standard argument handling is argparse.
"Mandatory Options" is a contradiction, and is not generally well supported by the various option parsing libraries; You should consider placing mandatory arguments as a positional arguments, not parsed by the option parser, this would agree with common practice much better.

Categories