argparse is Python's standard library for building CLIs. Here's how to use it effectively.
Basic Usage
import argparse
parser = argparse.ArgumentParser(description="Process some files")
parser.add_argument("filename", help="File to process")
parser.add_argument("-v", "--verbose", action="store_true", help="Verbose output")
args = parser.parse_args()
print(args.filename)
print(args.verbose)python script.py data.txt -vPositional Arguments
Required arguments by position:
parser.add_argument("input", help="Input file")
parser.add_argument("output", help="Output file")python script.py input.txt output.txtOptional Arguments
Flags with - or --:
# Boolean flag
parser.add_argument("-v", "--verbose", action="store_true")
# With value
parser.add_argument("-n", "--count", type=int, default=10)
# Required optional
parser.add_argument("-c", "--config", required=True)Argument Types
# Integer
parser.add_argument("-n", type=int)
# Float
parser.add_argument("-r", "--rate", type=float)
# File (opens automatically)
parser.add_argument("-f", type=argparse.FileType("r"))
# Path validation
from pathlib import Path
parser.add_argument("-d", type=Path)Choices
Restrict to specific values:
parser.add_argument(
"--format",
choices=["json", "csv", "xml"],
default="json"
)
parser.add_argument(
"--level",
type=int,
choices=range(1, 11) # 1-10
)Multiple Values
# Fixed number
parser.add_argument("files", nargs=2)
# One or more
parser.add_argument("files", nargs="+")
# Zero or more
parser.add_argument("files", nargs="*")
# Optional positional
parser.add_argument("output", nargs="?", default="out.txt")Actions
# Store True/False
parser.add_argument("-v", action="store_true")
parser.add_argument("--no-cache", action="store_false", dest="cache")
# Count occurrences
parser.add_argument("-v", action="count", default=0)
# -v -> 1, -vv -> 2, -vvv -> 3
# Append to list
parser.add_argument("-i", "--include", action="append")
# -i a -i b -> ["a", "b"]
# Store constant
parser.add_argument("--debug", action="store_const", const=10)Default Values
parser.add_argument("-n", type=int, default=100)
parser.add_argument("--name", default="world")
# Environment variable fallback
import os
parser.add_argument(
"--api-key",
default=os.environ.get("API_KEY")
)Help Text
parser = argparse.ArgumentParser(
description="Process data files",
epilog="Example: %(prog)s data.csv -o output.json"
)
parser.add_argument(
"-o", "--output",
metavar="FILE",
help="Output file (default: stdout)"
)Subcommands
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(dest="command")
# 'init' subcommand
init_parser = subparsers.add_parser("init", help="Initialize project")
init_parser.add_argument("name")
# 'build' subcommand
build_parser = subparsers.add_parser("build", help="Build project")
build_parser.add_argument("-o", "--output", default="dist")
args = parser.parse_args()
if args.command == "init":
print(f"Initializing {args.name}")
elif args.command == "build":
print(f"Building to {args.output}")python cli.py init myproject
python cli.py build -o ./buildMutually Exclusive
group = parser.add_mutually_exclusive_group()
group.add_argument("-v", "--verbose", action="store_true")
group.add_argument("-q", "--quiet", action="store_true")Argument Groups
parser = argparse.ArgumentParser()
input_group = parser.add_argument_group("Input options")
input_group.add_argument("-i", "--input")
input_group.add_argument("-f", "--format")
output_group = parser.add_argument_group("Output options")
output_group.add_argument("-o", "--output")
output_group.add_argument("--compress", action="store_true")Config File Pattern
import argparse
import json
def load_config(path):
with open(path) as f:
return json.load(f)
parser = argparse.ArgumentParser()
parser.add_argument("-c", "--config", type=load_config, default={})
parser.add_argument("--name")
args = parser.parse_args()
# Config file provides defaults, CLI overrides
config = args.config
if args.name:
config["name"] = args.nameComplete Example
#!/usr/bin/env python3
import argparse
import sys
def main():
parser = argparse.ArgumentParser(
description="Convert files between formats",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Examples:
%(prog)s input.csv -o output.json
%(prog)s data.xml --format yaml -v
"""
)
parser.add_argument("input", help="Input file")
parser.add_argument(
"-o", "--output",
help="Output file (default: stdout)"
)
parser.add_argument(
"-f", "--format",
choices=["json", "yaml", "csv"],
default="json",
help="Output format (default: json)"
)
parser.add_argument(
"-v", "--verbose",
action="count",
default=0,
help="Increase verbosity"
)
parser.add_argument(
"--version",
action="version",
version="%(prog)s 1.0.0"
)
args = parser.parse_args()
if args.verbose >= 2:
print(f"Debug: {args}")
# Process files...
process(args.input, args.output, args.format)
if __name__ == "__main__":
main()Quick Reference
import argparse
parser = argparse.ArgumentParser(description="...")
# Positional
parser.add_argument("name")
# Optional
parser.add_argument("-n", "--name", default="value")
# Boolean
parser.add_argument("-v", action="store_true")
# With type
parser.add_argument("-n", type=int)
# Choices
parser.add_argument("--fmt", choices=["a", "b"])
# Multiple values
parser.add_argument("files", nargs="+")
# Parse
args = parser.parse_args()
print(args.name)argparse handles the boring parts of CLI building—parsing, validation, help text. Focus on your logic.
React to this post: