typed-argparse
typed-argparse is a small annotation-driven CLI helper for people who want
typed parser generation without adopting a large framework.
It is aimed at simple command-line tools, scripting utilities, and lightweight
LLM-facing CLIs where you want a small API surface, explicit Python functions,
and standard argparse behavior instead of a large abstraction layer.
The core package has no required third-party runtime dependencies. The main API
is build_parser(), which converts a typed function signature into an
argparse-compatible parser. The package also includes Argument, Option,
unwrap(), call(), parse_and_call(), and build_subcommand_parser(),
plus optional cmd2 integration through with_annotated().
Why use it:
- small API surface
- typed function signatures instead of command classes or decorators everywhere
- easy
argparse.Namespace -> kwargsconversion throughunwrap() - a good fit for short-lived tools and simple LLM CLI wrappers
- optional
cmd2integration when you want an interactive shell
Install
The package is published on PyPI as typed-argparse-gen and imported as
typed_argparse.
uv add typed-argparse-gen
For cmd2 integration:
uv add "typed-argparse-gen[cmd2]"
Main feature: build_parser()
Use build_parser() when you want annotation-driven parser generation directly.
import argparse
from typing import Annotated
from typed_argparse import Argument, Option, build_parser
def greet(
name: Annotated[str, Argument(help_text="Who to greet")],
count: Annotated[int, Option("--count", "-c", help_text="Number of greetings")] = 1,
loud: bool = False,
) -> None:
pass
parser = build_parser(greet)
args = parser.parse_args(["Kelvin", "--count", "2", "--loud"])
assert isinstance(parser, argparse.ArgumentParser)
assert args.name == "Kelvin"
assert args.count == 2
assert args.loud is True
build_parser_from_function() is still available as an alias.
By default:
- parameters without defaults become positional arguments
- parameters with defaults become
--optionflags bool = Falsebecomesstore_truebool = Truebecomesstore_falseon--no-nameAnnotated[..., Argument(...)]andAnnotated[..., Option(...)]override the defaults
Unwrapping and calling
Use unwrap() to convert a parsed argparse.Namespace into plain values.
Use call() and parse_and_call() for the common dispatch path.
from typed_argparse import build_parser, call, parse_and_call, unwrap
parser = build_parser(greet)
namespace = parser.parse_args(["Kelvin", "--count", "2"])
kwargs = unwrap(namespace)
values = unwrap(namespace, as_tuple=True)
assert kwargs == {"name": "Kelvin", "count": 2, "loud": False}
assert values == ("Kelvin", 2, False)
assert call(greet, namespace) == ["Hello Kelvin", "Hello Kelvin"]
assert parse_and_call(greet, ["Kelvin", "--loud"]) == ["HELLO KELVIN"]
Subcommands
Use build_subcommand_parser() or parse_and_call() with a mapping for
small multi-command CLIs.
from typed_argparse import build_subcommand_parser, parse_and_call
commands = {"greet": greet, "tag": tag}
parser = build_subcommand_parser(commands)
namespace = parser.parse_args(["tag", "release", "--labels", "stable"])
result = parse_and_call(commands, ["tag", "release", "--labels", "stable"])
Optional cmd2 support
If you are using cmd2, you can use the same metadata model with
with_annotated(). Install the optional cmd2 extra first.
For typed code, prefer direct imports:
import cmd2
from typing import Annotated
from typed_argparse import Argument, Option, with_annotated
class App(cmd2.Cmd):
def sport_choices(self) -> list[str]:
return ["football", "basketball", "tennis"]
@with_annotated
def do_play(
self,
sport: Annotated[str, Argument(choices_provider=sport_choices)],
venue: Annotated[str, Option("--venue", "-v")] = "home",
) -> None:
self.poutput(f"{sport=} {venue=}")
Development
uv sync --group dev
uv run ruff check .
uv run ty check
uv run pytest
uv build
Release flow
This repo is configured for semantic versioning with conventional commits.
- Push conventional commits to
main - GitHub Actions runs tests and lint with
uv python-semantic-releasedetermines the next version, updatesCHANGELOG.md, tags the release, and publishes to PyPI
Expected commit prefixes include feat:, fix:, and perf:. Breaking changes should use ! or a BREAKING CHANGE: footer.
Metadata
Release files for typed-argparse-gen 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| typed_argparse_gen-0.3.0.tar.gz | 27.5 kB | With provenance | Details for typed_argparse_gen-0.3.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| typed_argparse_gen-0.3.0-py3-none-any.whl | Python 3 | none | any | Details for typed_argparse_gen-0.3.0-py3-none-any.whl |
Total release size: 47.4 kB
Release files / typed_argparse_gen-0.3.0.tar.gz
| Download URL | typed_argparse_gen-0.3.0.tar.gz |
|---|---|
| Size | 27.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
7afd0d5f428acbb5ba2ce7beb9dd19054f53c64fd99b68c303f9802c9fdf920d
|
|
BLAKE2b-256 checksum How to use checksums |
652410d07a7d802bff0beea00b16c23a2e0d4525a2ab5e753306fe2a27f3ded8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on May 1, 2026.
Transparency logRelease files / typed_argparse_gen-0.3.0-py3-none-any.whl
| Download URL | typed_argparse_gen-0.3.0-py3-none-any.whl |
|---|---|
| Size | 19.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c4a16db44563e9a681d6a4d0c46661ebeba526226455e1023b20ab19d7a3dfcd
|
|
BLAKE2b-256 checksum How to use checksums |
86567467932ceca7629d63d58eaf32d4c9c9801fdc06b6ebd01daf63e26018ab
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on May 1, 2026.
Transparency logSecurity for typed-argparse-gen 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.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for typed_argparse_gen-0.3.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on May 1, 2026.
Transparency logA 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.
To learn more about protecting yourself from malicious actors, visit our package security documentation.