The Best Way to Make Command-line Interfaces in Python

How to write easy-to-use, intuitive Python programs

Command-line interface (CLI):

A command-line interface or command language interpreter, also known as a command-line user interface, console user interface and character user interface, is a means of interacting with a computer program where the user issues a command to the program in the form of successive lines of text.

You can make your program powerful and interactive by creating a command-line interface (CLI). A CLI allows you to take in command-line arguments (information that follows the program’s name on the command line of the operating system) to add additional features to your program, making your code both easy to use and flexible. Depending on the program, these arguments can be used to add additional features such as viewing help documentation, specifying an output file, or enabling test features that may be buggy for normal use.

When I first started programming in Python, I almost exclusively collected user input interactively like this:

def main():
first = input(“Enter your first name:”)
last = input(“Enter your last name:”)
print(first + ' ' + last)

While this code is fine for simple scripts, it is problematic for a few reasons. For starters, this code is not flexible. When a user runs this program, they are restricted to only a single set of defined rules. For example, what if instead of printing to the console, I wanted to log output to a text file? As a new user, how do I figure out how the program works? As a developer, you can create a command-line interface to offer a solution to these problems.

Important considerations

When creating a CLI, it is important to consider the following:

  1. Required arguments: What arguments are absolutely necessary in order for the program to run? For example, if I am writing a program to scrape a webpage a required argument could be the page’s domain.
  2. Documentation: It is important to write out the function of each option and argument so that a new user can figure out how your program works.
  3. Handle error cases: Let the user know exactly what went wrong and where
  4. Runtime status: If the task does not complete instantly, you should print out the current progress

Reading arguments using argparse

Argparse is a Python standard library module for parsing command-line arguments. You as the programmer can define the arguments that are to be taken and argparse will figure out how to parse those out of sys.argv (a list in Python, which contains the command-line arguments passed to the script, learn more here). Argparse also automatically generates help and usage messages and outputs errors when users give the program invalid arguments. It is very simple to use and makes it very easy to write intuitive CLI’s.

To get started, create a new file called test_cli.py and import the module and initialize a new parser:

import argparse
parser = argparse.ArgumentParser()
parser.parse_args()

Now run the code with the--help option:

python3 test_cli.py --help

You should receive a nice default help message like this:

usage: test_cli.py [-h]
optional arguments:
-h, --help show this help message and exit

Congratulations you just made your first command-line interface!

Now let’s add a welcome message to briefly let your user knows what the program does:

welcome = "Practicing creating interactive command-line interfaces"
parser = argparse.ArgumentParser(description=welcome)
parser.parse_args()

Now run the program with the -h flag. You should be able to see your fancy welcome message.

Now let’s do something more useful.

Adding Arguments

Suppose we are writing a program to scrape a webpage. Some arguments we may need are the domain of the webpage --domain or -d , the option to log output to an out file --ofile or -o , and perhaps the option to print a specific number of lines of output to the console --lines or -l. For this example, we will make the domain argument required, while the ofile and lines arguments will be optional.

We can easily add additional arguments to an argparse CLI by using .add_argument which will let us define usage details. We can add the required argument --domain as such:

parser.add_argument('--domain', '-d', required=True, help='domain name of the website you want to scrape. i.e. “https://ahadsheriff.com"')

Now run the program with the -h argument to see the documentation you wrote!

Since --domain is a required argument, try running the program without any flags and you will be treated to the following message:

usage: test_cli.py [-h] --domain DOMAIN
test_cli.py: error: the following arguments are required: --domain/-d

It works!

Time to add our additional arguments using argparse. If you don’t specify which arguments are required, argparse will assume they are optional. You can also set the type of an argument, for --lines we will take an integer. There are other useful options you can set for .add_argument— such as action= — which you can learn more about in the official argparse documentation here.

parser.add_argument('--ofile', '-o', help='define output file to save results of stdout. i.e. "output.txt"')
parser.add_argument('--lines', '-l', help='number of lines of output to print to the console"', type=int)

Now test your code to make sure everything is working properly. A simple way to do this is by storing the values of the arguments as variables, and then printing these values.

args = parser.parse_args()
domain = args.domain
ofile = args.ofile
lines = args.lines
print("domain:", domain)
print("output file:", ofile)
print("lines:", lines)

Note: optional arguments are stored as None by default while not in use.

Here is all my code:

In Conclusion

While this is not a comprehensive guide, it should be enough to get you thinking about command-line interfaces and improving the user experience of your scripts. After all, what’s the point of code if nobody is able to use it. If you have additional recommendations, tips, or resources, please share in the comments!


Thanks for reading! If you enjoyed it, be sure to smash that follow button :) Also be sure to check out my website, Twitter, LinkedIn, and Github.