7 Levels of Building Python Command Line Interfaces
Run your Python scripts like bash commands
Writing Python scripts to create command line interfaces (CLIs) is a widely used technique for DevOps and backend development.
The key to Python’s CLI implementation is the built-in module argparse
. It provides all the functionality you need and allows you to use a Python script as a command bash
.
This article will introduce some important points of creating a CLI with Python at 7 difficulty levels.
1. Launch the basic command line interface with the argparse module
First of all, let’s create a file called test.py
and make a simple argument parser:
import argparse parser = argparse.ArgumentParser() parser.parse_args()
Once we’ve defined this parser, we can now get arguments from the command line. Each instance ArgumentParser
contains parameter --help
(or -h
as a shortcut) to display useful information.
$ python test.py --help usage: test.py [-h]
optional arguments: -h, --help show this help message and exit
However, because we didn’t define any other arguments, the following input will throw an error:
$ python test.py 9 usage: test.py [-h] test.py: error: unrecognized arguments: 9
2. Define positional arguments
In teams bash
there are two types of arguments. One is positional, the other is optional.
For example, the command cp
has two positional arguments:
$ cp source_file dest_file
source_file
specifies the sources of the copied file. And the argument dest_file
specifies the location to copy the file.
We can also define a positional argument for our Python command line interface:
import argparse parser = argparse.ArgumentParser() parser.add_argument("num", type=int) args = parser.parse_args() print(args.num**2)
As you can see from the code above, we have defined the argument name as num
and specified its type as int
.
Now, if the input from the terminal is a valid integer, our Python script will print its square:
$ python test.py 9 81
3. Add more useful information and description
Like many Linux commands, a good CLI should provide users with enough information with the option --help
.
To this end, we can specify special information for the corresponding functions of the module. argparse
.
import argparse parser = argparse.ArgumentParser(prog='get_square',description='A CLI to calculate the square of an integer.') parser.add_argument("num", type=int, help='An integer that needs to get the square value.') args = parser.parse_args() print(args.num**2)
As shown above, we have added program and description information to the instance ArgumentParser
to give it a name and a detailed description. Moreover, we have given the functions add_argument()
help message so our users know what this argument is for.
Now let’s look at the output of the option again -h
:
$ python test.py -h usage: get_square [-h] num
A CLI to calculate the square of an integer.
positional arguments: num An integer that needs to get the square value.
optional arguments: -h, --help show this help message and exit
It’s more convenient and informative, isn’t it? 🙂
4. Define optional arguments
In addition to positional arguments, many command-line interfaces also require optional arguments.
Built-in option --help
all instances ArgumentParser
is an optional argument. We can add one more to the previous example:
import argparse parser = argparse.ArgumentParser(prog='get_square',description='A CLI to calculate the square of an integer.') parser.add_argument("num", type=int, help='An integer that needs to get the square value.') parser.add_argument('--verbose',help='Print more info.') args = parser.parse_args() if args.verbose: print(f'The square of {args.num} is {args.num**2}') else: print(args.num**2)
The above program has added an optional argument named:
--verbose
. If there is a value for this argument, the program will print more detailed information for the calculation.
Now let’s try to use it:
$ python test.py 9 --verbose 1 The square of 9 is 81
$ python test.py 9 --verbose 90908 The square of 9 is 81
$ python test.py 9 --verbose usage: get_square [-h] [--verbose VERBOSE] num get_square: error: argument --verbose: expected one argument
The annoying problem is that we have to provide a value for this option in order for it to work, no matter what the value is. If there is no value at all, as shown above, an error message will appear.
This is due to the fact that args.verbose
has the meaning None
if we use it directly without assigning any value to it.
It’s not as convenient as other Linux commands. So we need to optimize it through parameters action
.
5. Define Special Actions for Optional Arguments
Let’s change this line of code a bit:
parser.add_argument('--verbose',help='Print more info.', action='store_true')
Parameter action
functions add_argument()
can specify how to handle the values of this option.
In our case store_true
means that if a parameter is specified, the program will default to True
For args.verbose
.
And then execute the script with the option --verbose
directly:
$ python test.py 9 --verbose The square of 9 is 81
Apart from store_true
or store_false
Python also provides other parameter options action
. Let’s try a few:
– Use “store_const” action
We can use the parameter store_const
as an action and assign const
optional argument:
parser.add_argument('--verbose',help='Print more info.', action='store_const', const=1)
Therefore, the value args.verbose
will always be 1.
Parameter count
counts the number of times an optional argument occurs. Let’s edit our code and try:
import argparse parser = argparse.ArgumentParser(prog='get_square',description='A CLI to calculate the square of an integer.') parser.add_argument("num", type=int, help='An integer that needs to get the square value.') parser.add_argument('--verbose',help='Print more info.', action='count') args = parser.parse_args() if args.verbose==2: print(f'The square of {args.num} is {args.num**2}') elif args.verbose==1: print(f"{args.num}^2 == {args.num**2}") else: print(args.num**2)
During this time, we can determine how detailed the output will be by the number of options. --verbose
:
$ python test.py 9 --verbose --verbose The square of 9 is 81 $ python test.py 9 --verbose 9^2 == 81 $ python test.py 9 81
– Use “append” action
Action append
saves the list and adds each value of the argument to the list. In some cases, it will be useful to store multiple values of an optional argument.
To use it, change the following line of the previous Python code:
parser.add_argument('--verbose',help='Print more info.', action='append')
Now we can add multiple argument values --verbose
:
$ python test.py 9 --verbose 2 --verbose 3 --verbose 5 The verbose values are ['2', '3', '5']. The square of 9 is 81
6. Define Labels for Optional Arguments
A little boring to type many times --verbose
. Like a shortcut -h
for option --help
. We can also define a label for our option --verbose
in the following way:
parser.add_argument('-v','--verbose',help='Print more info.', action='count')
After label definition -v
we can use it directly:
$ python test.py 9 -vv The square of 9 is 81 $ python test.py 9 -v 9^2 == 81
7. Working with files on the command line
Module argparse
can also handle file type arguments, making it convenient to perform some basic file operations through command line interfaces.
– Reading a file via command line
If we want to display the contents of a file line by line on the terminal, we can write a Python script like this:
import argparse
parser = argparse.ArgumentParser() parser.add_argument('f', type=argparse.FileType('r')) args = parser.parse_args()
for line in args.f: print(line.strip())
Now let’s execute this Python script on the terminal and pass test.txt
as a file type argument:
$ python test.py test.txt Yang is writing a post. Yang is writing on Medium.
As shown above, the file test.txt
consists of two lines of sentences. They were correctly printed to the terminal using our Python script.
– Write data to file via command line
To write data to a file, we need to change the statement from r
on w
:
import argparse
parser = argparse.ArgumentParser() parser.add_argument('f', type=argparse.FileType('w')) args = parser.parse_args()
f = args.f f.write('Yang is writing') f.close()
The above code will write the sentence “Ian is writing” to the file assigned through the command line interface. Its usage is as follows:
$ python test.py test.txt
After executing the above command, the “test.txt” file will contain one line of the sentence “Ian writes”.
Conclusion
Mastering the module argparse
in Python will help us develop and implement easy-to-use command line interfaces through Python scripting.
When we need a customizable command line interface but don’t bother writing complex bash scripts, this Python module is our best friend. 👍