Skip to main content

protocli

pypi

Signature-driven CLI dispatcher: typed function signatures become argparse parsers, modules become lazily-imported subcommands, with nested dispatch, --help-all and lazy shell completions.

# mytool/__main__.py
from protocli import Dispatcher

Dispatcher(
    "mytool",
    {
        "greet": greet,          # a callable: its signature IS the parser
        "db": "mytool.db",       # a module path: lazy-imported on dispatch
        "cache": Dispatcher(     # a nested group, listed with its doc
            "mytool cache", {"clear": clear}, doc="Cache tools."
        ),
    },
).run()

run(argv=None) dispatches argv (default sys.argv[1:]) and returns the leaf's int result as the exit code, 0 for anything else, so main = Dispatcher(...).run serves as a console-script entry point and main(["greet", "ada"]) drives it from tests.

A callable (or a module's main) maps to CLI arguments by signature:

def greet(
    name: str,                        # required positional
    title: str | None = None,         # optional positional
    *rest: str,                       # variadic
    loud: bool = False,               # --loud   (keyword-only, default False)
    times: int = 1,                   # --times N
    lang: Literal["en", "hu"] = "en", # --lang restricted to choices
    tags: list[str] = [],             # --tags a,b,c  (comma-separated)
): ...

Each parameter's --help text comes from the function's Google-style Args: section; continuation lines are joined:

def pull(source: str, *, dest: str | None = None):
    """Download a published dataset.

    Args:
        source: project URL or path
        dest: target directory, the pull cache when omitted
    """

Dynamic completions

Literal fixes a closed set the parser enforces. Complete carries candidates the parser never sees — computed on demand, when the shell asks and only then:

from typing import Annotated
from protocli import Complete, FILES

Machine = Annotated[str, Complete(inventory.get_names)]   # any () -> Sequence[str]

def deploy(*names: Machine, config: Annotated[str, FILES] = ""): ...

deploy <TAB> offers the machine names, dropping the ones already typed (Complete(fn, repeat=True) keeps them); --config <TAB> defers to the shell's native pathname completion.

The completer runs on the --complete path alone — never on dispatch, never under --help-all. Its values are advisory and never become argparse choices, so an unknown value reaches the function and is rejected there, with the function's own error. That is the difference from Literal, and the reason the two are exclusive on one parameter.

Completion resolves which parameter the cursor sits on, so positionals, variadics and flag values all complete, and a flag already given is not offered again. A module can instead expose a get_completions(rest) hook when candidates depend on more than one argument, or its own nested _dispatcher = Dispatcher(...).

mytool --help-all prints every parser in the tree.

Auto-discovery over a package's public modules:

Dispatcher.from_package("mytool").run()

Bash completion

mytool --bash-completion prints the bash script that completes mytool and every alias onto it; on each TAB it asks mytool --complete <words before the cursor> for candidates. Load it from ~/.bashrc, after the aliases:

eval "$(mytool --bash-completion)"

To start the tool only on its first TAB, put this line in a file named after the tool in ~/.local/share/bash-completion/completions/. The line is the same for every tool, and an alias onto the tool completes once the tool's script has loaded:

eval "$("${BASH_SOURCE##*/}" --bash-completion 2>/dev/null)"

Metadata

Release files for protocli 0.4.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for protocli 0.4.0
File Size Uploaded Provenance
protocli-0.4.0.tar.gz 16.5 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for protocli 0.4.0
File Interpreter ABI Platform
protocli-0.4.0-py3-none-any.whl Python 3 none any Details

Total release size: 31.8 kB

Release files / protocli-0.4.0.tar.gz

Download URL protocli-0.4.0.tar.gz
Size 16.5 kB
Tags Source
SHA-256 checksum
How to use checksums
ef0900eff589b60f5f47f0da21a7af0bbae07a3f3e7bd6260b6d766fda8edad0
BLAKE2b-256 checksum
How to use checksums
1c93cdd906600764870eed113b1cc2e08ea33f747bdd5d56a954f001b0466ae5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.13.3 {"installer":{"name":"uv","version":"0.13.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / protocli-0.4.0-py3-none-any.whl

Download URL protocli-0.4.0-py3-none-any.whl
Size 15.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d2267837a3ade1ebcaf609d5671652954346eeca976b717391e1582540e7c904
BLAKE2b-256 checksum
How to use checksums
0fd096e53710f3b7c1398226aaf61d67fab0c939166fd9aaa71f46012b9b2caa
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.13.3 {"installer":{"name":"uv","version":"0.13.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Security for protocli 0.4.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

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