Super Easy Python CLI with Click

By Richard Barella

Your python code is now 100% more elegant and usable as a command-line program using Click

Many people who use python are used to the scriptfile workflow, where you write a rigid script in python and run it, somewhat similar to how people use bash scripts.

  1. You find an answer in a blog somewhere that describes how to do something in python
  2. You draft up a python script for the task and get it to work
  3. You hard-code all the parameters the script needs

Don't get me wrong – drafting up python scripts to prototype your idea is really useful. You get your idea working fast, even if your code becomes messy and unmaintainable.

However, wouldn't you like your python script to be as elegant and usable as all the command-line utilities you're used to?

1
2
3
4
ls -l
find -name *.py
grep -r "some text"
ssh --version

For kicks, lets take the python3 print() function, and give it a CLI. Kind of like the echo command in bash.

This is the definition of print(): https://docs.python.org/3/library/functions.html#print

print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)

So in python, you can print in all sorts of ways, more than just print('hello'). For example, you can add customized string to append to the end, change the seperator between words, and output to a file instead of stdout.

1
2
3
print('hello', end='\r') 
print('hello', 'hi', sep=',')
print('hello', file=open('out.txt', 'w'))

The simple CLI

Take a look on how easy it is to turn the print statement above into a full-featured CLI.

print.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

import click
import sys






def print_prog(args, sep, end, out):
'''Print the arguments you give this program to stdout or to a file. Similar to echo.
'''
print(*args, sep=sep, end=end, file=open(out, 'w') if out else sys.stdout)

if __name__ == '__main__':
print_prog()

Essentially this script is taking all the command line arguments and giving them directly to the print() function. So we are in effect giving the bash-terminal all the capabilities of python's print(). Instead of print this CLI program could easily be changed to perform any scripting task with flexible and configurable input.

Now that we have our command-line-enabled python script, lets see how well it does…

echoing things

1
./print.py can it echo this?
can it echo this?
Usage: print.py [OPTIONS] [ARGS]... Print the arguments you give this program to stdout or to a file. Similar to echo. Options: -s, --sep TEXT String to seperate each argument (default: " ")] -e, --end TEXT String to append to end (default: "\n") -o, --out TEXT Output file (default: stdout) --help Show this message and exit.

Wow… we can already see this has more features than the ever-so-useful echo

For example, we can change the seperator between the args

1
./print.py these args are seperated by dashes --sep='-'
these-args-are-seperated-by-dashes

Also, not always ending with just a newline

1
./print.py maybe I want 2 newlines --end=$'\n\n' && print.py instead
maybe I want 2 newlines instead

You can write to a file too

1
./print.py write this to a file --out=file.txt

Then read the file

write this to a file

Making this your own

This was a demonstration to show you how easy it is to create your own CLI. You don't need write plain python scriptfiles anymore.

Take this template and apply it to your own program.

Visit the Click website to reference the Click documentation while building your projects.

Also, for a slightly more complex example, you can check out my QuadArt project which uses Click CLI to be usable by anyone through the terminal. I wrote a blog post about it here. Here is an exerpt of the part of quadart.py that uses Click:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23











def main(filename, left, right, up, down, output, size, draw_type, thresh, max_recurse):
quadart = QuadArt(std_thresh=thresh, draw_type=draw_type, max_recurse=max_recurse)
quadart.generate(filename, left=left, right=right,
up=up, down=down,
output_size=size)
if output is None:
quadart.display()
else:
quadart.save(output)

if __name__ == '__main__':
main()

This is the magic of combining python and the terminal with the glue of CLI. The possibilities are endless!

See you next post.

–Ricky