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. 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; mytool --complete <args…> emits completion candidates for shell integration.

Auto-discovery over a package's public modules:

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

Metadata

Release files for protocli 0.3.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.3.0
File Size Uploaded Provenance
protocli-0.3.0.tar.gz 14.4 kB Without provenance Details

Built distribution (wheel)

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

Total release size: 27.3 kB

Release files / protocli-0.3.0.tar.gz

Download URL protocli-0.3.0.tar.gz
Size 14.4 kB
Tags Source
SHA-256 checksum
How to use checksums
591587dd05058d5ba7789a1245e43b4cf64d438db31568fcdb4544948f7dc2f3
BLAKE2b-256 checksum
How to use checksums
9cf0e01a1bb87d9d42718cf5a0fb3517c977535a54914e948a09811d20609340
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.13.2 {"installer":{"name":"uv","version":"0.13.2","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.3.0-py3-none-any.whl

Download URL protocli-0.3.0-py3-none-any.whl
Size 12.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ffeed598a0123aa090aebfa4f45097f9b2cdb019e075182bfc939aae25c16458
BLAKE2b-256 checksum
How to use checksums
d3572a9fad82e2457df09b49571c1b2c564bf64bfa813f55d92f25f1ffdce09b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.13.2 {"installer":{"name":"uv","version":"0.13.2","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.3.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