For the average computer user, the command line is a mysterious place reserved for hackers and nefarious government types who spy on our communications. Plain text against a stark black background elicits images of Matthew Broderick playing "Global Thermonuclear War" against a military supercomputer or Robert Redford and his crew of "Sneakers" facing off against Ben Kingsley's evil genius. But for me as a fledgling Python programmer, learning basic command-line operations was a game-changer that made me feel less like an imposter. Then when I learned I could write my own command-line interfaces (ok, so while they're not technically "cool looking interfaces," they really are quite cool), or CLIs, I began to feel more like an actual programmer. And thus began my love affair with command-line programs.
I've written quite a few of these little apps. Some are just for fun. From a word unscrambler that helps me cheat on Word Jumble games to a one-word command that retrieves quotes from everyone's favorite Parks & Recreation curmudgeon, Ron Swanson, many of my CLIs do mostly pointless things. Others, however, are useful. Frustrated with the multiple clicks required to pull up contact info in my Outlook, one of my CLIs is just a quick contact lookup--I type % contact {name}
and bam! There's Bob's phone number. I work as a real estate paralegal and another of my CLIs retrieves current mortgage interest rates. Want to know the average 30-year FHA interest rate? Type % rates 30fha
and there it is. The point is CLIs give us options for almost unlimited fun and productivity.
Fortunately, several great Python libraries make writing CLIs quick, easy, and in some cases, even attractive. I primarily use two. Argparse is part of the Python standard library. For the most part, I try to use the standard library in my code whenever I can; the less I have to depend on third-party libraries, the better. Argparse produces a perfectly functional if bland-looking, CLI. It requires a few more lines of code than some other solutions, but it's a solid choice.
My other go-to CLI library is Typer. Harnessing the power of type hints and Will McGugan's incredible Rich library, Typer allows you to produce CLIs that are both powerful and attractive. There's a small learning curve, especially if you're new to typing and type hints, but the little extra effort is worth it.
Finally, I recently came upon a new library that appears to be perfect for whipping up quick and dirty CLIs: Arguably. With a simple decorator, Arguably turns any function into a working CLI. If you need to access some functions quickly with minimal effort, Arguably fits the bill. As of the time of this writing, Arguably has been on pypi for a little less than a month, so it will be fun to see what, if anything, people do with it.
To give you an idea of what the code and output look like with each of these options, I have written the same program as a CLI using each of the libraries. The program returns the sum of the numbers entered as positional arguments. For each library, I give you the code, the help display, and test run results.
Argparse:
# add_argparse.py
import argparse
parser = argparse.ArgumentParser(
prog="Add Numbers",
description="Adds entered numbers"
)
parser.add_argument('nums',
type=float,
nargs="+",
help="numbers to be added")
args = parser.parse_args()
print(sum(args.nums))
(.env) mark@Marks-MacBook-Air CLIs % python add_argparse.py -h
usage: Add Numbers [-h] nums [nums ...]
Adds entered numbers
positional arguments:
nums numbers to be added
options:
-h, --help show this help message and exit
(.env) mark@Marks-MacBook-Air CLIs % python add_argparse.py 3 4 5
12.0
Typer:
# add_typer.py
import typer
from typing import List
def add(nums: List[float] = typer.Argument(None, help="Enter one or more numbers to add")):
"""Adds entered numbers"""
print(sum(nums))
if __name__ == '__main__':
typer.run(add)
(.env) mark@Marks-MacBook-Air CLIs % python add_typer.py --help
Usage: add_typer.py [OPTIONS] [NUMS]...
Adds entered numbers
╭─ Arguments ──────────────────────────────────────────────────────────────────╮
│ nums [NUMS]... Enter one or more numbers to add [default: None] │
╰──────────────────────────────────────────────────────────────────────────────╯
╭─ Options ────────────────────────────────────────────────────────────────────╮
│ --help Show this message and exit. │
╰──────────────────────────────────────────────────────────────────────────────╯
(.env) mark@Marks-MacBook-Air CLIs % python add_typer.py 3 4 5
12.0
Arguably:
# add_arguably.py
import arguably
@arguably.command
def add(*args: float):
"""Adds entered numbers"""
print(sum(args))
if __name__ == '__main__':
arguably.run()
(.env) mark@Marks-MacBook-Air CLIs % python add_arguably.py -h
usage: add_arguably.py [-h] [args ...]
Adds entered numbers
positional arguments:
args (type: float)
options:
-h, --help show this help message and exit
(.env) mark@Marks-MacBook-Air CLIs % python add_arguably.py 3 4 5
12.0
What's the most useless CLI you've ever written? What about the most productive?
(All code can be found in the Awkward Python GitHub repository)