Generate zsh completions with Python.
Project description
zcompy
zcompy (zsh completion using Python) is a Python library that makes it easy to generate sophisticated zsh completion scripts for your command-line tools.
Instead of writing complex zsh completion scripts by hand, you can define your commands and options in Python and let zcompy generate the completion for you.
Features
- 🐍 Pure Python: Define completions using familiar Python syntax
- 🎯 Type-safe: Built-in support for common argument types (files, directories, strings)
- 🔄 Sub-commands: Full support for nested sub-commands
- 🎨 Custom completions: Define your own completion functions with python functions
- 🔗 Dependencies: Completion could depend on other option values
Installation
From PyPI
pip install zcompy
From Source
git clone https://github.com/FateScript/zcompy.git
cd zcompy
pip install -e .
Development Installation
git clone https://github.com/FateScript/zcompy.git
cd zcompy
pip install -e ".[dev]"
Quick Start
Here's a simple example to get you started:
from zcompy import Command, Option, Files, Completion
# Create your command
mytool = Command("mytool", "My awesome command-line tool")
# Add global options for mytool
mytool.add_options([
Option(("--verbose", "-v"), "Enable verbose output"),
Option(("--config", "-c"), "Config file path", complete_func=Files())
])
# Create sub-commands
build_cmd = Command("build", "Build the project")
build_cmd.add_options([
Option(
("--output", "-o"), "Output directory",
complete_func=Files(dir_only=True)
),
Option(
("--optimize", "-O"), "Optimization level",
complete_func=Completion(func=("o1", "o2", "o3"))
)
])
# Add sub-command to main command
mytool.add_sub_commands(build_cmd)
# print completion source
print(mytool.complete_source())
# Also, you might generate zsh completion code in output dir
# mytool.completion_entry(output_dir="~/.zsh/completion")
Then add to your ~/.zshrc or run in your terminal sesssion:
fpath=(~/.zsh/completions $fpath)
autoload -U compinit && compinit
compdef _mytool mytool
👉 Please type mytool in cli and press <TAB> to feel the magic 🪄
Usage
Basic Command Structure
from zcompy import Command, Option, Completion, Files
# Create a command
cmd = Command("mycmd", "Description of your command")
# Add options
cmd.add_options([
Option(("--flag", "-f"), "Turn on to enable something"),
Option(("--file",), "Input file", complete_func=Files()),
Option(("--dir",), "Output directory", complete_func=Files(dir_only=True))
])
Sub-commands
# Create main command
main = Command("git", "Git version control")
# Create sub-commands
status = Command("status", "Show working tree status")
commit = Command("commit", "Record changes to repository")
commit.add_options([
Option(("--message", "-m"), "Commit message", type="STRING"),
Option(("--amend",), "Amend previous commit")
])
# Add sub-commands to main
main.add_sub_commands([status, commit])
Custom Completions
Define your own completion functions
NOTE:
- To make your completions work, simply print each completion string to stdout.
- If you want to show descriptions for completions, print them after a space, like:
completion description.
def list_things():
for item in ["thing1", "thing2", "thing3"]:
print(f"my_{item}")
branch_option = Option(
("--things", "-t"),
"things to describe",
type="THINGS",
complete_func=Completion(list_things)
)
Advanced Usage
Automatic CLI Framework Support
zcompy provides built-in support for generating completions from popular Python CLI frameworks:
ArgumentParser support
from argparse import ArgumentParser
from zcompy.parser_command import ParserCommand
# Create your argparse parser
parser = ArgumentParser(prog="mytool", description="My awesome CLI tool")
parser.add_argument("--verbose", "-v", action="store_true", help="Enable verbose output")
parser.add_argument("--config", "-c", type=str, help="Config file path")
parser.add_argument("--mode", choices=["auto", "manual", "disabled"], help="Operation mode")
# Add sub-commands
subparsers = parser.add_subparsers(dest="command")
build_parser = subparsers.add_parser("build", help="Build the project")
build_parser.add_argument("--output", "-o", type=str, help="Output directory")
# Generate completion using zcompy
parser_command = ParserCommand(parser)
command = parser_command.to_command()
print(command.complete_source())
# Add custom completion for file paths
from zcompy.action import Files
parser_command.add_action_for_options("--config", "--output", action=Files())
Abseil (absl-py) Support
from absl import flags
from zcompy.absl_command import AbslFlagsCommand
# Define your absl flags
FLAGS = flags.FLAGS
flags.DEFINE_string('name', 'World', 'The name to greet')
flags.DEFINE_integer('count', 1, 'The number of greetings')
flags.DEFINE_bool('verbose', False, 'Whether to display verbose output')
flags.DEFINE_enum('color', 'blue', ['red', 'blue', 'green'], 'Choose a color')
# Generate completion using zcompy
cmd = AbslFlagsCommand(name="mytool").to_command()
print(cmd.complete_source())
Fire Support
Users could use FireCommand like fire-guide.
python class
import fire
from zcompy.fire_command import FireCommand
class MyCLI:
"""My awesome CLI tool."""
def add(self, x, y):
"""Addition command"""
return x + y
def mul(self, a, b):
"""Multiplication command"""
return a * b
def build(self, output_dir="./build", optimize=True):
"""Build the project"""
return f"Building to {output_dir}"
# Generate completion using zcompy
fire_cmd = FireCommand(name="mytool", obj=MyCLI)
command = fire_cmd.to_command()
print(command.complete_source())
python function
def add_func(x, y):
"""Addition command"""
return x + y
fire_cmd = FireCommand(name="calc", obj=add_func)
command = fire_cmd.to_command()
print(command.complete_source())
python dict
func_dict = {"add": lambda x, y: x + y, "mul": lambda a, b: a * b}
fire_cmd = FireCommand(name="math", obj=func_dict)
command = fire_cmd.to_command()
print(command.complete_source())
Dependent Completions
Completions could depend on other options' value/existence:
from zcompy import DependentCompletion, Option
def complete_based_on_config(config_path):
"""Complete based on config_path value."""
if config_path and os.path.exists(config_path):
# Read config and provide completions
with open(config_path) as f:
configs = f.read().splitlines()
for line, config in enumerate(configs):
print(f"{config} line {line + 1}")
config_dependent = Option(
("--target",),
"Target based on config",
type="TARGET",
complete_func=DependentCompletion(
func=complete_based_on_config,
depends_on="--config"
)
)
Positional Arguments
from zcompy.action import GitBranches, GitCommits
# Add positional arguments
cmd.add_positional_args([
Files("*.py"),
GitBranches(),
GitCommits(),
])
# Use repeat_pos_args if you want to repeat positional arguments.
# for example, `cmd file1 file2 file3`
cmd.repeat_pos_args = Files()
Development
Setup Development Environment
git clone https://github.com/FateScript/zcompy.git
cd zcompy
python -m venv zcompy
source zcompy/bin/activate
pip install -e ".[dev]"
Running Tests
pytest tests
Acknowledgments
- Thanks to Claude code and Kimi K2 for writing code and giving inspiration, guidance.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file zcompy-0.0.1.tar.gz.
File metadata
- Download URL: zcompy-0.0.1.tar.gz
- Upload date:
- Size: 27.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0a9f14ed177667be3ae264c130544d6cde8427415bb9d73e9b83aac3c8d14da8
|
|
| MD5 |
3fddcc2c21296d74bb7b84fbedecfc17
|
|
| BLAKE2b-256 |
8ae4f9425da74ec67f335b6d8f4e228244303b062e31f759fb97dfe2877df00b
|
File details
Details for the file zcompy-0.0.1-py3-none-any.whl.
File metadata
- Download URL: zcompy-0.0.1-py3-none-any.whl
- Upload date:
- Size: 26.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b0f7500dbc237e4fa75e1c12ef32a634df2fd5f1d6ae25f2345ef96fb6eaff1e
|
|
| MD5 |
872c7bb8962121512bc9315e14a465e7
|
|
| BLAKE2b-256 |
78574fdb2c3f1cb2b2617a2852830d14f1f6f2cf7c9d84a7ebf1f1289cb1e6be
|