Using the scaffold and click libraries in Python, you can upgrade a simple utility into a full-fledged command-line interface tool.

In my career, I have written, used, and seen a lot of random scripts. Some people need to semi-automate tasks, and so they are born. After a while, they become larger and larger. They can change hands many times in a lifetime. I often wish these scripts provided a more command-line tool-like feel. But how hard is it to really improve the level of quality, from one-off scripts to the right tools? This turns out to be not difficult in Python.

Build the skeleton script

In this article, I’ll start with a small piece of Python code. I’ll apply it to the scaffold module and extend it with the click library to accept command-line arguments.

All of the code examples shown in this article that are not inserted here, you can find specific versions of the code in Each commit in the repository describes some meaningful steps in the course of this article.

This clip does a few things:

As an example, it’s simple, but it will give you an understanding of the process.

Create an application using Pyscaffold

First, you need to install the scaffold, click, and tox Python libraries.

After installing scaffold, switch to the directory where the sample rotoscope project is located, and then execute the following command:

Pyscaffold will rewrite my, so restore it from Git:

Pyscaffold explains in the documentation how to set up a complete sample project, which I won’t cover here, you can explore later. In addition to this, Pyscaffold can also provide you with continuous integration (CI) templates in your projects:

Looking at the test folder and running the tox command in the project directory, it immediately outputs an error: The packaged infrastructure could not find the relevant library.

Now create a Git tag (e.g. v0.2) that the tool recognizes as an installable version. Before committing your changes, take a look at the automatically generated setup.cfg and edit it as needed. For this example, you can modify the LICENSE and project description to add those changes to the Git staging area, and I have to disable the precommit hook and then commit them. Otherwise, I’ll run into errors because the Python style checker flake8 complains about bad formatting.

If this script has an entry point that the user can call from the command line, that’s even better. Now, you can only run it by finding the .py file and executing it manually. Fortunately, Python’s packaging infrastructure has a nice “canned” way to easily make configuration changes. Add the following to the .cfg section of setup options.entry_points:

This change creates a shell command called roto, which you can use to invoke rotoscope scripts, and after installing rotoscope with pip, you can use the roto command.

That’s it, you get all the packaging, testing, and documentation settings for free from Pyscaffold. You also get a pre-commit hook to ensure that (in most cases) you submit according to the set rules.

CLI tooling

Now, some values are hard-coded into the script, and they are more convenient as command arguments. For example, it is better to take the INCOMING constant as a command-line argument.

First, import the click library, decorate the rotoscope() method using the command decorator provided by Click, and add an argument that Click passes to the rotoscope function. Click provides a set of validators, so add a path validator to the parameter. Click also makes it convenient to use the function’s inline string as part of the command-line documentation. So you will end up with the following method signature:

The main function calls rotoscope(), which is now a Click command that does not require passing any arguments.

Options can also be automatically populated using environment variables. For example, change the ARCHIVE constant to an option:

Use the same path validator. This time, let Click populate the environment variable, which defaults to the value of the old constant if it doesn’t provide anything.

Click does a lot more, with colored console output, hints, and subcommands that let you build complex CLI tools. Browse the Click documentation to find more of its features.

Now add some tests.


Click provides some recommendations for running end-to-end tests using the CLI runner. You can use it to implement a complete test (in the sample project, the test is in the tests folder. )

The test is in a method of the test class. Most of the conventions are very close to what I’ve used in other Python projects, but there are some details because rotoscope uses click. In the test method, I created a CliRunner. The test uses it to run this command on an isolated file system. Then test creating the incoming and archive directories and a virtual incoming/test.txt file in the isolated file system, and then it calls CliRunner, just as you would call a command-line application. After the run is complete, the test checks the quarantined file system and verifies that incoming is empty and that the archive contains two files (the latest link and the archive).

To perform these tests on the console, run tox in the root directory of the project.

During the execution of the test, I found a bug in the code. When I do the Click conversion, rotoscope simply unlinks the latest file, whether it exists or not. The test started with a new file system (not my home folder) and quickly failed. I can prevent this error by running in a good isolated and automated test environment. This will avoid a lot of “it works fine on my machine” problems.

Build skeleton scripts and modules

At this end of this article, we can use scaffold and click to do some advanced operations. There are many ways to upgrade a normal Python script or even turn your simple utility into a full-fledged CLI tool.


Author: Mark Meyer Title: lkxed Translator: MjSeven Proofreader: wxy

This article was compiled by LCTT originally, and was launched by Linux China