Python argv validation - python

I need to check if the user is giving the input file and the name of the output, and I'm doing the following:
def main():
if len(argv) > 2:
script, file_in, file_out = argv
execute_code(file_in, file_out)
else:
print "Wrong number of arguments!"
print "Usage: python script.py filename_input filename_output"
if __name__ == '__main__':
main()
Is there other way to check if the argv arguments are correct?

You'd use argparse:
The argparse module makes it easy to write user-friendly command-line
interfaces. The program defines what arguments it requires, and
argparse will figure out how to parse those out of sys.argv.
For example your main function could be rewritten as
import argparse
def main():
parser = argparse.ArgumentParser()
parser.add_argument('file_in', help='input file')
parser.add_argument('file_out', help='output file')
args = parser.parse_args()
execute_code(args.file_in, args.file_out)
if __name__ == '__main__':
main()
argparse will perform validation for you and display fairly helpful error messages if some of the required arguments are missing:
vaultah#base:~$ python3 /home/vaultah/untitled.py
usage: untitled.py [-h] file_in file_out
untitled.py: error: the following arguments are required: file_in, file_out
vaultah#base:~$ python3 /home/vaultah/untitled.py in
usage: untitled.py [-h] file_in file_out
untitled.py: error: the following arguments are required: file_out
Additionally, it will generate a help message
vaultah#base:~$ python3 /home/vaultah/untitled.py -h
usage: untitled.py [-h] file_in file_out
positional arguments:
file_in input file
file_out output file
optional arguments:
-h, --help show this help message and exit

While it's a little more work, you might want to consider using argparse.
You code would become:
import argparse
def execute_code(file_in, file_out):
pass
def main():
parser = argparse.ArgumentParser(description='Process some files.')
parser.add_argument('file_in', help='input file')
parser.add_argument('file_out', help='output file')
args = parser.parse_args()
execute_code(args.file_in, args.file_out)
if __name__ == '__main__':
main()
Running the program with no arguments:
python demo.py
Yields:
usage: demo.py [-h] file_in file_out
demo.py: error: the following arguments are required: file_in, file_out
Running the program with the -h flag:
python demo.py -h
Yields:
usage: demo.py [-h] file_in file_out
Process some files.
positional arguments:
file_in input file
file_out output file
optional arguments:
-h, --help show this help message and exit

Use argparse; ideally, use argparse.FileType to open files automatically from command-line arguments.
If the arguments don't make sense as open files, you can catch the exception thrown.

You can also specify the option required=True to make the arguments mandatory. This will throw an error if the required arguments are not specified. Here is an example:
parser.add_argument("--required_arg",
required=True,
help="The argument which is mandatory")
For checking the path of the input and output files, you can use the following code:
if not os.path.exists(file_name):
error_message = file_name + " does not exist \n";
You can also look at my blog Techable for more information on argument parser in python.

Related

collecting input files from command line in unix using argparse library

I'm trying to write a script that would take some flags and files as arguments and then execute other scripts, depend on the flag that the user chooses. For example, the command line should look like that:
main_script.py -flag1 -file_for_flag_1 another_file_for_flag_1
and
main_script.py -flag2 -file_for_flag_2
I tried to use the argparse library, but I don't know how to take the input files as arguments for the next steps and manipulate them as I want. I started with:
parser = argparse.ArgumentParser(description="Processing inputs")
parser.add_argument(
"-flat_map",
type=str,
nargs="+",
help="generates a flat addressmap from the given files",
)
parser.add_argument(
"-json_convert",
type=str,
nargs="+",
help="generates a flat addressmap from the given files",
)
args = parser.parse_args(args=["-flat_map"])
print(args)
I printed args in the end to see what I get from it but I got nothing I can work with.
Would like to have some guidance. Thanks.
You can convert the args to a dict (where the key is the arg option and the value is the arg value) if it's more convenient for you:
args_dict = {key: value for key, value in vars(parser.parse_args()).items() if value}
Using argparse you can use sub-commands to select sub-modules:
import argparse
def run_command(parser, args):
if args.command == 'command1':
# add code for command1 here
print(args)
elif args.command == 'command2':
# add code for command2 here
print(args)
parser = argparse.ArgumentParser(
prog='PROG',
epilog="See '<command> --help' to read about a specific sub-command."
)
subparsers = parser.add_subparsers(dest='command', help='Sub-commands')
A_parser = subparsers.add_parser('command1', help='Command 1')
A_parser.add_argument("--foo")
A_parser.add_argument('--bar')
A_parser.set_defaults(func=run_command)
B_parser = subparsers.add_parser('command2', help='Command 2')
B_parser.add_argument('--bar')
B_parser.add_argument('--baz')
B_parser.set_defaults(func=run_command)
args = parser.parse_args()
if args.command is not None:
args.func(parser, args)
else:
parser.print_help()
This generates a help page like so:
~ python args.py -h
usage: PROG [-h] {command1,command2} ...
positional arguments:
{command1,command2} Sub-commands
command1 Command 1
command2 Command 2
optional arguments:
-h, --help show this help message and exit
See '<command> --help' to read about a specific sub-command.
and help text for each sub-command:
~ python args.py B -h
arg.py command2 -h
usage: PROG command2 [-h] [--bar BAR] [--baz BAZ]
optional arguments:
-h, --help show this help message and exit
--bar BAR
--baz BAZ

argparse: Why do I get "the following arguments are required"?

I am a beginner in programming, I am using the example
import argparse
import pandas as pd
def read_data(fname):
return pd.read_csv(fname)
if __name__ == "__main__":
options = argparse.ArgumentParser()
options.add_argument("-f", "--file", type=str, required=True)
args = options.parse_args()
data = read_data(args.file)
print(data)
I got this error:
error: the following arguments are required: -f/--file
Would you please help me how can define my file name, where to write it?
Thank you
With required=True, the command-line must include the -f or --file arguments:
# python myprog.py --file=somefile.txt
Make required=False
options.add_argument("-f", "--file", type=str, required=False)
Your original code would require yourprogram -f filename.csv where yourprogram is the name of your script file, and filename.csv is the name of a CSV file with input data. The -f option can also be spelled out in longhand as --file.
But options should typically be optional. Make this a regular required argument if it is mandatory.
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("file", type=str)
args = parser.parse_args()
data = read_data(args.file)
print(data)
Usage: yourprogram filename.csv
Perhaps you are using python yourprogram.py to run this script; then the usage would be python yourprogram.py filename.csv

argparser.print_help() not printing the full message

I have a program where I tried to put help in my code using argparse:
import argparse,sys
parser = argparse.ArgumentParser(description='prog desc')
parser.add_argument('path', help='name of directory')
args = parser.parse_args()
parser.print_help()
this prints:
>python testArgs.py
usage: testArgs.py [-h] path
testArgs.py: error: too few arguments
but I'm expecting same as if I entered -h:
>python testArgs.py -h
usage: testArgs.py [-h] path
prog desc
positional arguments:
path name of directory
optional arguments:
-h, --help show this help message and exit
But if I switch the position of the print_help() before parse_args(), then it works right:
import argparse,sys
parser = argparse.ArgumentParser(description='prog desc')
parser.add_argument('path', help='name of directory')
parser.print_help()
args = parser.parse_args()
output:
>python testArgs.py
usage: testArgs.py [-h] path
prog desc
positional arguments:
path name of directory
optional arguments:
-h, --help show this help message and exit
usage: testArgs.py [-h] path
testArgs.py: error: too few arguments
What am I doing wrong?
In your first example your program doesn't reach the parser.print_help() method, it fails on parser.parse_args(), prints the default error message (which is testArgs.py: error: too few arguments) and exits the program.
In your second example, when you switch between the functions, it still behaves the same but you see the help details because you called the print_help() function before the program fails (you can see it fails because it still prints the error message at the end).
If you want to print the help message when an argparse error occurred, read this post:
Display help message with python argparse when script is called without any arguments

python - is it possible to enter user-chosen input and output files

I'm a newbie in python, so please bear with me.
I don't know how to describe,so I'll just show an example.
python CODE.py -i1 input1.txt -i2 input2.txt -o output.txt
Is such thing possible with python? I've looked up for a while but haven't find an answer.
Thank you!
Instead of just linking to the argparse module or the argparse tutorial,
the other respondents probably should have just shown you how to do it:
import argparse
# Build the parser
p = argparse.ArgumentParser(prog='CODE.PY')
p.add_argument('-i1', type=argparse.FileType('r'),
metavar='sourcefile1', help='First input file')
p.add_argument('-i2', type=argparse.FileType('r'),
metavar='sourcefile2', help='Second input file')
p.add_argument('-o', type=argparse.FileType('w'),
metavar='destfile', help='Destination filename')
# Parse sys.argv
ns = p.parse_args()
# Use the files
data1 = ns.i1.read()
data2 = ns.i2.read()
result = data1[:10] + data2[:10]
ns.o.write(result)
A nice feature of argparse is that not only does it build parsers, it creates a nice option for command-line help:
$ python CODE.PY -h
usage: CODE.PY [-h] [-i1 sourcefile1] [-i2 sourcefile2] [-o destfile]
optional arguments:
-h, --help show this help message and exit
-i1 sourcefile1 First input file
-i2 sourcefile2 Second input file
-o destfile Destination filename
Yes, you can use system argument with your code.
Following snippet of code might help you to resolve your problem
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('inFile', nargs=2, help="Choose in file to use")
parser.add_argument('outFile', nargs=1, help="Choose out file to use")
args=parser.parse_args()
your_fun_call( args.inFile , args.outFile[0] )
Might look wierd at first look but you can refer this document
argparse
Note: infile argument has nargs as 2 because you want two input
files ( nargs stands for number of argument)
As thefourtheye said you can used argparse module. But if you want simple solution, just pass 2 inputs and output file paths as arguments to your executable and use sys.argv to get them in your program in order. The sys.argv[0] is your application name, sys.argv[1] is first input file path, sys.argv[2] is second input file path and sys.argv[3] is output file path.
import sys
input1 = sys.argv[1]
input2 = sys.argv[2]
output = sys.argv[3]
now you can call like below:
python my_app.py /path/to/input1.txt /path/to/input2.txt /path/to/output.txt

How can I print a Python file's docstring when executing it?

I have a Python script with a docstring. When the parsing of the command-line arguments does not succeed, I want to print the docstring for the user's information.
Is there any way to do this?
Minimal example
#!/usr/bin/env python
"""
Usage: script.py
This describes the script.
"""
import sys
if len(sys.argv) < 2:
print("<here comes the docstring>")
The docstring is stored in the module's __doc__ global.
print(__doc__)
By the way, this goes for any module: import sys; print(sys.__doc__). Docstrings of functions and classes are also in their __doc__ attribute.
Argument parsing should always be done with argparse.
You can display the __doc__ string by passing it to the description parameter of Argparse:
#!/usr/bin/env python
"""
This describes the script.
"""
if __name__ == '__main__':
from argparse import ArgumentParser
parser = ArgumentParser(description=__doc__)
# Add your arguments here
parser.add_argument("-f", "--file", dest="myFilenameVariable",
required=True,
help="write report to FILE", metavar="FILE")
args = parser.parse_args()
print(args.myFilenameVariable)
If you call this mysuperscript.py and execute it you get:
$ ./mysuperscript.py --help
usage: mysuperscript.py [-h] -f FILE
This describes the script.
optional arguments:
-h, --help show this help message and exit
-f FILE, --file FILE write report to FILE
Here is an alternative that does not hardcode the script's filename, but instead uses sys.argv[0] to print it. Using %(scriptName)s instead of %s improves readability of the code.
#!/usr/bin/env python
"""
Usage: %(scriptName)s
This describes the script.
"""
import sys
if len(sys.argv) < 2:
print __doc__ % {'scriptName' : sys.argv[0].split("/")[-1]}
sys.exit(0)
This will print the __doc__ string when --help is the only argument.
if __name__=='__main__':
if len(sys.argv)==2 and sys.argv[1]=='--help':
print(__doc__)
Works for both:
./yourscriptname.py --help
python3 yourscriptname.py --help
An enhancement of #MartinThoma's answer so it prints multi-line docstrings inspired by Python argparse: How to insert newline in the help text?.
Argument parsing should always be done with argparse.
You can display the doc string by passing it to the description
parameter of Argparse:
#!/usr/bin/env python
"""
This summarizes the script.
Additional descriptive paragraph(s).
""" # Edited this docstring
if __name__ == '__main__':
from argparse import ArgumentParser, RawTextHelpFormatter # Edited this line
parser = ArgumentParser(description=__doc__
formatter_class=RawTextHelpFormatter) # Added this line
# Add your arguments here
parser.add_argument("-f", "--file", dest="myFilenameVariable",
required=True,
help="write report to FILE", metavar="FILE")
args = parser.parse_args()
print(args.myFilenameVariable)
If you call this mysuperscript.py and execute it you get:
$ ./mysuperscript.py --help
usage: mysuperscript.py [-h] -f FILE
This summarizes the script.
Additional descriptive paragraph(s).
optional arguments:
-h, --help show this help message and exit
-f FILE, --file FILE write report to FILE
Without the addition of the formatter_class the output would not have the line break in the docstring.

Categories

Resources