avatarEsteban Thilliez

Summary

The article introduces Click, a Python library designed to simplify the creation of command line interfaces (CLIs) by providing a high-level API and features such as automatic help page generation, parameter type validation, and support for nested commands.

Abstract

The Python Libraries Series article focuses on Click, a Python library that streamlines the development of command line interfaces (CLIs). It emphasizes Click's simplicity, flexibility, and range of features that enhance both the developer experience and the user experience. The library's design philosophy centers on writing readable and expressive code, treating commands as functions. Click handles complexities like argument parsing and validation, and it generates help pages automatically. The article provides a brief tutorial on creating a basic CLI with Click, demonstrating how to define commands, groups, and parameters, and how to handle different types of inputs. It also touches on the library's ability to support custom parameter types and its extensive built-in type system. The author concludes by encouraging readers to explore Click for their projects and to check out other articles in the series for more Python libraries.

Opinions

  • The author suggests that building a CLI without a library like Click can be cumbersome and error-prone, especially for complex interfaces.
  • Click is praised for its simplicity and enjoyability in CLI development, abstracting away the complexities of argument handling.
  • The author compares Click with other libraries like argparse and cmd, noting that while argparse is convenient for small projects, it lacks flexibility, and cmd is straightforward but better suited for certain types of projects.
  • Click's automatic help page generation is highlighted as a feature that reduces the need for manual documentation and ensures users have access to clear instructions.
  • The author expresses a personal inclination towards using Click's built-in types over native Python types for argument type validation.
  • The author indicates a preference for using arguments for subcommands or file paths and using options for other command-line inputs, suggesting this as a best practice.
  • The author hints at future exploration of Click for personal projects, implying a positive opinion of the library's potential for real-world applications.
  • The article concludes with an invitation to readers to discover more Python libraries, suggesting the value of expanding one's toolkit with versatile libraries like Click.

Click: A Python Lib to Build Beautiful Command Line Interfaces

Photo by Markus Spiske on Unsplash

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 click

Normally, 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:
  greet

To 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 value

The 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:

Python
Software Development
Programming
Coding
Command Line
Recommended from ReadMedium