Mathew K Analytics

Lesson 14 · Python standard library deep dive

Python argparse Explained: Build Real CLI Tools | Standard Library #14

Video fourteen of the twenty-five-part series: argparse, for building real, professional command-line interfaces. Positional and optional arguments, types,…

argparse

What you'll learn

Datasets used in this lesson

Save these next to the notebook. In Google Colab, upload them with the 📁 icon on the left first.

📓 Full notebook

Download .ipynb

Python Standard Library Deep-Dive, Video 14: argparse#

  • Video fourteen of the twenty-five-part series: argparse, for building real, professional command-line interfaces.
  • Positional and optional arguments, types, flags, choices, multiple values, subcommands, and auto-generated help.
  • A quick note: every example here calls parse_args with an explicit list, exactly how a real CLI script would be unit tested, so these cells run identically here and in a genuine terminal.
  • Let's get into it.

Part 1: What argparse Offers#

import argparse
parser = argparse.ArgumentParser(description='A demo command-line tool')
print(type(parser))
<class 'argparse.ArgumentParser'>

Part 2: Positional Arguments#

parser = argparse.ArgumentParser()
parser.add_argument('filename')
args = parser.parse_args(['report.csv'])
print(args.filename)
print(args)
report.csv
Namespace(filename='report.csv')
parser = argparse.ArgumentParser()
parser.add_argument('filename')
try:
    parser.parse_args([])
except SystemExit as e:
    print(f'Caught: argparse genuinely called sys.exit with code {e.code}')
Caught: argparse genuinely called sys.exit with code 2
usage: ipykernel_launcher.py [-h] filename
ipykernel_launcher.py: error: the following arguments are required: filename

Part 3: Optional Arguments and Flags#

parser = argparse.ArgumentParser()
parser.add_argument('filename')
parser.add_argument('-v', '--verbose', help='enable verbose output')
args = parser.parse_args(['report.csv', '--verbose', 'yes'])
print(args.filename, args.verbose)
args2 = parser.parse_args(['report.csv'])
print(args2.verbose)
report.csv yes
None

Part 4: Types and Defaults#

parser = argparse.ArgumentParser()
parser.add_argument('--count', type=int, default=1)
parser.add_argument('--rate', type=float, default=1.0)
args = parser.parse_args(['--count', '5', '--rate', '2.5'])
print(args.count, type(args.count))
print(args.rate, type(args.rate))
args2 = parser.parse_args([])
print(args2.count, args2.rate)
5 <class 'int'>
2.5 <class 'float'>
1 1.0

Part 5: Boolean Flags with action='store_true'#

parser = argparse.ArgumentParser()
parser.add_argument('--force', action='store_true')
parser.add_argument('--dry-run', action='store_true')
args = parser.parse_args(['--force'])
print(args.force, args.dry_run)
args2 = parser.parse_args([])
print(args2.force, args2.dry_run)
True False
False False

Part 6: choices and Validation#

parser = argparse.ArgumentParser()
parser.add_argument('--format', choices=['csv', 'json', 'xml'], default='csv')
args = parser.parse_args(['--format', 'json'])
print(args.format)
try:
    parser.parse_args(['--format', 'yaml'])
except SystemExit:
    print('Caught: an invalid choice genuinely got rejected automatically')
json
Caught: an invalid choice genuinely got rejected automatically
usage: ipykernel_launcher.py [-h] [--format {csv,json,xml}]
ipykernel_launcher.py: error: argument --format: invalid choice: 'yaml' (choose from 'csv', 'json', 'xml')

Part 7: nargs - Multiple Values#

parser = argparse.ArgumentParser()
parser.add_argument('--files', nargs='+')
args = parser.parse_args(['--files', 'a.txt', 'b.txt', 'c.txt'])
print(args.files)
print(type(args.files))
parser2 = argparse.ArgumentParser()
parser2.add_argument('--tags', nargs='*', default=[])
print(parser2.parse_args([]).tags)
print(parser2.parse_args(['--tags', 'x', 'y']).tags)
['a.txt', 'b.txt', 'c.txt']
<class 'list'>
[]
['x', 'y']

Part 8: Subcommands#

parser = argparse.ArgumentParser(prog='mytool')
subparsers = parser.add_subparsers(dest='command')
add_parser = subparsers.add_parser('add')
add_parser.add_argument('--value', type=int, required=True)
remove_parser = subparsers.add_parser('remove')
remove_parser.add_argument('--id', type=int, required=True)
args1 = parser.parse_args(['add', '--value', '42'])
print(args1.command, args1.value)
args2 = parser.parse_args(['remove', '--id', '7'])
print(args2.command, args2.id)
add 42
remove 7

Part 9: Help Text and Argument Groups#

parser = argparse.ArgumentParser(
    prog='analyzer',
    description='Analyze a dataset and produce a report'
)
parser.add_argument('input_file', help='path to the input data file')
output_group = parser.add_argument_group('output options')
output_group.add_argument('--output', help='where to write the report')
output_group.add_argument('--format', choices=['pdf', 'html'], default='pdf')
help_text = parser.format_help()
print('input_file' in help_text)
print('output options' in help_text)
print('Analyze a dataset' in help_text)
True
True
True

Part 10: Common Patterns#

def build_parser():
    parser = argparse.ArgumentParser(description='Process a data file')
    parser.add_argument('input_file')
    parser.add_argument('--output', default='output.csv')
    parser.add_argument('--verbose', action='store_true')
    parser.add_argument('--format', choices=['csv', 'json'], default='csv')
    return parser
def main(argv):
    parser = build_parser()
    args = parser.parse_args(argv)
    if args.verbose:
        print(f'Processing {args.input_file} -> {args.output} as {args.format}')
    return 0
exit_code = main(['data.csv', '--verbose', '--format', 'json'])
print(exit_code)
Processing data.csv -> output.csv as json
0

Wrap-Up: What You Learned#

  • argparse parses, validates, and type-converts command-line arguments declaratively.
  • Positional arguments are required by position; optional arguments start with dashes and default to None.
  • type converts raw strings automatically; default supplies a fallback when an argument is omitted.
  • action='store_true' builds a genuine on-off flag with no separate value.
  • choices restricts an argument to a fixed valid set, rejecting anything else automatically.
  • nargs controls how many values an argument consumes: plus, star, or question mark.
  • add_subparsers builds independent sub-commands, each with its own arguments, like git's own commands.
  • Help text and argument groups are auto-generated from descriptions and help strings.
  • A real pattern: a testable build_parser plus main(argv) function, never touching sys.argv directly in tests.
  • That wraps up argparse. Next up: pickle and shelve, for object serialization and simple persistence.

Found this useful?

All lessons, notebooks and datasets here are free. If they helped you, a coffee keeps new lessons coming.