Building command line interfaces in Python

popular python software-development

It is very useful to be able to create command line interfaces for our programs. There are several situations in which we want to do that:

Python standard library provides us with the basic building blocks to create simple command-line interfaces such as argparse to read command-line arguments passed to our Python file, input for interactivity and print function to make simple outputs.

However even for simple scripts I recommend to use one of the many available libraries unless we cannot install additional dependencies in our environment. They pack a lot of useful stuff that we will definitely want to use and make the process of creating CLIs a piece of cake.

Click

My first recommendation is Click. Click is simple to use CLI library and comes already with support for coloring output, showing progress bars and it can even open editors for multi-line text editing. It has one other advantage. Due to its popularity it is included in some tools that we might be using already. Frameworks Flask and FastAPI are notable examples where we can use Click right away without installing it. We can also add some simple additions like tabulate to produce simple tables in the terminal.

Rich

If simple colors won’t cut it, there is this neat library called Rich. Rich is basically print() function on steroids. It can pretty-print Python lists and collections, output emojis, render Markdown and even highlight source code!

Let’s see an example of Click and Rich libraries together in action to setup a simple program with progress bar, table and colors:

"""Example of using libraries Click and Rich to create CLI"""

import time
import click
from rich.console import Console
from rich.table import Column, Table
console = Console()


@click.group()
def cli():
pass


def get_length(word: str) -> int:
time.sleep(1)
return len(word)


@cli.command()
@click.argument('words', nargs=-1)
def compute(words):
table = Table(show_header=True, header_style="bold magenta")
table.add_column("Word", style="dim", width=12)
table.add_column("Length")
with click.progressbar(words) as click_words:
for word in click_words:
word_length = get_length(word)
table.add_row(word, str(word_length))
console.print(table)


if __name__ == "__main__":
cli()

Typer

Typer is a CLI tool built on Click which enables us to leverage Python typing to define command line arguments instead of using decorators. Let’s see a simple example of taking arguments and using them:

import typer


app = typer.Typer()


@app.command()
def display(color: str, reverse: bool = True):
message = f"Hello from typer using {color} color!"
if not reverse:
typer.echo(typer.style(message, fg=color))
else:
typer.echo(typer.style(message[::-1], fg=color))


if __name__ == "__main__":
app()

Both Click and Typer can automatically display help to users of our programs using --help option.

You can run both examples from the Github repo.

There are countless CLI tools for Python but I believe that Click, Rich and Typer will cover most of our needs for simple CLI programs that we typically build.

Last updated on 30.1.2020.