Wednesday, April 8, 2020

Python Command Line Argument - Parse variable value at run-time


If you have been writing python command line scripts, chances are you will want to make your script interactive with on the command line.

For example, you will want to set values for some variables at every start of the script. So, instead of editing the script directly, python provides module to help you define the variable at the point of running the script.

There are several modules for doing this, but we will talk about the Python argparse module.

In the script below for example, we did like to change the values of the variables "x and y" each time we want to add new set of values as seen in the script. So, each time we have to edit the script from the text editor before running it.

x = 9
y = 0

print(x + y)



It would be great if we can specify new variables directly on the command line each time we run the script without editing the script directly. This is where 'Command Line Argument' comes to play.

Lets modify the script so it uses command line interface with the Python argparse library.

There are basically five steps involved as listed below:-
1. Import 'argparse' library
2. Create the parser object
3. Add optional, required or positional arguments to the parser
4. Execute to create dictionary collection of the values using .parse_args() method
5. Use the values from the dictionary

#1. Import 'argparse' library
import argparse

#2. Create the parser object
parser = argparse.ArgumentParser()

#3. Add optional, required or positional arguments to the parser
parser.add_argument("-x", "--x_variable", type=int, required=True, help="X numeric value")
parser.add_argument("-y", "--y_variable", type=int, required=True, help="Y numeric value")

#4. Execute to create dictionary collection of the values using .parse_args()
args = vars(parser.parse_args())


# 5. Use the values from the dictionary
x = args['x_variable']
y = args['y_variable']

print(x + y)



If you execute the script like above (without specifying the argument variable), you will get this error:-
usage: Script.py [-h] -x X_VARIABLE -y Y_VARIABLE
Script.py: error: the following arguments are required: -x/--x_variable, -y/--y_variable


This is custom error message from python's argparse library that is telling you how to use the script. The script expects you to provide the values for the two required variables "x and y" by simply entering the values after the script file name as seen below.




What happens if we just entered the variables without "-x" and "-y"?


This will through the error shown above. If we want the script to work like so without "-x" and "-y" calling the variable names, then we need to use "positional arguments". That is to say the arguments will be written without '-' or '--' as seen below.

#1. Import 'argparse' library
import argparse

#2. Create the parser object
parser = argparse.ArgumentParser()

#3. Add optional, required and positional arguments to the parser
parser.add_argument("x", type=int, help="X numeric value")
parser.add_argument("y", type=int, help="Y numeric value")

#4. Execute to create dictionary collection of the values using .parse_args()
args = vars(parser.parse_args())


# 5. Use the values from the dictionary
x = args['x']
y = args['y']

print(x + y)

When use "positional arguments", some parameter options are not allowed as we will see more later.
Note the major change were on these lines;-

parser.add_argument("x", type=int, help="X numeric value")
parser.add_argument("y", type=int, help="Y numeric value")



What happens if we entered the variables with the names "--x_variable" and "--y_variable"?


The symbol '--' means the longer name of the arguments. Every other thing works just like '-'.


Lets take a deeper look at every step of using the 'argparse' library.


1. Import 'argparse' library
#1. Import 'argparse' library
import argparse
There is no much customization to do here. It is a normal import just like any other python module. It is generally imported as 'import argparse' but you can also shorten the imported name like this: 'import argparse as ap' (this is not a common convention in the python community)


2. Create the parser object
#2. Create the parser object
parser = argparse.ArgumentParser()
There are handful of optional parameters you can include when creating the object. Some mostly used once are description (text that is shown before the help text), epilog (text that is shown after the help text), prog (Sets a custom Name for the script).
#2. Create the parser object
parser = argparse.ArgumentParser(description='text that is shown BEFORE the help text', epilog='text that is shown AFTER the help text', prog='my_add_script')

You could also change the default '-' or '--' character for calling the arguments by including prefix_chars='/' to the options. In this case it will change it to '/'.


3. Add optional, required and positional arguments to the parser
Here you add all the arguments that the script need to use. This is probably the most complicated steps of all and you will most likely spend most of the time customizing this step.
In the sample script, we needed just two arguments, so we added them using the .add_argument() method with several optional parameters as already seen.

#3. Add optional, required or positional arguments to the parser
parser.add_argument("-x", "--x_variable", type=int, required=True, help="X numeric value")
parser.add_argument("-y", "--y_variable", type=int, required=True, help="Y numeric value")

-x: Short name
--x_variable: Long name
type: type of expected input argument
required: the argument is required
help: a help text for the argument

If you want the arguments to be optional, then remove the required flag/option like this.
#3. Add optional arguments to the parser
parser.add_argument("-x", "--x_variable", type=int, help="X numeric value")
parser.add_argument("-y", "--y_variable", type=int, help="Y numeric value")

If you want arguments to be positional, then remove the 'short and long' names like this. And you don't need to enter 'x' or 'y' to call the arguments from the command line.
#3. Add positional arguments to the parser
parser.add_argument("x", type=int, help="X numeric value")
parser.add_argument("y", type=int, help="Y numeric value")


There are many more option (such as: action, nargs, default, choices, metavar, dest, etc) you can use to customize the arguments, see other resources for details.



4. Execute to create dictionary collection of the values using .parse_args()
At this point, if the arguments are correctly entered and they met the conditions from step 3 above then their values should be available in the 'args' object as a dictionary object when we call "parser.parse_args()".

If we don't use the "vars()" method like this: args = parser.parse_args(), then the values are accessed like so: args.name
x = args.x
y = args.y

But if we don't use the "vars()" method like this: args = vars(parser.parse_args()), then the values are accessed like so: args['name']
x = args['x']
y = args['y']



5. Use the values from the dictionary
This is the actual script that will utilize the command line arguments. So, here we simply substitute the variables within the script with the retrieved command line arguments obtained from above.
# 5. Use the values from the dictionary
x = args['x']
y = args['y']

print(x + y)




Further Reading
1) Official Argparse Documentation - Python.org
2)  Python Argparse Cookbook - Marcus Kazmierczak

No comments:

Post a Comment