Hello! Welcome to the next lesson in our Python for DevOps journey.
In our last session, you mastered using the requests library to interact with REST APIs, a vital skill for automating communication between services. We built a Python function to fetch data from the GitHub API, but to get information for a different user, we had to go back and edit the code. This isn't efficient for a tool you want to reuse.
Today, we'll solve that problem by learning how to build professional Command-Line Interfaces (CLIs) for our scripts. This allows us to pass information to our program when we run it, making our tools flexible and powerful.
Today's Learning Outcome: By the end of this lesson, you will be able to describe the purpose of the argparse library and use it to parse basic command-line arguments in a Python script.
1. Why Do We Need argparse?
When you run a command in your terminal, like ls -l or git commit -m "My message", the parts that come after the command name (-l, -m, "My message") are command-line arguments. They control the program's behavior.
Python scripts can also accept these arguments. The simplest way is to use the sys.argv list, which contains all the words from the command line. However, manually processing this list is cumbersome and error-prone. You have to:
- Check if enough arguments were provided.
- Convert strings to numbers or other types.
- Handle optional flags (like
-l). - Write your own help message to explain how to use the script.
This is where Python's built-in argparse module comes in. It automates all of this for you, making your scripts more robust and user-friendly.

The main benefits of using argparse are:
- Automatic Help Messages: It generates a helpful usage message when a user runs your script with
-hor--help. - Error Handling: It provides clear error messages if the user provides invalid arguments.
- Type Conversion: It can automatically convert arguments to the correct data type (e.g., from a string to an integer).
- Structured Parsing: It neatly organizes positional arguments and optional flags.
Getting Started Building a Python CLI With argparse
To see the difference between manual parsing and using argparse, watch the beginning of this video from Real Python. It clearly illustrates the problems that argparse solves.
Watch from the beginning to 2:48. Pay attention to the contrast between parsing sys.argv by hand and the cleaner, more robust approach offered by argparse.
2. The Five Steps of argparse
Using argparse follows a consistent, five-step pattern.
Getting Started Building a Python CLI With argparse
This short clip outlines the five fundamental steps you'll use every time you build a CLI with argparse.
Watch from 2:48 to 3:42 to get a high-level overview of the process.
Here are the five steps:
- Import
argparse. - Create an
ArgumentParserobject. This object will hold all the information necessary to parse the command-line arguments. - Add arguments to the parser using the
add_argument()method. This is where you define what arguments your script accepts. - Parse the arguments by calling the
parse_args()method. This tellsargparseto inspect the command line, check the arguments, and convert them. - Use the arguments in your script. The
parse_args()method returns an object with the argument values as attributes.
Let's see a very basic example that just takes a name and prints a greeting.
# 1. Import the library
import argparse
# 2. Create the parser
parser = argparse.ArgumentParser(description="A simple script that greets the user.")
# 3. Add an argument
# This defines a 'positional' argument named 'name'
parser.add_argument("name", help="The name of the person to greet.")
# 4. Parse the arguments from the command line
args = parser.parse_args()
# 5. Use the parsed argument
# The value is accessed via 'args.name'
print(f"Hello, {args.name}!")
Save this as greeter.py. Now, run it from your terminal:
# Run the script with the required argument
$ python greeter.py "Alice"
Hello, Alice!
# See what happens if you forget the argument
$ python greeter.py
usage: greeter.py [-h] name
greeter.py: error: the following arguments are required: name
# Check out the automatically generated help message
$ python greeter.py -h
usage: greeter.py [-h] name
A simple script that greets the user.
positional arguments:
name The name of the person to greet.
options:
-h, --help show this help message and exit
As you can see, argparse handles the missing argument error and the help message for us!
3. Positional vs. Optional Arguments
argparse supports two main types of arguments.
a) Positional Arguments
These are required arguments that must be provided in a specific order. In our greeter.py example, name is a positional argument.
Let's apply this to the GitHub user script from our last lesson. We'll make the username a positional argument.
Getting Started Building a Python CLI With argparse
This video section gives a practical demonstration of creating a positional argument and shows the benefits of built-in error handling and type conversion.
Watch from 3:42 to 7:30. Note how the script is transformed from using hardcoded values to accepting command-line input, and how argparse handles both missing arguments and type errors gracefully.
Here's how we can modify our get_github_user script:
import argparse
import requests
def get_github_user(username):
url = f"https://api.github.com/users/{username}"
try:
response = requests.get(url, timeout=5)
response.raise_for_status()
user_data = response.json()
print(f"Successfully fetched data for {user_data['name']}")
print(f"Location: {user_data.get('location', 'N/A')}")
print(f"Public Repos: {user_data['public_repos']}")
except requests.exceptions.HTTPError as e:
if e.response.status_code == 404:
print(f"Error: Could not find a GitHub user named '{username}'.")
else:
print(f"HTTP Error: {e}")
except requests.exceptions.RequestException as e:
print(f"An unexpected error occurred: {e}")
# --- Argparse setup ---
parser = argparse.ArgumentParser(description="Fetch GitHub user information.")
parser.add_argument("username", help="The GitHub username to look up.")
args = parser.parse_args()
# --- Main script logic ---
get_github_user(args.username)
Save this as github_user.py and run it:
$ python github_user.py torvalds
Successfully fetched data for Linus Torvalds
Location: Portland, OR
Public Repos: 8
b) Optional Arguments
These arguments are, as the name implies, optional. They are identified by a prefix, either a single dash (-) for a short name or two dashes (--) for a long name. They are often called "flags".
Optional arguments can either be simple on/off switches or take a value.
- Boolean Flag (on/off): Use
action="store_true". This is perfect for a--verboseor--debugflag. If the flag is present, its value isTrue; otherwise, it'sFalse. - Value-taking Flag: This is the default behavior. For example,
--output file.txt.
Let's watch a demonstration of creating these optional arguments.
Getting Started Building a Python CLI With argparse
This clip demonstrates how to define optional arguments, including both long and short versions, default values, and the very common action="store_true" for boolean flags.
Watch from 12:01 to 17:11. Focus on how to define an optional argument with a name like --city, how to set a default value, and how the action="store_true" flag works.
Test your understanding!
You want to add an optional argument to your script called --port that should accept a number. It should have a short version -p. Which of the following add_argument calls is correct?
parser.add_argument("port", "-p", type=int, help="The port number")parser.add_argument("--port", "-p", type=int, help="The port number")parser.add_argument("-p", "--port", type=int, help="The port number")parser.add_argument("--port", type=int, required=True, help="The port number")
Show answer
The correct answer is 3. parser.add_argument("-p", "--port", type=int, help="The port number").
- Optional arguments are defined by their flag names (e.g.,
"-p","--port") as the first arguments toadd_argument(). - Positional arguments (like in option 1) are defined by a name without dashes.
- Option 2 has the long and short flags in the wrong order, which is not conventional.
- Option 4 correctly defines an optional argument, but makes it required, which is possible but not what was asked.
4. Putting It All Together: An Enhanced CLI Tool
Let's enhance our github_user.py script to use both positional and optional arguments. We'll add a --verbose flag to print the entire JSON response.
import argparse
import requests
import json # For pretty-printing the verbose output
def get_github_user(username, verbose=False):
url = f"https://api.github.com/users/{username}"
try:
response = requests.get(url, timeout=5)
response.raise_for_status()
user_data = response.json()
print(f"Successfully fetched data for {user_data['name']}")
print(f"Location: {user_data.get('location', 'N/A')}")
print(f"Public Repos: {user_data['public_repos']}")
# If verbose is True, print the whole dictionary
if verbose:
print("\n--- Verbose Output ---")
print(json.dumps(user_data, indent=4))
except requests.exceptions.HTTPError as e:
if e.response.status_code == 404:
print(f"Error: Could not find a GitHub user named '{username}'.")
else:
print(f"HTTP Error: {e}")
except requests.exceptions.RequestException as e:
print(f"An unexpected error occurred: {e}")
# --- Argparse setup ---
parser = argparse.ArgumentParser(description="Fetch GitHub user information.")
# Positional argument
parser.add_argument("username", help="The GitHub username to look up.")
# Optional boolean flag
parser.add_argument("-v", "--verbose",
action="store_true",
help="Enable verbose output (prints the full JSON response).")
args = parser.parse_args()
# --- Main script logic ---
# Pass the arguments to our function
get_github_user(args.username, args.verbose)
Now you have a much more powerful tool!
# Standard run
$ python github_user.py guido
Successfully fetched data for Guido van Rossum
Location: Bay Area
Public Repos: 41
# Run with the verbose flag
$ python github_user.py guido --verbose
Successfully fetched data for Guido van Rossum
Location: Bay Area
Public Repos: 41
--- Verbose Output ---
{
"login": "gvanrossum",
"id": 289384,
...
"created_at": "2008-10-21T21:20:06Z",
"updated_at": "2023-11-20T21:48:47Z"
}
For more examples and a different perspective, you can also consult this text-based guide.
Mastering Python's argparse: A Comprehensive Guide for ...
This article, 'Mastering Python's argparse', provides clear, concise code examples for the concepts we've discussed, including positional arguments, optional arguments, types, and flags.
Quickly review the sections 'Positional Arguments', 'Optional Arguments', 'Argument Types', and 'Flag Arguments (Boolean Options)'. These provide excellent textual reinforcement of what we've covered.
Conclusion
You've now learned how to transform a simple Python script into a reusable and professional command-line tool. This is a fundamental skill in DevOps, as it allows you to build automation that is easy to run, configure, and share.
Key Takeaways:
argparseis Python's standard library for building command-line interfaces.- It automatically handles error checking and generates help messages (
-h/--help). - Positional arguments are required and defined by their name (e.g.,
parser.add_argument("filename")). - Optional arguments (flags) are not required and are defined by their flag names (e.g.,
parser.add_argument("-v", "--verbose")). - Use
action="store_true"to create simple boolean flags. - The parsed arguments are returned in a namespace object, accessible with dot notation (e.g.,
args.username).
Next Up
In this lesson, we laid the groundwork by learning the tool. In our next and final lesson of this module, we will put this knowledge to practical use by building on today's example to build a simple CLI tool in Python that wraps a previously learned automation task. We will formalize our script, making it a polished and complete utility.