Skip to main content

Automatically generate shell tab completion scripts for python CLI apps

Project description

  • What: Automatically generate shell tab completion scripts for python CLI apps

  • Why: Speed & correctness. Alternatives like argcomplete & pyzshcomplete are slow and have side-effects

  • How: shtab processes an argparse.ArgumentParser object to generate a tab completion script for your shell

Features

  • Outputs completion for bash and zsh

  • Supports argparse and docopt (via argopt)

  • Supports arguments, options and subparsers

  • Supports path completion

Usage

Installing shtab’s own tab completion scripts is possible via:

# Install locally (eager)
echo 'eval "$(shtab --shell=bash shtab.main.get_main_parser)"' \
  >> ~/.bash_completion

# Install locally (lazy load for bash-completion>=2.8)
echo 'eval "$(shtab --shell=bash shtab.main.get_main_parser)"' \
  > "${BASH_COMPLETION_USER_DIR:-${XDG_DATA_HOME:-$HOME/.local/share}/bash-completion}/completions/shtab"

# Install system-wide
echo 'eval "$(shtab --shell=bash shtab.main.get_main_parser)"' \
  | sudo tee "$(pkg-config --variable=completionsdir bash-completion)"/shtab

# Install system-wide (legacy)
echo 'eval "$(shtab --shell=bash shtab.main.get_main_parser)"' \
  | sudo tee "$BASH_COMPLETION_COMPAT_DIR"/shtab

# Install once (will have to re-run if the target's CLI API changes,
# but doesn't need target to always be in $PYTHONPATH)
shtab --shell=bash shtab.main.get_main_parser --error-unimportable \
  | sudo tee "$BASH_COMPLETION_COMPAT_DIR"/shtab

# zsh equivalent
shtab --shell=zsh shtab.main.get_main_parser --error-unimportable \
  | sudo tee /usr/local/share/zsh/site-functions/_shtab

The same would work for most existing argparse-based scripts. For example, starting with this existing code:

import argparse

def get_main_parser():
    parser = argparse.ArgumentParser(prog="<MY_PROG>", ...)
    parser.add_argument(...)
    parser.add_subparsers(...)
    ...
    return parser

if __name__ == "__main__":
    parser = get_main_parser()
    args = parser.parse_args()
    ...

Assuming this code example is installed in MY_PROG.command.main, simply run:

# bash
echo 'eval "$(shtab --shell=bash MY_PROG.command.main.get_main_parser)"' \
  >> ~/.bash_completion

# zsh
shtab --shell=zsh -u MY_PROG.command.main.get_main_parser \
  | sudo tee /usr/local/share/zsh/site-functions/_MY_PROG

Configuration

Alternatively, add direct support to scripts for a little more configurability:

import argparse
import shtab, os  # for completion magic

def get_main_parser():
    parser = argparse.ArgumentParser(prog="<MY_PROG>", ...)
    parser.add_argument("--install-completion-shell", choices=["bash", "zsh"])
    parser.add_argument(
        "--file",
        choices=shtab.Optional.FILE,  # file tab completion
    )
    parser.add_argument(
        "--dir",
        choices=shtab.Required.DIRECTORY,  # directory tab completion
        default=os.getenv("BASH_COMPLETION_USER_DIR"),
    )
    ...
    return parser

if __name__ == "__main__":
    parser = get_main_parser()
    args = parser.parse_args()

    # completion magic
    shell = args.install_completion_shell
    if shell:
        completion_script = shtab.complete(parser, shell=shell)
        filename = args.file or "<MY_PROG>"
        print("Writing to system completion directory...")
        with open(os.path.join(args.dir, filename), "w") as fd:
            fd.write(completion_script)
        print("Please restart your terminal.")

    ...

More Examples

#!/usr/bin/env python
"""Greetings and partings.

Usage:
  greeter [options] [<you>] [<me>]

Options:
  -b, --bye  : Say "goodbye" (instead of "hello")
  -c, --print-bash-completion  : Output a tab-completion script

Arguments:
  <you>  : Your name [default: Anon]
  <me>  : My name [default: Casper]
"""
import sys, argopt, shtab
parser = argopt.argopt(__doc__)
if __name__ == "__main__":
    args = parser.parse_args()
    if args.print_bash_completion:
        print(shtab.complete(parser, shell="bash"))
        sys.exit(0)

    msg = "k thx bai!" if args.bye else "hai!"
    print("{} says '{}' to {}".format(args.me, msg, args.you))

Alternatives

  • argcomplete

    • executes the underlying script every time <TAB> is pressed (slow and has side-effects)

    • only provides bash completion

  • pyzshcomplete

    • executes the underlying script every time <TAB> is pressed (slow and has side-effects)

    • only provides zsh completion

  • click

    • different framework completely replacing argparse

    • solves multiple problems (rather than POSIX-style “do one thing well”)

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

shtab-0.0.0.tar.gz (10.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

shtab-0.0.0-py2.py3-none-any.whl (8.5 kB view details)

Uploaded Python 2Python 3

File details

Details for the file shtab-0.0.0.tar.gz.

File metadata

  • Download URL: shtab-0.0.0.tar.gz
  • Upload date:
  • Size: 10.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/1.13.0 pkginfo/1.4.2 requests/2.23.0 setuptools/41.4.0 requests-toolbelt/0.8.0 tqdm/4.46.0 CPython/2.7.15

File hashes

Hashes for shtab-0.0.0.tar.gz
Algorithm Hash digest
SHA256 75461a3bcc0b37bef05929623579905d8aa3fe7c571211b38d3f36c873e5f4ed
MD5 6b79c8c9a5fc5663540e9637ff8f246c
BLAKE2b-256 bfabe2473809a7cc5c9635b5f5240519693b7b2b58c6cd7001ed6ba8075b5d19

See more details on using hashes here.

File details

Details for the file shtab-0.0.0-py2.py3-none-any.whl.

File metadata

  • Download URL: shtab-0.0.0-py2.py3-none-any.whl
  • Upload date:
  • Size: 8.5 kB
  • Tags: Python 2, Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/1.13.0 pkginfo/1.4.2 requests/2.23.0 setuptools/41.4.0 requests-toolbelt/0.8.0 tqdm/4.46.0 CPython/2.7.15

File hashes

Hashes for shtab-0.0.0-py2.py3-none-any.whl
Algorithm Hash digest
SHA256 1d5f172b1a5a7680f8d8f8e5c860d47e7e61d15cd993767a02c56fcd50122c5c
MD5 37d7b1ddd13005e5d90e7faaa6654767
BLAKE2b-256 5dfe805e8f52cd47b3102d28d93a5e229fd5c8228511710289fc7970c54cd0cc

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page