Skip to main content

typer-static-completion

CI conda-forge pypi-version python-version

Generate static shell completions for typer applications. Requires Python 3.11 or newer.

Status: initial Bash, Fish, and Zsh implementation. Typer introspection and generation work for nested commands, flags, choices, tuple options, scalar/tuple/variadic arguments, and paths. The CLI provides generate; the Python API provides generate() and write(). PowerShell and dynamic delegation remain unimplemented. See TODO.md for the remaining work.

from typer_static_completion import generate
from myapp.cli import app

script = generate(app, "myapp", "bash")

Pass "fish" or "zsh" to target those shells. Write the returned script to a file and source it in the corresponding shell (after compinit for Zsh). Completion stays static: dynamic callback values are omitted by default. Explicit file fallback is supported; hybrid delegation currently raises an error. The supported Typer 0.26 parser accepts chain=True but does not execute chained commands. Generation rejects this setting explicitly, including callback and add_typer settings, before Typer discards it during command conversion. Chain completion remains deferred until the supported parser can execute chains.

Tuple options such as pair: tuple[Color, Path] complete each value using its own type. All three shells support --pair blue path, --pair=blue path, attached short values, and repeated occurrences. Param.values holds the per-position ValueSpec metadata for callers constructing command trees by hand. Tuple positional arguments also complete each position using its own type; options may appear between values, and subsequent scalar or variadic arguments receive their own completions.

Groups can take scalar, tuple, or variadic arguments. Completion consumes their values before offering subcommands, then switches to the child's scope. Like Typer's default parser, group options must precede the first argument; a child starts its own option parsing. Optional arguments still consume available words, and variadic group arguments consume the remainder, including command names. Custom groups with allow_interspersed_args=True are diagnosed as unsupported.

Choices configured with case_sensitive=False accept differently cased prefixes and insert the declared spelling, including in tuple parameters. Case-sensitive choices retain exact prefix matching. Matching uses lowercase prefixes, as in Typer's completion, with non-ASCII casing governed by the shell locale.

The public Shell enum lists the three implemented shells. Generator subclasses implement render() and quote(); custom generators can be registered under additional string names. verify.check_syntax() checks scripts with a locally installed shell's parser.

Command models are frozen, and each Command copies its subcommand mapping into a read-only view. Changing the original dictionary does not change the tree. Declaration order is preserved. Trees remain unhashable; use dataclasses.replace() to construct modified versions. Subcommand views are not mutable dictionaries.

Build-time generation and example

Run the example from this checkout:

pixi run example deploy --environment staging
pixi run example-completions

The second task calls write() from examples/completions.py, producing build/completions/bash/shipyard, build/completions/zsh/_shipyard, and build/completions/fish/shipyard.fish. The example is exercised by the CI test suite. In your project, call the same API during your build or release process:

from typer_static_completion import GenerationOptions, write
from myapp.cli import app

outputs = write(
    app,
    "myapp",
    output_dir="build/completions",
    options=GenerationOptions(regenerate_command="pixi run completions"),
)

Use shells=["fish"] to select shells, dry_run=True to preview the returned path-to-content mapping without writes, or layout={"bash": "share/bash-completion/completions/{prog}"} to override a shell's destination beneath the output directory. Unchanged files keep their modification times. Generation and destination checks finish before writing; changed files are replaced individually, so an I/O failure can leave a partially updated set. Custom paths cannot escape the output directory or collide.

To try completion in an interactive shell, run these commands from the checkout in the corresponding shell. The shipyard function supplies the example command; a packaged application would supply its own console entrypoint.

Bash:

shipyard() { pixi run example "$@"; }
source build/completions/bash/shipyard

Zsh:

shipyard() { pixi run example "$@"; }
autoload -Uz compinit
compinit
source build/completions/zsh/_shipyard

Fish:

function shipyard
    pixi run example $argv
end
source build/completions/fish/shipyard.fish

Try typing shipyard deploy --environment st followed by TAB. Completion itself runs entirely in the shell. For persistent installation, copy the Bash file to ~/.local/share/bash-completion/completions/shipyard when using bash-completion, or source it from your Bash startup file. Copy the Fish file to ~/.config/fish/completions/shipyard.fish (or your $XDG_CONFIG_HOME equivalent). For Zsh, copy _shipyard to a directory on fpath before calling compinit. These installation steps are manual; generation does not edit shell profiles.

After changing the CLI, rerun pixi run example-completions and source or install the updated files. For your own application, replace that task with your build's generation command. The banner records the regeneration command for reference.

Command line interface

Generate one shell's script from an importable Typer app:

pixi run typer-static-completion generate myapp.cli:app --prog-name myapp --shell fish -o myapp.fish

generate requires --shell and --prog-name. Omit -o (or use -o -) to emit the script on stdout. Otherwise, it writes to exactly the specified path, creating parent directories as needed. Relative paths are relative to the current working directory. Import output goes to stderr so it cannot corrupt the generated script.

Targets must point to Typer instances, such as myapp.cli:app; wrapper functions and factories are never called to discover an app. Targets must already be importable in the current environment. For factory-backed applications, construct the app explicitly and use the Python API.

Exit codes are 0 for success and 2 for usage or operation errors. There is no project discovery, ownership manifest, or automatic installation. Regenerate and install scripts through your project's build process when its CLI changes.

To generate this CLI's own Fish completion:

pixi run typer-static-completion generate typer_static_completion.cli:app --prog-name typer-static-completion --shell fish -o typer-static-completion.fish

The CLI is also available as pixi run python -m typer_static_completion.cli.

Interactive screen snapshots

Bash, Fish, and Zsh have real interactive PTY screen snapshots like those in commander-static-completion, recording suggestions, inserted text, and cursor position. The isolated snapshot environment provides all three shells, pexpect, and pyte on Linux/macOS. Ordinary unit tests can run without those integration dependencies.

pixi run -e snapshots test-snapshots
pixi run -e snapshots update-snapshots

Review changes under tests/snapshots/ after updating. Each screen snapshot has sections for all three shells. Full completion files sit alongside them in tests/snapshots/generated/demo.{bash,fish,zsh}, making changes to the emitted code and its size reviewable over time. Both kinds of snapshots use the same update/check commands; full-script checks also run with ordinary unit tests. Missing or changed snapshots fail checks; updating is forbidden in CI. The harness uses an isolated 80x24 terminal, named editing keys, timeouts, process cleanup, and sentinels that fail if static completion invokes the CLI or Python. CI checks the snapshots on Linux and macOS. Fish terminal capability negotiation is exercised by the harness.

The parsing matrix in tests/parsing_cases.py covers scalar/variadic arguments, repeated options, count flags, short clusters, shadowed parent options, and --. Its screen tests assert the expected completed line before comparing snapshots. tests/snapshots/parsing/ also checks two CLIs loaded together and sourced twice; tests/snapshots/generated/parsing.{bash,fish,zsh} records the corresponding full completion files. Separate tests verify the tricky cases against Typer's parser.

The CLI itself has four shared interactive cases in tests/snapshots/cli/ and full scripts in tests/snapshots/generated/cli.{bash,fish,zsh}.

The coverage fixture adds 45 shared screens for custom/disabled help flags, hidden commands/options, deprecated commands, literal help descriptions, Unicode, and escaped values, including metacharacters already in the typed prefix. These cases use C.UTF-8 and live in tests/snapshots/coverage/, with full scripts in tests/snapshots/generated/coverage.{bash,fish,zsh}. Completed lines are parsed by the actual shell using a controlled stub to verify argument values and reject executable substitutions before snapshots can update. Bash explicitly quotes literal candidates containing expansion syntax because Readline's filename quoting alone can leave backticks executable. Custom help aliases retain their configured order for deterministic output across processes. Bash respects quotes and escapes when finding the part Readline will replace, including prefixes with embedded quotes. Zsh avoids inserting a literal trailing space inside an already-closed quoted value.

The tuple cases in tests/tuple_cases.py have interactive screen snapshots and a full generated-script fixture alongside the existing parsing matrix.

The tuple-argument fixture adds 24 shared screens covering interspersed options, --, following scalar/variadic arguments, choices, paths, and directories. Full scripts live in tests/snapshots/generated/tuple-arguments.{bash,fish,zsh}.

The group-argument fixture adds 27 shared screens for parent arguments, nested groups, option boundaries, --, paths, and optional/variadic arguments. Full scripts live in tests/snapshots/generated/group-arguments.{bash,fish,zsh}.

The case-matching fixture adds 21 shared interactive screens for insensitive options, arguments, tuple positions, ambiguous matches, and accented values, plus sensitive-choice regressions. Full scripts live in tests/snapshots/generated/case.{bash,fish,zsh}.

The Unicode fixture adds 14 shared screens for CJK characters, single-code-point emoji, and decomposed/stacked accents, including completion in the middle of a line. Cursor markers use terminal cells rather than string indices. Snapshots also record the exact editor buffer and cursor offset, and tests pass the completed arguments through Typer so screen normalization cannot hide changes to decomposed values. Zsh's default display shows combining marks as codes; the original code points remain in its edit buffer. Full scripts live in tests/snapshots/generated/unicode.{bash,fish,zsh}.

The word-break fixture adds 12 Bash-specific snapshot cases, each checked with six COMP_WORDBREAKS settings (72 scenarios). They cover :, =, and @, quoted/escaped prefixes, assignments, and attached short options, with exact editor-state checks. Bash preserves @ when Readline includes it in the word being replaced. Full scripts live in tests/snapshots/generated/word-breaks.{bash,fish,zsh}.

Current snapshot baselines target the locked Bash 5.x, Fish 4.x, and Zsh 5.9 environment. Multi-code-point emoji sequences, line wrapping, unusual shell parsing modes, and filenames containing control characters still need broader coverage.

Installation

This project is managed by pixi. You can install the package in development mode using:

git clone https://github.com/pavelzw/typer-static-completion
cd typer-static-completion

pixi run pre-commit-install
pixi run test

Download files

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

Source Distribution

typer_static_completion-0.0.1.tar.gz (137.9 kB view details)

Uploaded Source

Built Distribution

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

typer_static_completion-0.0.1-py3-none-any.whl (32.8 kB view details)

Uploaded Python 3

File details

Details for the file typer_static_completion-0.0.1.tar.gz.

File metadata

  • Download URL: typer_static_completion-0.0.1.tar.gz
  • Upload date:
  • Size: 137.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for typer_static_completion-0.0.1.tar.gz
Algorithm Hash digest
SHA256 fd1326611e06f23dc86e6d14c14885d8a72e238a595ed20da57cacae1453e559
MD5 5f4129477db1e90da07d8b8b214b280c
BLAKE2b-256 20fd7ab783017a2adea9b787404c6f0f186aeb65c84a89544d34831828b2c897

See more details on using hashes here.

Provenance

The following attestation bundles were made for typer_static_completion-0.0.1.tar.gz:

Publisher: build.yml on pavelzw/typer-static-completion

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file typer_static_completion-0.0.1-py3-none-any.whl.

File metadata

File hashes

Hashes for typer_static_completion-0.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 c2ad7929aa6bc4e235af9434e852c9a236f1bbb3c227b87f57067baab92eb6a7
MD5 9a54bb01c6a710a2d158869b29c33b9f
BLAKE2b-256 c3730519b7dab66090f6f146cee902de678c347bc71bca388dbba47c3db90ba0

See more details on using hashes here.

Provenance

The following attestation bundles were made for typer_static_completion-0.0.1-py3-none-any.whl:

Publisher: build.yml on pavelzw/typer-static-completion

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.0.2

2 files

This release

0.0.1 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page