Will Sorenson Machine Learning and Coding

Quick Command Line Apps with Click

Synopsis

If thinking of making a CLI tool, consider using Python with click. It is very fast and will make your life easier. It is probably the most straightforward way to automate tasks.

This script removes an enormous headache of making blog posts. As I already tend to take notes using the Jupyter Notebook, it makes it very easy to blog regularly.

Which Library to Use

There are a number of good libraries that make making CLI apps with Python easy. I am personally a big fan of click as it seems to be the quickest way to get running. I have a short CLI available that automates my blog posting workflow here.

Here is the heart of pelican_autopost. This little code already makes all of the necessary documentation, prompts, default values, and arguments.

import click
BLOG_DIR = '~/blog'
@click.command()
@click.option('--blog-dir', default=BLOG_DIR)
@click.option('--notebook-path', prompt='Enter the full notebook path',
              help='files must be''located in `blog_dir`')
@click.option('--title', prompt='enter the title. Must be unique', default=None)
@click.option('--tags', prompt='enter a tag. You may enter more than one via',
              multiple=True)
@click.option('--category', default=None)
def _main(blog_dir, notebook_path, title, tags, category):
    """
    Simple program that takes the directory of a notebook
     (use `greadlink -f file.ipynb |  pbcopy`)
    and other parameters and then publishes it to my pelican blog.


    Examples
    ----
    ./pelican_auto_post.py --tags *Nix --tags CLI  --title sqlite3
    Enter the full notebook path: /Users/Will/Devel/blog_posts/sqlite3_CLI.ipynb

    """
    if not title:
        title = os.path.splitext(notebook_path)[0]

    make_md(blog_dir, title, tags, category, notebook_path)
    copy_notebook(notebook_path, blog_dir, title)
    publish(blog_dir)

Running the Script from anywhere

Now that we have the script, we can easily run it from anywhere by performing the following steps:

  1. Make a directory for all of your CLI tools if you don’t already have it. I use ~/scipts. Move your script to here.
  2. Add this directory to your PATH environmental variable. For OSX this is ~/.bash_profile
  3. Make sure you have the proper shebang line added to the top of your file #!/usr/bin/env python3

Executing Bash Scripts

Executing bash scripts from Python can be tricky. The Github describes how I did it but the most robust way to do this seems to be to execute the data directly from python like this:

from subprocess import call

with open('~/scripts/script_name.sh'):
    script = file.read()

rc = call(script, shell=True)

Make sure that you only run this with trusted code that oyu are feeding it yourself. Otherwise it poses a security issue. An alterantive option would be to santize the file in Python before using subprocess.call on it.

Testing

If the CLI is quite small, often times the best test is just going to be the script itself. I recommend to only test to prevent the things that can cause problems (accidently overwriting or deleting files). In the pelican autopost tool, for example, the only test I feel helped is the one that insures that the markdown files won’t be overwritten because this could cause problems if there were to be two blog posts of the same title.