python argparse with mandatory input file argument - python

How to add a mandatory option to the parser with prefix -i or --input to specify the input file to the script?
The provided value should be placed into the infile variable

Distilling from the documentation, a minimalistic answer would be
import argparse
#Create the parser
parser = argparse.ArgumentParser(description='Does some stuff with an input file.')
#add the argument
parser.add_argument('-i', '--input', dest='infile', type=file, required=True,
metavar='INPUT_FILE', help='The input file to the script.')
#parse and assign to the variable
args = parser.parse_args()
infile=args.infile
Be aware that if the specified file does not exist, the parser will throw an IOError. removing the type=file parameter will default to reading a string and will let you handle the file operations on the parameter later on.

Related

How could I default to nothing with argparse pointing to a pathname?

Currently, I'm using argparse to output the following file:
import argparse
....
parser = argparse.ArgumentParser(description='do cool stuff')
parser.add_argument('--output_text_file',
default="outputs/output_file1.txt",
help='file path for the output text file')
This is already an optional argument. However, I would like the default option to be do not output anything. If the user would like a file output, they can call the argument with the pathname above, e.g. `--output_text_file "outputs/my_text.txt"
What is normally the correct way to do this?
I suspect that if I use:
default=""
there will be an error above.
Quite simply, just omit the default:
parser.add_argument('--output-text-file')
In the args, check whether the output_text_file is None. The name will always be present.
You could set your default to os.devnull, it's a cross-platform value which corresponds to the file path of a null device
parser.add_argument('--output_text_file',
default=os.devnull,
help='file path for the output text file')

Can I set stdin as required with Python argparse?

I have a script that uses some arguments and some stdin data.
For checking arguments I use argparse.ArgumentParser
Is it possible to check if any stdin data is given? Something like that:
parser.add_argument('infile', nargs='?', type=argparse.FileType('r'), default=sys.stdin, required=True)
but this example gives this error:
TypeError: 'required' is an invalid argument for positionals
No. It wont't read from whatever file you pass it, be it given on the command line, or stdin. You will get an open file handle, with not even a single byte/char consumed.
Simply read the data yourself, for instance with data = args.infile.read() (assuming args is the result of parsing`).
You can then test if it is empty, with a simple if not data:...
But usually, if you expect data in a specific format, the best is to simply try to parse it, and raise an error if you fail. Either empty data is invalid (json for instance), or it is valid but then it should be an acceptable input.
(as for the error, required only tells whether some option must be given on the command line or not, for --options and -o options. Positionals are always required unless you change their numbers with nargs).
The error is just because of the required=True parameter; and the message tells you what is wrong. It should be:
parser.add_argument('infile', nargs='?', type=argparse.FileType('r'), default=sys.stdin)
By 'calling' this infile, as opposed to '--infile', you've created a positional argument. argparse itself determines whether it is required or not. With nargs='?' it can't be required. It's by definition optional (but not an optionals argument :) ).
The FileType type lets you name a file (or '-') in the commandline. It will open it (stdin is already open) and assign it to the args.infile attribute. It does nothing more.
So after parsing, using args.infile gives you access to this open file, which you can read as needed (and optionally close if not stdin).
So this is a convenient way of letting your users specify which file should be opened for use in your code. It was intended for simple scripts that read one file, do something, and write to another.
But if all you are looking at is stdin, there isn't any point in using this type. sys.stdin is always available for reading. And there isn't any way of making the parser read stdin. It parses sys.argv which comes from the commandline.
There is an # prefix file feature that tells the parser to read commandline strings from a file. It parses the file and splices the values into sys.argv. See the argparse docs.
From the docs The add_argument() method
required - Whether or not the command-line option may be omitted (optionals only).
The required keyword is only used for options (e.g., -f or --foo) not for positional arguments. Just take it out.
parser.add_argument('infile', nargs='?', type=argparse.FileType('r'),
default=sys.stdin)
When parsed infile will either be a string or the sys.stdin file object. You would need to read that file to see if there is anything in it. Reading can be risky... you may block forever. But that just means that the user didn't follow instructions.

Multiple files for one argument in argparse Python 2.7

Trying to make an argument in argparse where one can input several file names that can be read.
In this example, i'm just trying to print each of the file objects to make sure it's working correctly but I get the error:
error: unrecognized arguments: f2.txt f3.txt
. How can I get it to recognize all of them?
my command in the terminal to run a program and read multiple files
python program.py f1.txt f2.txt f3.txt
Python script
import argparse
def main():
parser = argparse.ArgumentParser()
parser.add_argument('file', nargs='?', type=file)
args = parser.parse_args()
for f in args.file:
print f
if __name__ == '__main__':
main()
I used nargs='?' b/c I want it to be any number of files that can be used . If I change add_argument to:
parser.add_argument('file', nargs=3)
then I can print them as strings but I can't get it to work with '?'
If your goal is to read one or more readable files, you can try this:
parser.add_argument('file', type=argparse.FileType('r'), nargs='+')
nargs='+' gathers all command line arguments into a list. There must also be one or more arguments or an error message will be generated.
type=argparse.FileType('r') tries to open each argument as a file for reading. It will generate an error message if argparse cannot open the file. You can use this for checking whether the argument is a valid and readable file.
Alternatively, if your goal is to read zero or more readable files, you can simply replace nargs='+' with nargs='*'. This will give you an empty list if no command line arguments are supplied. Maybe you might want to open stdin if you're not given any files - if so just add default=[sys.stdin] as a parameter to add_argument.
And then to process the files in the list:
args = parser.parse_args()
for f in args.file:
for line in f:
# process file...
More about nargs:
https://docs.python.org/2/library/argparse.html#nargs
More about type: https://docs.python.org/2/library/argparse.html#type
Just had to make sure there was at least one argument
parser.add_argument('file',nargs='*')

How do get parameter without name in python

I am trying to write a python script which accepts optional input parameters plus an input file:
./script --lines 1 file.txt
should take 1 for the number of lines (--lines) and then take file.txt as an input file. However, getopt does not even see "file.txt" since it does not have a parameter name in front of it.
How can I get the filename? I already considered using sys.arv[-1], but this means when I run:
./script --lines 1
then 1 will be taken as the input filename. My script will then throw an error (if no file named 1 exists):
error: file '1' no found
This works, but is not a great solution. Is there a way around this?
Definitely use argparse -- It's included in python2.7+ and can easily be installed for older versions:
parser = argparse.ArgumentParser()
parser.add_argument('--lines', type=int, default=0, help='number of lines')
parser.add_argument('file', help='name of file')
namespace = parser.parse_args()
print namespace.lines
print namespace.file
In a call to getopts:
opts, args = getopts(...)
the second element is a list of arguments not recognized by getopts. In your example, it will be a list containing the single item 'file.txt'.

Optional Parameter Python?

I need to create a program called extractGenes.py
The command line parameters need to take 2 OR 3 parameters:
-s is an optional parameter, or switch, indicating that the user wwants the spliced gene sequence(introns removed). The user does not have to provide this (meaning he wants the entire gene sequence), but it he does provide it then it must be the first parameter
input file (with the genes)
output file (where the program will create to store the fasta file
The file contains lines like this:
NM_001003443 chr11 + 5925152 592608098 2 5925152,5925652, 5925404,5926898,
However, I am not sure how to include the -s optional parameter into the starting function.
So I started with:
getGenes(-s, input, output):
fp = open(input, 'r')
wp = open(output, "w")
but am unsure as to how to include the -s.
This case is simple enough to use sys.argv directly:
import sys
spliced = False
if '-s' in sys.argv:
spliced = True
sys.argv.remove('-s')
infile, outfile = sys.argv[1:]
Alternatively, you can also use the more powerful tools like argparse and optparse to generate a command-line parser:
import argparse
parser = argparse.ArgumentParser(description='Tool for extracting genes')
parser.add_argument('infile', help='source file with the genes')
parser.add_argument('outfile', help='outfile file in a FASTA format')
parser.add_argument('-s', '--spliced', action='store_true', help='remove introns')
if __name__ == '__main__':
result = parser.parse_args('-s myin myout'.split())
print vars(result)
Argparse is a python library that willl take care of optional paremeters for you. http://docs.python.org/library/argparse.html#module-argparse
Try something like this:
def getGenes(input, output, s=False):
if s:
...
else:
...
If you input 2 parameters, s will be False;
getGenes(input, output)
If you call getGenes() with 3 parameters, s will be the 3rd parameter, so in this case calling it with any non False value will yield the else clause.

Categories