A small typed parser generator for lightweight Python CLIs.
Project description
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.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file typed_argparse_gen-0.3.0.tar.gz.
File metadata
- Download URL: typed_argparse_gen-0.3.0.tar.gz
- Upload date:
- Size: 27.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7afd0d5f428acbb5ba2ce7beb9dd19054f53c64fd99b68c303f9802c9fdf920d
|
|
| MD5 |
de2c49341c88929f1d35e8f3605370df
|
|
| BLAKE2b-256 |
652410d07a7d802bff0beea00b16c23a2e0d4525a2ab5e753306fe2a27f3ded8
|
Provenance
The following attestation bundles were made for typed_argparse_gen-0.3.0.tar.gz:
Publisher:
release.yml on KelvinChung2000/typed-argparse
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
typed_argparse_gen-0.3.0.tar.gz -
Subject digest:
7afd0d5f428acbb5ba2ce7beb9dd19054f53c64fd99b68c303f9802c9fdf920d - Sigstore transparency entry: 1419417296
- Sigstore integration time:
-
Permalink:
KelvinChung2000/typed-argparse@6ddb58c1c2daee8d8ed2c9f8c220edbf1957b8e8 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/KelvinChung2000
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@6ddb58c1c2daee8d8ed2c9f8c220edbf1957b8e8 -
Trigger Event:
push
-
Statement type:
File details
Details for the file typed_argparse_gen-0.3.0-py3-none-any.whl.
File metadata
- Download URL: typed_argparse_gen-0.3.0-py3-none-any.whl
- Upload date:
- Size: 19.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c4a16db44563e9a681d6a4d0c46661ebeba526226455e1023b20ab19d7a3dfcd
|
|
| MD5 |
da703e08fe98e05d5f516c2c4e79760b
|
|
| BLAKE2b-256 |
86567467932ceca7629d63d58eaf32d4c9c9801fdc06b6ebd01daf63e26018ab
|
Provenance
The following attestation bundles were made for typed_argparse_gen-0.3.0-py3-none-any.whl:
Publisher:
release.yml on KelvinChung2000/typed-argparse
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
typed_argparse_gen-0.3.0-py3-none-any.whl -
Subject digest:
c4a16db44563e9a681d6a4d0c46661ebeba526226455e1023b20ab19d7a3dfcd - Sigstore transparency entry: 1419417449
- Sigstore integration time:
-
Permalink:
KelvinChung2000/typed-argparse@6ddb58c1c2daee8d8ed2c9f8c220edbf1957b8e8 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/KelvinChung2000
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@6ddb58c1c2daee8d8ed2c9f8c220edbf1957b8e8 -
Trigger Event:
push
-
Statement type: