Shell completion

Click · Advanced · 10 min

Completion makes large CLIs discoverable and is expected of polished tools.

Click has built-in completion for bash (4.4+), zsh, fish and, since 8.5, PowerShell. It works for installed entry points (not python script.py). Completion is activated by an environment variable named after the program: for my-tool it is _MY_TOOL_COMPLETE.

Users generate a script once and source it from their shell config:

_MY_TOOL_COMPLETE=bash_source my-tool > ~/.my-tool-complete.bash
echo '. ~/.my-tool-complete.bash' >> ~/.bashrc

with zsh_source, fish_source or powershell_source for the other shells. Document this in your README or offer a completion subcommand that prints it.

Out of the box Click completes subcommand names, option names, Choice values, and file paths for Path and File types.

For dynamic values (git branches, server names), pass shell_complete=fn to a parameter. The function receives (ctx, param, incomplete) and returns a list of strings or click.shell_completion.CompletionItem objects (which can carry help text shown by zsh and fish). Filter by the incomplete prefix yourself.

Completion runs your program with ctx.resilient_parsing = True: callbacks and prompts are skipped and errors suppressed. Keep completion functions fast, avoid side effects, and remember that your module is imported on every keypress-triggered completion, which is a strong reason to keep top-level imports light.

Example

import click
from click.shell_completion import CompletionItem

ENVIRONMENTS = {"dev": "local cluster", "staging": "pre-prod", "prod": "live!"}

def complete_env(ctx, param, incomplete):
    return [CompletionItem(name, help=desc)
            for name, desc in ENVIRONMENTS.items() if name.startswith(incomplete)]

@click.command()
@click.argument("env", shell_complete=complete_env)
@click.option("--format", type=click.Choice(["json", "table"]))
def status(env, format):
    click.echo(f"{env}: ok")

items = complete_env(None, None, "st")
print([(i.value, i.help) for i in items])   # [('staging', 'pre-prod')]

# Users enable it once for the installed command `status`:
#   eval "$(_STATUS_COMPLETE=bash_source status)"

Remember

  • Built-in completion for bash, zsh, fish and (8.5+) PowerShell via _PROG_COMPLETE
  • Choices, subcommands and paths complete automatically
  • shell_complete=fn returns CompletionItems for dynamic values

Watch out for

  • Doing slow network calls in shell_complete without caching, making Tab hang.

Check yourself

  1. For an installed program named db-admin, which variable triggers completion script generation?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: click.palletsprojects.com/en/stable/shell-completion/