When building Python command-line interfaces (CLI), Python’s argparse module offers a comprehensive solution. You can use argparse to create user-friendly command-line interfaces that parse arguments and options directly from the command line. This tutorial guides you through organizing CLI projects, adding arguments and options, and customizing your CLI’s behavior with argparse.
You’ll also learn about setting up command-line argument parsers, parsing arguments, and implementing advanced features like subcommands and mutually exclusive argument groups. By understanding how argparse handles errors and messages, you can create robust and intuitive CLIs for your Python applications.
By the end of this tutorial, you’ll understand that:
- Command-line interfaces enable interaction with applications through terminals.
- You can create CLIs in Python using the standard library
argparsemodule. argparseparses command-line arguments and generates help messages.- You can customize CLIs with
argparseby defining argument types and actions. - Subcommands and mutually exclusive groups enhance CLI functionality.
To get the most out of this tutorial, you should be familiar with Python programming, including concepts such as object-oriented programming, script development and execution, and Python packages and modules. It’ll also be helpful if you’re familiar with general concepts and topics related to using a command line or terminal.
Get Your Code: Click here to get the working argparse CLI examples from this tutorial so you can adapt them for your own command-line apps.
Take the Quiz: Test your knowledge with our interactive “Build Command-Line Interfaces With Python's argparse” quiz. You’ll receive a score upon completion to help you track your learning progress:
Interactive Quiz
Build Command-Line Interfaces With Python's argparseIn this quiz, you'll test your understanding of creating command-line interfaces (CLIs) in Python using the argparse module. This knowledge is essential for creating user-friendly command-line apps, which are common in development, data science, and systems administration.
Getting to Know Command-Line Interfaces
Since the invention of computers, humans have always needed and found ways to interact and share information with these machines. The information exchange has flowed among humans, computer software, and hardware components. The shared boundary between any two of these elements is generically known as an interface.
In software development, an interface is a special part of a given piece of software that allows interaction between components of a computer system. When it comes to human and software interaction, this vital component is known as the user interface.
You’ll find different types of user interfaces in programming. Probably, graphical user interfaces (GUIs) are the most common today. However, you’ll also find apps and programs that provide command-line interfaces (CLIs) for their users. In this tutorial, you’ll learn about CLIs and how to create them in Python.
Command-Line Interfaces (CLIs)
Command-line interfaces allow you to interact with an application or program through your operating system command line, terminal, or console.
To understand command-line interfaces and how they work, consider this practical example. Say that you have a directory called sample containing three sample files. If you’re on a Unix-like operating system, such as Linux or macOS, go ahead and open a command-line window or terminal in the parent directory and then execute the following command:
$ ls sample/
hello.txt lorem.md realpython.md
The ls Unix command lists the files and subdirectories contained in a target directory, which defaults to the current working directory. The above command call doesn’t display much information about the content of sample. It only displays the filenames on the screen.
Note: If you’re on Windows, then you’ll have an ls command that works similarly to the Unix ls command. However, in its plain form, the command displays a different output:
PS> ls .\sample\
Directory: C:\sample
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 11/10/2022 10:06 AM 88 hello.txt
-a--- 11/10/2022 10:06 AM 2629 lorem.md
-a--- 11/10/2022 10:06 AM 429 realpython.md
The PowerShell ls command issues a table containing detailed information on every file and subdirectory under your target directory. So, the upcoming examples won’t work as expected on Windows systems.
Suppose you want richer information about your directory and its content. In that case, you don’t need to look around for a program other than ls because this command has a full-featured command-line interface with a useful set of options that you can use to customize the command’s behavior.
For example, go ahead and execute ls with the -l option:
$ ls -l sample/
total 24
-rw-r--r--@ 1 user staff 83 Aug 17 22:15 hello.txt
-rw-r--r--@ 1 user staff 2609 Aug 17 22:15 lorem.md
-rw-r--r--@ 1 user staff 428 Aug 17 22:15 realpython.md
The output of ls is quite different now. The command displays much more information about the files in sample, including permissions, owner, group, date, and size. It also shows the total space that these files use on your computer’s disk.
Note: To get a detailed list of all the options that ls provides as part of its CLI, go ahead and run the man ls command in your command line or terminal.
This richer output results from using the -l option, which is part of the Unix ls command-line interface and enables the detailed output format.
Commands, Arguments, Options, Parameters, and Subcommands
Throughout this tutorial, you’ll learn about commands and subcommands. You’ll also learn about command-line arguments, options, and parameters, so you should incorporate these terms into your tech vocabulary:
-
Command: A program or routine that runs at the command line or terminal window. You’ll typically identify a command with the name of the underlying program or routine.
-
Argument: A required or optional piece of information that a command uses to perform its intended action. Commands typically accept one or many arguments, which you can provide as a whitespace-separated or comma-separated list on your command line.
-
Option, also known as flag or switch: An optional argument that modifies a command’s behavior. Options are passed to commands using a specific name, like
-lin the previous example. -
Parameter: An argument that an option uses to perform its intended operation or action.
-
Subcommand: A predefined name that can be passed to an application to run a specific action.
Consider the sample command construct from the previous section:
$ ls -l sample/
In this example, you’ve combined the following components of a CLI:
ls: The command’s name or the app’s name-l: An option, switch, or flag that enables detailed outputssample: An argument that provides additional information to the command’s execution
Now consider the following command construct, which showcases the CLI of Python’s package manager, known as pip:
$ pip install -r requirements.txt
This is a common pip command construct, which you’ve probably seen before. It allows you to install the requirements of a given Python project using a requirements.txt file. In this example, you’re using the following CLI components:
pip: The command’s nameinstall: The name of a subcommand ofpip-r: An option of theinstallsubcommandrequirements.txt: An argument, specifically a parameter of the-roption
Now you know what command-line interfaces are and what their main parts or components are. It’s time to learn how to create your own CLIs in Python.
Getting Started With CLIs in Python: sys.argv vs argparse
Python comes with a couple of tools that you can use to write command-line interfaces for your programs and apps. If you need to quickly create a minimal CLI for a small program, then you can use the argv attribute from the sys module. This attribute automatically stores the arguments that you pass to a given program at the command line.
Using sys.argv to Build a Minimal CLI
As an example of using argv to create a minimal CLI, say that you need to write a small program that lists all the files in a given directory, similar to what ls does. In this situation, you can write something like this:
ls_argv.py
import sys
from pathlib import Path
if (args_count := len(sys.argv)) > 2:
print(f"One argument expected, got {args_count - 1}")
raise SystemExit(2)
elif args_count < 2:
print("You must specify the target directory")
raise SystemExit(2)
target_dir = Path(sys.argv[1])
if not target_dir.is_dir():
print("The target directory doesn't exist")
raise SystemExit(1)
for entry in target_dir.iterdir():
print(entry.name)
This program implements a minimal CLI by manually processing the arguments provided at the command line, which are automatically stored in sys.argv. The first item in sys.argv is always the program’s name. The second item will be the target directory. The app shouldn’t accept more than one target directory, so the args_count must not exceed 2.
After checking the content of sys.argv, you create a pathlib.Path object to store the path to your target directory. If this directory doesn’t exist, then you inform the user and exit the app. The for loop lists the directory content, one entry per line.
If you run the script from your command line, then you’ll get the following results:
$ python ls_argv.py sample/
hello.txt
lorem.md
realpython.md
$ python ls_argv.py
You must specify the target directory
$ python ls_argv.py sample/ other_dir/
One argument expected, got 2
$ python ls_argv.py non_existing/
The target directory doesn't exist
Your program takes a directory as an argument and lists its content. If you run the command without arguments, then you get an error message. If you run the command with more than one target directory, you also get an error. Running the command with a nonexistent directory produces another error message.
Even though your program works okay, parsing command-line arguments manually using the sys.argv attribute isn’t a scalable solution for more complex CLI apps. If your app needs to take many more arguments and options, then parsing sys.argv will be a complex and error-prone task. You need something better, and you get it in Python’s argparse module.
Creating a CLI With argparse
A much more convenient way to create CLI apps in Python is using the argparse module, which comes in the standard library. This module was first released in Python 3.2 with PEP 389 and is a quick way to create CLI apps in Python without installing a third-party library, such as Typer or Click.
This module was released as a replacement for the older getopt and optparse modules because they lacked some important features.
Python’s argparse module allows you to:
- Parse command-line arguments and options
- Take a variable number of parameters in a single option
- Provide subcommands in your CLIs
These features turn argparse into a powerful CLI framework that you can confidently rely on when creating your CLI applications. To use Python’s argparse, you’ll need to follow four straightforward steps:
- Import
argparse. - Create an argument parser by instantiating
ArgumentParser. - Add arguments and options to the parser using the
.add_argument()method. - Call
.parse_args()on the parser to get theNamespaceof arguments.
As an example, you can use argparse to improve your ls_argv.py script. Go ahead and create ls.py with the following code:
ls.py v1
import argparse
from pathlib import Path
parser = argparse.ArgumentParser()
parser.add_argument("path")
args = parser.parse_args()
target_dir = Path(args.path)
if not target_dir.exists():
print("The target directory doesn't exist")
raise SystemExit(1)
for entry in target_dir.iterdir():
print(entry.name)
Your code has changed significantly with the introduction of argparse. The most notable difference from the previous version is that the conditional statements to check the arguments provided by the user are gone. That’s because argparse automatically checks the presence of arguments for you.
In this new implementation, you first import argparse and create an argument parser. To create the parser, you use the ArgumentParser class. Next, you define an argument called path to get the user’s target directory.
The next step is to call .parse_args() to parse the input arguments and get a Namespace object that contains all the user’s arguments. Note that now the args variable holds a Namespace object, which has a property for each argument that’s been gathered from the command line.
In this example, you only have one argument, called path. The Namespace object allows you to access path using the dot notation on args. The rest of your code remains the same as in the first implementation.
Now go ahead and run this new script from your command line:
$ python ls.py sample/
lorem.md
realpython.md
hello.txt
$ python ls.py
usage: ls.py [-h] path
ls.py: error: the following arguments are required: path
$ python ls.py sample/ other_dir/
usage: ls.py [-h] path
ls.py: error: unrecognized arguments: other_dir/
$ python ls.py non_existing/
The target directory doesn't exist
The first command prints the same output as your original script, ls_argv.py. In contrast, the second command displays output that’s quite different from in ls_argv.py. The program now shows a usage message and issues an error telling you that you must provide the path argument.
In the third command, you pass two target directories, but the app isn’t prepared for that. Therefore, it shows the usage message again and throws an error letting you know about the underlying problem.
Finally, if you run the script with a nonexistent directory as an argument, then you get an error telling you that the target directory doesn’t exist, so the program can’t do its work.
A new implicit feature is now available to you. Now your program accepts an optional -h flag. Go ahead and give it a try:
$ python ls.py -h
usage: ls.py [-h] path
positional arguments:
path
options:
-h, --help show this help message and exit
Great, now your program automatically responds to the -h or --help flag, displaying a help message with usage instructions for you. That’s a really neat feature, and you get it for free by introducing argparse into your code!
With this quick introduction to creating CLI apps in Python, you’re now ready to dive deeper into the argparse module and all its cool features.
Creating Command-Line Interfaces With Python’s argparse
You can use the argparse module to write user-friendly command-line interfaces for your applications and projects. This module allows you to define the arguments and options that your app will require. Then argparse will take care of parsing those arguments and options of sys.argv for you.
Another cool feature of argparse is that it automatically generates usage and help messages for your CLI apps. The module also issues errors in response to invalid arguments and more.
Before diving deeper into argparse, you need to know that the module’s documentation recognizes two different types of command-line arguments:
- Positional arguments, which you know as arguments
- Optional arguments, which you know as options, flags, or switches
In the ls.py example, path is a positional argument. Such an argument is called positional because its relative position in the command construct defines its purpose.
Optional arguments aren’t mandatory. They allow you to modify the behavior of the command. In the ls Unix command example, the -l flag is an optional argument, which makes the command display a detailed output.
With these concepts clear, you can kick things off and start building your own CLI apps with Python and argparse.
Creating a Command-Line Argument Parser
The command-line argument parser is the most important part of any argparse CLI. All the arguments and options that you provide at the command line will pass through this parser, which will do the hard work for you.
To create a command-line argument parser with argparse, you need to instantiate the ArgumentParser class:
>>> from argparse import ArgumentParser
>>> parser = ArgumentParser()
>>> parser
ArgumentParser(
prog='',
usage=None,
description=None,
formatter_class=<class 'argparse.HelpFormatter'>,
conflict_handler='error',
add_help=True
)
The constructor of ArgumentParser takes many different arguments that you can use to tweak several features of your CLIs. All of its arguments are optional, so the most bare-bones parser that you can create results from instantiating ArgumentParser without any arguments.
You’ll learn more about the arguments to the ArgumentParser constructor throughout this tutorial, particularly in the section on customizing your argument parser. For now, you can tackle the next step in creating a CLI with argparse. That step is to add arguments and options through the parser object.
Adding Arguments and Options
To add arguments and options to an argparse CLI, you’ll use the .add_argument() method of your ArgumentParser instance. Note that the method is common for arguments and options. Remember that in the argparse terminology, arguments are called positional arguments, and options are known as optional arguments.
The first argument to the .add_argument() method sets the difference between arguments and options. This argument is identified as either name or flag. So, if you provide a name, then you’ll be defining an argument. In contrast, if you use a flag, then you’ll add an option.
You’ve already worked with command-line arguments in argparse. So, consider the following enhanced version of your custom ls command, which adds an -l option to the CLI:
ls.py v2
1import argparse
2import datetime
3from pathlib import Path
4
5parser = argparse.ArgumentParser()
6
7