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.2.tar.gz (138.7 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.2-py3-none-any.whl (33.9 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: typer_static_completion-0.0.2.tar.gz
  • Upload date:
  • Size: 138.7 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.2.tar.gz
Algorithm Hash digest
SHA256 b164f7ae41ea1a4452e3726ef957d0a0da69cdcb58b2ab0b64978207c0c8df92
MD5 bdfb393cee383faf8b6049965b687b00
BLAKE2b-256 321e4835a843bbb2be2fcfb0bb0da77b42e97cb6cba4827b32f90040241cc400

See more details on using hashes here.

Provenance

The following attestation bundles were made for typer_static_completion-0.0.2.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.2-py3-none-any.whl.

File metadata

File hashes

Hashes for typer_static_completion-0.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 3ed365c1704000ccd7d2740811ec456790cb48592242a9fc9dc6ba01dca40682
MD5 fb975f72ace5e4d4019e93c5e450a64b
BLAKE2b-256 1553e9f29d52b187d44bfa7da164b1bf49da0aa5a93667ff610013f475c92cd7

See more details on using hashes here.

Provenance

The following attestation bundles were made for typer_static_completion-0.0.2-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

This release

0.0.2 This release

2 files

0.0.1

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