Skip to main content

Python CLI Applications

Command Line Interface (CLI) applications are programs that users interact with through a terminal or command prompt rather than a graphical user interface. They're essential tools in DevOps workflows, allowing engineers to automate tasks, process data, and administer systems efficiently.

Why Build CLI Applications in Python?​

Python is an excellent choice for building CLI applications because:

  • Readability: Python's clean syntax makes command-line tools easier to maintain
  • Cross-platform: Python CLI apps work on Windows, macOS, and Linux
  • Rich ecosystem: Many libraries exist to simplify CLI development
  • Integration capabilities: Python can interact with system commands and other tools

Basic CLI Structure​

Let's start with a simple CLI application structure:

python
#!/usr/bin/env python3

def main():
print("Hello from my CLI application!")

if __name__ == "__main__":
main()

Save this as simple_cli.py, make it executable (chmod +x simple_cli.py on Unix-based systems), and run it:

bash
$ ./simple_cli.py
Hello from my CLI application!

Command-Line Arguments​

Most CLI applications need to accept command-line arguments. Python's standard library includes the argparse module for this purpose.

Using argparse​

Here's a basic example:

python
#!/usr/bin/env python3
import argparse

def main():
parser = argparse.ArgumentParser(description="A simple CLI application")
parser.add_argument("name", help="The name to greet")
parser.add_argument("--loud", "-l", action="store_true", help="Print in uppercase")

args = parser.parse_args()

greeting = f"Hello, {args.name}!"

if args.loud:
greeting = greeting.upper()

print(greeting)

if __name__ == "__main__":
main()

Running this script with arguments:

bash
$ ./greet_cli.py Alice
Hello, Alice!

$ ./greet_cli.py Bob --loud
HELLO, BOB!

$ ./greet_cli.py --help
usage: greet_cli.py [-h] [--loud] name

A simple CLI application

positional arguments:
name The name to greet

optional arguments:
-h, --help show this help message and exit
--loud, -l Print in uppercase

Building DevOps CLI Tools​

DevOps engineers frequently build CLI tools to automate tasks. Let's create a simple tool that checks the status of services:

python
#!/usr/bin/env python3
import argparse
import subprocess
import sys

def check_service(service_name):
"""Check if a systemd service is running."""
try:
result = subprocess.run(
["systemctl", "is-active", service_name],
capture_output=True,
text=True,
check=False
)
status = result.stdout.strip()

if status == "active":
print(f"✅ Service {service_name} is running")
return True
else:
print(f"❌ Service {service_name} is not running (status: {status})")
return False
except Exception as e:
print(f"Error checking service {service_name}: {e}")
return False

def main():
parser = argparse.ArgumentParser(description="Check status of system services")
parser.add_argument("services", nargs="+", help="Service names to check")
parser.add_argument("--restart-failed", action="store_true",
help="Attempt to restart failed services")

args = parser.parse_args()

failed_services = []

for service in args.services:
if not check_service(service):
failed_services.append(service)

if failed_services and args.restart_failed:
print("\nAttempting to restart failed services...")
for service in failed_services:
print(f"Restarting {service}...")
subprocess.run(["sudo", "systemctl", "restart", service], check=False)
check_service(service)

if __name__ == "__main__":
main()

This script:

  1. Accepts a list of service names to check
  2. Checks if each service is running
  3. Optionally attempts to restart failed services

Example usage:

bash
$ ./check_services.py nginx postgresql
✅ Service nginx is running
❌ Service postgresql is not running (status: inactive)

$ ./check_services.py nginx postgresql --restart-failed
✅ Service nginx is running
❌ Service postgresql is not running (status: inactive)

Attempting to restart failed services...
Restarting postgresql...
✅ Service postgresql is running

Advanced CLI Libraries​

While argparse is included in the standard library, more powerful libraries can enhance your CLI applications.

Click​

Click is a powerful and intuitive package for creating beautiful command line interfaces:

python
#!/usr/bin/env python3
import click
import os

@click.group()
def cli():
"""File operations utility."""
pass

@cli.command()
@click.argument('path')
@click.option('--size', '-s', is_flag=True, help='Show file size')
@click.option('--count', '-c', is_flag=True, help='Show file count')
def analyze(path, size, count):
"""Analyze the specified directory."""
if not os.path.exists(path):
click.echo(f"Error: {path} does not exist")
return

if not os.path.isdir(path):
click.echo(f"Error: {path} is not a directory")
return

if size:
total_size = sum(os.path.getsize(os.path.join(path, f))
for f in os.listdir(path) if os.path.isfile(os.path.join(path, f)))
click.echo(f"Total size: {total_size/1024:.2f} KB")

if count:
file_count = len([f for f in os.listdir(path) if os.path.isfile(os.path.join(path, f))])
click.echo(f"File count: {file_count}")

if not size and not count:
click.echo(f"Directory: {path}")
for item in os.listdir(path):
click.echo(f"- {item}")

if __name__ == '__main__':
cli()

Example usage:

bash
$ ./file_tool.py analyze ./documents --size
Total size: 2345.78 KB

$ ./file_tool.py analyze ./documents --count
File count: 17

$ ./file_tool.py analyze ./documents
Directory: ./documents
- report.pdf
- notes.txt
- meeting_minutes.docx
- ...

Typer​

Typer is a library for building CLI applications that uses Python type hints:

python
#!/usr/bin/env python3
import typer
import requests
from typing import Optional
import time

app = typer.Typer()

@app.command()
def ping(
url: str,
count: int = 3,
interval: float = 1.0,
timeout: Optional[float] = 5.0
):
"""Ping a website and check response time."""
successful = 0
times = []

typer.echo(f"Pinging {url} {count} times...")

for i in range(count):
try:
start_time = time.time()
response = requests.get(url, timeout=timeout)
end_time = time.time()

if response.status_code == 200:
elapsed = (end_time - start_time) * 1000 # ms
times.append(elapsed)
successful += 1
typer.echo(f"Ping {i+1}: Success - Response time: {elapsed:.2f}ms")
else:
typer.echo(f"Ping {i+1}: Failed - Status code: {response.status_code}")
except requests.exceptions.RequestException as e:
typer.echo(f"Ping {i+1}: Error - {str(e)}")

if i < count - 1:
time.sleep(interval)

typer.echo(f"\nSummary:")
typer.echo(f"- Successful: {successful}/{count} ({successful/count*100:.1f}%)")

if times:
typer.echo(f"- Avg response time: {sum(times)/len(times):.2f}ms")
typer.echo(f"- Min response time: {min(times):.2f}ms")
typer.echo(f"- Max response time: {max(times):.2f}ms")

if __name__ == "__main__":
app()

Example usage:

bash
$ ./ping_tool.py ping https://www.example.com --count 4 --interval 0.5
Pinging https://www.example.com 4 times...
Ping 1: Success - Response time: 145.23ms
Ping 2: Success - Response time: 138.67ms
Ping 3: Success - Response time: 152.11ms
Ping 4: Success - Response time: 141.89ms

Summary:
- Successful: 4/4 (100.0%)
- Avg response time: 144.48ms
- Min response time: 138.67ms
- Max response time: 152.11ms

Best Practices for Python CLI Applications​

  1. User-friendly error handling: Provide clear error messages when something goes wrong
  2. Progress feedback: For long-running operations, show progress bars or status updates
  3. Colorful output: Use libraries like colorama or rich to make output more readable
  4. Documentation: Include help text for all commands and options
  5. Configuration files: Allow users to set defaults in config files
  6. Testing: Write tests for your CLI applications
  7. Packaging: Make your CLI tools installable with pip

Making Your CLI Application Installable​

To make your CLI tool available system-wide, create a proper Python package:

my_tool/
├── pyproject.toml
├── README.md
└── src/
└── my_tool/
├── __init__.py
└── main.py

In your pyproject.toml:

toml
[build-system]
requires = ["setuptools>=42", "wheel"]
build-backend = "setuptools.build_meta"

[project]
name = "my-tool"
version = "0.1.0"
description = "A helpful CLI tool"
authors = [
{name = "Your Name", email = "your.email@example.com"}
]
readme = "README.md"
requires-python = ">=3.7"
dependencies = [
"requests>=2.25.1",
"typer>=0.4.0",
]

[project.scripts]
my-tool = "my_tool.main:app"

After installing this package with pip install -e ., you can run my-tool from anywhere in your system.

Summary​

Python CLI applications are powerful tools for DevOps engineers, allowing automation of various tasks through simple command-line interfaces. We've covered:

  • Basic CLI application structure
  • Using argparse for processing command-line arguments
  • Building practical DevOps tools
  • Advanced CLI libraries like Click and Typer
  • Best practices and packaging for distribution

These skills enable you to create efficient, user-friendly tools that can streamline your DevOps workflows and automate repetitive tasks.

Additional Resources​

Exercises​

  1. Build a CLI tool that monitors disk usage and sends an alert when space is low
  2. Create a backup utility that takes directory paths as arguments
  3. Develop a multi-command application for managing Docker containers
  4. Extend the service checking tool to generate a report in multiple formats (text, JSON, HTML)
  5. Build a deployment script that takes configuration options and updates a service


If you spot any mistakes on this website, please let me know at feedback@compilenrun.com. I’d greatly appreciate your feedback! :)