Click: A Python Lib to Build Beautiful Command Line Interfaces
This article is part of the Python Libraries Series. Find more below!
When you want to build a project without bothering with design and building a user interface, you will use command line interfaces (CLIs).
Click is a popular Python library that simplifies the process of building robust and efficient CLIs.
Why Click?
When it comes to building command line interfaces (CLIs) in Python, you have many options available.
First, you can just try to build your CLI without using any library. However, this approach can quickly become cumbersome and error-prone, especially as your CLI grows in complexity.
That’s why you probably want to use a library. A popular one is argparse. However, while this library can be convenient for small projects, it’s not really flexible, because of the design of the library. For example, argparse has built-in behavior to guess if something is an argument or an option. This becomes a problem when dealing with incomplete command lines; the behaviour becomes unpredictable without full knowledge of a command line. Also, argparse does not support disabling interspersed arguments. If you don’t need these features, well you can go with argparse, I started with this library and it worked fine.
Another option could be the cmd library. Cmd provides a simple framework for writing line-oriented command interpreters. These are often useful for test harnesses, administrative tools, and prototypes that will later be wrapped in a more sophisticated interface. I’ve built a small project with this library (a CLI to interact with a cloud storage provider) and it was pretty straightforward, so cmd is a good recommendation too, I’ll probably talk about it later.
For now, let’s focus on Click.
Click focuses on simplicity and aims to make the development of CLIs more enjoyable. It provides a high-level API that abstracts away the complexities of handling command line arguments, options, and subcommands. Instead of wrestling with low-level details, you can focus on defining the structure and behavior of your command line application.
The design philosophy behind Click revolves around writing code that is both readable and expressive. Click embraces the concept of “command as a function,” where each command is represented by a Python function. This approach allows you to write concise and self-contained functions that perform specific tasks within the command line application.
In addition to its simplicity, Click offers a range of features that enhance the user experience. One notable feature is the automatic generation of help pages. This feature reduces the need for manual documentation and ensures that users have access to clear instructions and usage examples.
Click also provides support for parameter types and validation. This ensures that input values are properly validated and prevents common errors and misuse. Furthermore, Click offers support for custom parameter types, enabling you to define yout own validation logic tailored to your specific application requirements.
Another powerful feature of Click is its support for nested commands and groupings. This allows you to organize related commands into logical groups and define complex command line structures.
Your First CLI with Click
Let’s start by importing Click:
import clickNormally, you don’t need to install click, it’s already installed with your default Python installation.
With click, one function is one command. Let’s create our first function, so our first command.
@click.command()
def greet():
click.echo("Hello World!")You just have to use the decorator click.command() to indicate it is a command.
Now, you can write a main :
if __name__ == '__main__':
greet()If you run your script, it will display Hello World! :
python script.py
Hello World!Now, you probably want to build a CLI with several commands available. So, you’ll need groups. To create a group, we just use the click.group() decorator. Then, we have to change the decorator of our commands:
import click
@click.group()
def cli():
pass
@cli.command()
def greet():
click.echo('Hello World!')
if __name__ == '__main__':
cli()Now, if we run python script.py , we’ll get a generic message:
Usage: cliwithclick.py [OPTIONS] COMMAND [ARGS]...
Options:
--help Show this message and exit.
Commands:
greetTo run our command, we need to run python script.py greet .
python script.py greet
Hello World!Instead of changing the decorator of our commands, we can just use click.command() and attach our commands to a group using group.add_command(command) .
@click.group()
def cli():
pass
@click.command()
def greet():
click.echo('Hello World!')
cli.add_command(greet)Adding Parameters
To add parameters to command, you just have to use the click.option() or click.argument() decorators:
@click.command()
@click.option('--name', '-n', default='World')
@click.argument('greeting', default='Hello')
def greet(name, greeting):
print(f'{greeting}, {name}!')python cliwithclick.py greet --name Dan Hello
Hello, Dan!As a reminder, an option is optional, and an argument is mandatory. It’s sometimes a confusion among developers so it’s worth making it clear.
To choose between options and arguments, it’s recommended to use arguments exclusively for things like going to subcommands or input filenames / URLs, and have everything else be an option instead.
You can also specify the type of an argument. It ensures the user isn’t typing something wrong.
@click.command()
@click.argument('number', type=click.INT)
def double(number):
click.echo(number * 2)Instead of using click.INT , you can also use just int but I recommend using click types.
python cliwithclick.py double 3
6
python cliwithclick.py double 3.3
Usage: cliwithclick.py double [OPTIONS] NUMBER
Try 'cliwithclick.py double --help' for help.
Error: Invalid value for 'NUMBER': '3.3' is not a valid integer.There are a lot of types available, here is the list:
click.INT
click.FLOAT
click.BOOL
click.STRING
click.Path()
click.File()
click.DateTime()
click.UUID
click.Choice(['rock', 'paper', 'scissors'])
click.Tuple([click.INT, click.INT])
click.IntRange(0, 10)
click.FloatRange(0, 10)
click.DateTime(formats=['%Y-%m-%d'])
click.UUID(version=4)For more information about the types, check the doc!
You can also define your own custom types if you want. Here is an example:
class BasedStringParamType(click.ParamType):
name = 'string'
def convert(self, value, param, ctx):
if not isinstance(value, str):
self.fail(
'expected string, got %s of type %s' % (
value, type(value).__name__
), param, ctx
)
return valueThe name attribute is used for the documentation. The convert method is called when the parameter is parsed. And if this method should fail because the parameter can’t be converted, you just have to call self.fail() .
Final Note
And here it is, you know how to build a robust CLI in a few lines! This article was short, but its purpose is mainly to introduce you to a library you probably have never heard about. It’s not to rewrite the documentation. And the same applies to the other articles of this series.
I hope I’ve introduced you to a library you’ll use! Personally, I haven’t done any big projects with it yet, but I’ll probably rewrite a little project I did on the fly with the cmd library!
If you want to discover other Python libraries, click below!
If you liked the story, don’t forget to clap and maybe follow me if you want to explore more of my content :)
You can also subscribe to me via email to be notified every time I publish a new story, just click here!
If you’re not subscribed to Medium yet and wish to support me or get access to all my stories, you can use my link:





